mirror of
https://github.com/usbharu/Hideout.git
synced 2026-07-06 05:28:22 +00:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
1ac8a93619
|
|||
|
a284f4359e
|
|||
|
3a49b2ce9a
|
|||
|
5ae4d1577a
|
@@ -49,4 +49,3 @@ out/
|
||||
/hideout-core/.kotlin/sessions/
|
||||
/hideout-mastodon/.kotlin/sessions/
|
||||
/http-client.private.env.json
|
||||
/logs/
|
||||
|
||||
@@ -48,6 +48,12 @@ repositories {
|
||||
}
|
||||
}
|
||||
}
|
||||
configurations {
|
||||
all {
|
||||
exclude("org.springframework.boot", "spring-boot-starter-logging")
|
||||
exclude("ch.qos.logback", "logback-classic")
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("dev.usbharu:hideout-core:0.0.1")
|
||||
|
||||
@@ -90,6 +90,7 @@ dependencies {
|
||||
implementation("org.springframework.boot:spring-boot-starter-web")
|
||||
implementation("org.springframework.boot:spring-boot-starter-security")
|
||||
implementation("org.springframework.boot:spring-boot-starter-thymeleaf")
|
||||
implementation("org.springframework.boot:spring-boot-starter-log4j2")
|
||||
implementation("org.springframework.boot:spring-boot-starter-validation")
|
||||
annotationProcessor("org.springframework:spring-context-indexer")
|
||||
|
||||
@@ -124,7 +125,8 @@ dependencies {
|
||||
|
||||
implementation(libs.http.signature)
|
||||
implementation(libs.emoji.kt)
|
||||
implementation(libs.logback.ecs.encoder)
|
||||
|
||||
|
||||
|
||||
testImplementation("org.springframework.boot:spring-boot-starter-test")
|
||||
testImplementation(libs.kotlin.junit)
|
||||
@@ -132,6 +134,7 @@ dependencies {
|
||||
testImplementation(libs.ktor.client.mock)
|
||||
testImplementation(libs.h2db)
|
||||
testImplementation(libs.mockito.kotlin)
|
||||
|
||||
}
|
||||
|
||||
detekt {
|
||||
@@ -142,20 +145,14 @@ detekt {
|
||||
autoCorrect = true
|
||||
}
|
||||
|
||||
configurations {
|
||||
matching { it.name == "detekt" }.all {
|
||||
resolutionStrategy.eachDependency {
|
||||
if (requested.group == "org.jetbrains.kotlin") {
|
||||
useVersion(io.gitlab.arturbosch.detekt.getSupportedKotlinVersion())
|
||||
}
|
||||
configurations.matching { it.name == "detekt" }.all {
|
||||
resolutionStrategy.eachDependency {
|
||||
if (requested.group == "org.jetbrains.kotlin") {
|
||||
useVersion(io.gitlab.arturbosch.detekt.getSupportedKotlinVersion())
|
||||
}
|
||||
}
|
||||
all {
|
||||
exclude("org.apache.logging.log4j", "log4j-slf4j2-impl")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//tasks{
|
||||
// bootRun {
|
||||
// sourceResources(sourceSets.main.get())
|
||||
@@ -179,6 +176,13 @@ tasks.withType<io.gitlab.arturbosch.detekt.DetektCreateBaselineTask>().configure
|
||||
exclude("**/org/koin/ksp/generated/**", "**/generated/**")
|
||||
}
|
||||
|
||||
configurations {
|
||||
all {
|
||||
exclude("org.springframework.boot", "spring-boot-starter-logging")
|
||||
exclude("ch.qos.logback", "logback-classic")
|
||||
}
|
||||
}
|
||||
|
||||
project.gradle.taskGraph.whenReady {
|
||||
println(this.allTasks)
|
||||
this.allTasks.map { println(it.name) }
|
||||
|
||||
+1
-3
@@ -26,10 +26,8 @@ class GetActorDetailApplicationService(
|
||||
actorRepository.findById(ActorId(command.id))
|
||||
?: throw IllegalArgumentException("Actor ${command.id} not found.")
|
||||
} else if (command.actorName != null) {
|
||||
val host = if (command.actorName.host.isEmpty()) {
|
||||
val host = command.actorName.host.ifEmpty {
|
||||
applicationConfig.url.host
|
||||
} else {
|
||||
command.actorName.host
|
||||
}
|
||||
actorRepository.findByNameAndDomain(command.actorName.userpart, host)
|
||||
?: throw IllegalArgumentException("Actor ${command.actorName} not found.")
|
||||
|
||||
-8
@@ -1,8 +0,0 @@
|
||||
package dev.usbharu.hideout.core.application.actor
|
||||
|
||||
import org.springframework.stereotype.Service
|
||||
|
||||
@Service
|
||||
interface SetAlsoKnownAsLocalActorApplicationService {
|
||||
suspend fun setAlsoKnownAs(actorId: Long, alsoKnownAs: List<Long>)
|
||||
}
|
||||
-3
@@ -1,3 +0,0 @@
|
||||
package dev.usbharu.hideout.core.application.actor
|
||||
|
||||
data class SuspendLocalActor(val actorId: Long)
|
||||
-44
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2024 usbharu
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.usbharu.hideout.core.application.actor
|
||||
|
||||
import dev.usbharu.hideout.core.application.shared.LocalUserAbstractApplicationService
|
||||
import dev.usbharu.hideout.core.application.shared.Transaction
|
||||
import dev.usbharu.hideout.core.domain.model.actor.ActorId
|
||||
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
|
||||
import dev.usbharu.hideout.core.domain.model.support.principal.LocalUser
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.stereotype.Service
|
||||
|
||||
@Service
|
||||
class SuspendLocalActorApplicationService(
|
||||
transaction: Transaction,
|
||||
private val actorRepository: ActorRepository,
|
||||
) : LocalUserAbstractApplicationService<SuspendLocalActor, Unit>(transaction, logger) {
|
||||
|
||||
override suspend fun internalExecute(command: SuspendLocalActor, principal: LocalUser) {
|
||||
val id = ActorId(command.actorId)
|
||||
val actor =
|
||||
actorRepository.findById(id) ?: throw IllegalArgumentException("Actor ${command.actorId} not found.")
|
||||
actor.suspend = true
|
||||
actorRepository.save(actor)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val logger = LoggerFactory.getLogger(SuspendLocalActorApplicationService::class.java)
|
||||
}
|
||||
}
|
||||
-3
@@ -1,3 +0,0 @@
|
||||
package dev.usbharu.hideout.core.application.actor
|
||||
|
||||
data class UnsuspendLocalActor(val actorId: Long)
|
||||
-44
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2024 usbharu
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.usbharu.hideout.core.application.actor
|
||||
|
||||
import dev.usbharu.hideout.core.application.shared.LocalUserAbstractApplicationService
|
||||
import dev.usbharu.hideout.core.application.shared.Transaction
|
||||
import dev.usbharu.hideout.core.domain.model.actor.ActorId
|
||||
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
|
||||
import dev.usbharu.hideout.core.domain.model.support.principal.LocalUser
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.stereotype.Service
|
||||
|
||||
@Service
|
||||
class UnsuspendLocalActorApplicationService(
|
||||
transaction: Transaction,
|
||||
private val actorRepository: ActorRepository,
|
||||
) : LocalUserAbstractApplicationService<UnsuspendLocalActor, Unit>(transaction, logger) {
|
||||
|
||||
override suspend fun internalExecute(command: UnsuspendLocalActor, principal: LocalUser) {
|
||||
val findById = actorRepository.findById(ActorId(command.actorId))
|
||||
?: throw IllegalArgumentException("Actor ${command.actorId} not found.")
|
||||
|
||||
findById.suspend = false
|
||||
actorRepository.save(findById)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val logger = LoggerFactory.getLogger(UnsuspendLocalActorApplicationService::class.java)
|
||||
}
|
||||
}
|
||||
+11
-4
@@ -5,20 +5,24 @@ import dev.usbharu.hideout.core.application.timeline.AddTimelineRelationship
|
||||
import dev.usbharu.hideout.core.application.timeline.UserAddTimelineRelationshipApplicationService
|
||||
import dev.usbharu.hideout.core.domain.event.relationship.RelationshipEvent
|
||||
import dev.usbharu.hideout.core.domain.event.relationship.RelationshipEventBody
|
||||
import dev.usbharu.hideout.core.domain.model.timelinerelationship.TimelineRelationship
|
||||
import dev.usbharu.hideout.core.domain.model.timelinerelationship.TimelineRelationshipId
|
||||
import dev.usbharu.hideout.core.domain.model.timelinerelationship.Visible
|
||||
import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailRepository
|
||||
import dev.usbharu.hideout.core.domain.shared.id.IdGenerateService
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.stereotype.Component
|
||||
|
||||
@Component
|
||||
class TimelineRelationshipFollowSubscriber(
|
||||
private val userAddTimelineRelationshipApplicationService: UserAddTimelineRelationshipApplicationService,
|
||||
private val idGenerateService: IdGenerateService,
|
||||
private val userDetailRepository: UserDetailRepository,
|
||||
private val domainEventSubscriber: DomainEventSubscriber
|
||||
) : Subscriber {
|
||||
|
||||
override fun init() {
|
||||
domainEventSubscriber.subscribe<RelationshipEventBody>(RelationshipEvent.ACCEPT_FOLLOW.eventName) {
|
||||
domainEventSubscriber.subscribe<RelationshipEventBody>(RelationshipEvent.FOLLOW.eventName) {
|
||||
val relationship = it.body.getRelationship()
|
||||
val userDetail = userDetailRepository.findByActorId(relationship.actorId.id)
|
||||
?: throw InternalServerException("Userdetail ${relationship.actorId} not found by actorid.")
|
||||
@@ -30,9 +34,12 @@ class TimelineRelationshipFollowSubscriber(
|
||||
@Suppress("UnsafeCallOnNullableType")
|
||||
userAddTimelineRelationshipApplicationService.execute(
|
||||
AddTimelineRelationship(
|
||||
userDetail.homeTimelineId!!,
|
||||
relationship.targetActorId,
|
||||
Visible.FOLLOWERS
|
||||
TimelineRelationship(
|
||||
TimelineRelationshipId(idGenerateService.generateId()),
|
||||
userDetail.homeTimelineId!!,
|
||||
relationship.targetActorId,
|
||||
Visible.FOLLOWERS
|
||||
)
|
||||
),
|
||||
it.body.principal
|
||||
)
|
||||
|
||||
-46
@@ -1,46 +0,0 @@
|
||||
package dev.usbharu.hideout.core.application.domainevent.subscribers
|
||||
|
||||
import dev.usbharu.hideout.core.application.timeline.RemoveTimelineRelationship
|
||||
import dev.usbharu.hideout.core.application.timeline.UserRemoveTimelineRelationshipApplicationService
|
||||
import dev.usbharu.hideout.core.domain.event.relationship.RelationshipEvent
|
||||
import dev.usbharu.hideout.core.domain.event.relationship.RelationshipEventBody
|
||||
import dev.usbharu.hideout.core.domain.model.timelinerelationship.TimelineRelationshipRepository
|
||||
import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailRepository
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.stereotype.Component
|
||||
|
||||
@Component
|
||||
class TimelineRelationshipUnfollowSubscriber(
|
||||
private val domainEventSubscriber: DomainEventSubscriber,
|
||||
private val userRemoveTimelineRelationshipApplicationService: UserRemoveTimelineRelationshipApplicationService,
|
||||
private val userDetailRepository: UserDetailRepository,
|
||||
private val timelineRelationshipRepository: TimelineRelationshipRepository,
|
||||
) : Subscriber {
|
||||
override fun init() {
|
||||
domainEventSubscriber.subscribe<RelationshipEventBody>(RelationshipEvent.UNFOLLOW.eventName) {
|
||||
val relationship = it.body.getRelationship()
|
||||
val userDetail = userDetailRepository.findByActorId(relationship.actorId.id) ?: throw IllegalStateException(
|
||||
"UserDetail ${relationship.actorId} not found by actorId."
|
||||
)
|
||||
if (userDetail.homeTimelineId == null) {
|
||||
logger.warn("HomeTimeline for ${userDetail.id} not found.")
|
||||
return@subscribe
|
||||
}
|
||||
|
||||
val timelineRelationship = timelineRelationshipRepository.findByTimelineIdAndActorId(
|
||||
userDetail.homeTimelineId!!,
|
||||
relationship.targetActorId
|
||||
)
|
||||
?: throw IllegalStateException("TimelineRelationship ${userDetail.homeTimelineId} to ${relationship.targetActorId} not found by timelineId and ActorId")
|
||||
|
||||
userRemoveTimelineRelationshipApplicationService.execute(
|
||||
RemoveTimelineRelationship(timelineRelationship.id),
|
||||
it.body.principal
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val logger = LoggerFactory.getLogger(TimelineRelationshipUnfollowSubscriber::class.java)
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package dev.usbharu.hideout.core.application.model
|
||||
|
||||
import dev.usbharu.hideout.core.domain.model.emoji.CustomEmoji
|
||||
import dev.usbharu.hideout.core.domain.model.reaction.Reaction
|
||||
import java.net.URI
|
||||
|
||||
data class Reactions(
|
||||
val postId: Long,
|
||||
val count: Int,
|
||||
val name: String,
|
||||
val domain: String,
|
||||
val url: URI?,
|
||||
val actorIds: List<Long>,
|
||||
) {
|
||||
companion object {
|
||||
fun of(reactionList: List<Reaction>, customEmoji: CustomEmoji?): Reactions {
|
||||
val first = reactionList.first()
|
||||
return Reactions(
|
||||
first.id.value,
|
||||
reactionList.size,
|
||||
customEmoji?.name ?: first.unicodeEmoji.name,
|
||||
customEmoji?.domain?.domain ?: first.unicodeEmoji.domain.domain,
|
||||
customEmoji?.url,
|
||||
reactionList.map { it.actorId.id }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package dev.usbharu.hideout.core.application.model
|
||||
|
||||
import dev.usbharu.hideout.core.domain.model.timeline.TimelineVisibility
|
||||
|
||||
data class Timeline(
|
||||
val id: Long,
|
||||
val userDetailId: Long,
|
||||
val name: String,
|
||||
val visibility: TimelineVisibility,
|
||||
val isSystem: Boolean
|
||||
) {
|
||||
companion object {
|
||||
fun of(timeline: dev.usbharu.hideout.core.domain.model.timeline.Timeline): Timeline {
|
||||
return Timeline(
|
||||
timeline.id.value,
|
||||
timeline.userDetailId.id,
|
||||
timeline.name.value,
|
||||
timeline.visibility,
|
||||
timeline.isSystem
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
+5
-22
@@ -9,10 +9,8 @@ import dev.usbharu.hideout.core.domain.model.media.Media
|
||||
import dev.usbharu.hideout.core.domain.model.media.MediaRepository
|
||||
import dev.usbharu.hideout.core.domain.model.post.PostId
|
||||
import dev.usbharu.hideout.core.domain.model.post.PostRepository
|
||||
import dev.usbharu.hideout.core.domain.model.reaction.ReactionRepository
|
||||
import dev.usbharu.hideout.core.domain.model.support.principal.Principal
|
||||
import dev.usbharu.hideout.core.domain.service.post.IPostReadAccessControl
|
||||
import dev.usbharu.hideout.core.query.reactions.ReactionsQueryService
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.stereotype.Service
|
||||
|
||||
@@ -22,9 +20,7 @@ class GetPostDetailApplicationService(
|
||||
private val postRepository: PostRepository,
|
||||
private val actorRepository: ActorRepository,
|
||||
private val mediaRepository: MediaRepository,
|
||||
private val iPostReadAccessControl: IPostReadAccessControl,
|
||||
private val reactionsQueryService: ReactionsQueryService,
|
||||
private val reactionRepository: ReactionRepository,
|
||||
private val iPostReadAccessControl: IPostReadAccessControl
|
||||
) : AbstractApplicationService<GetPostDetail, PostDetail>(
|
||||
transaction,
|
||||
logger
|
||||
@@ -42,15 +38,6 @@ class GetPostDetailApplicationService(
|
||||
|
||||
val mediaList = mediaRepository.findByIds(post.mediaIds)
|
||||
|
||||
val reactions = reactionsQueryService.findAllByPostId(post.id)
|
||||
|
||||
val favourited = reactionRepository.existsByPostIdAndActorIdAndCustomEmojiIdOrUnicodeEmoji(
|
||||
post.id,
|
||||
principal.actorId,
|
||||
null,
|
||||
"❤"
|
||||
)
|
||||
|
||||
return PostDetail.of(
|
||||
post = post,
|
||||
actor = actor,
|
||||
@@ -59,8 +46,6 @@ class GetPostDetailApplicationService(
|
||||
reply = post.replyId?.let { fetchChild(it, actor, iconMedia, principal) },
|
||||
repost = post.repostId?.let { fetchChild(it, actor, iconMedia, principal) },
|
||||
moveTo = post.moveTo?.let { fetchChild(it, actor, iconMedia, principal) },
|
||||
reactionsList = reactions,
|
||||
favourited
|
||||
)
|
||||
}
|
||||
|
||||
@@ -84,12 +69,10 @@ class GetPostDetailApplicationService(
|
||||
|
||||
val mediaList = mediaRepository.findByIds(post.mediaIds)
|
||||
return PostDetail.of(
|
||||
post = post,
|
||||
actor = first,
|
||||
iconMedia = third,
|
||||
mediaList = mediaList,
|
||||
reactionsList = emptyList(),
|
||||
favourited = false
|
||||
post,
|
||||
first,
|
||||
third,
|
||||
mediaList
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+2
-9
@@ -1,6 +1,5 @@
|
||||
package dev.usbharu.hideout.core.application.post
|
||||
|
||||
import dev.usbharu.hideout.core.application.model.Reactions
|
||||
import dev.usbharu.hideout.core.domain.model.actor.Actor
|
||||
import dev.usbharu.hideout.core.domain.model.media.Media
|
||||
import dev.usbharu.hideout.core.domain.model.post.Post
|
||||
@@ -24,9 +23,7 @@ data class PostDetail(
|
||||
val sensitive: Boolean,
|
||||
val deleted: Boolean,
|
||||
val mediaDetailList: List<MediaDetail>,
|
||||
val moveTo: PostDetail?,
|
||||
val reactionsList: List<Reactions>,
|
||||
val favourited: Boolean
|
||||
val moveTo: PostDetail?
|
||||
) {
|
||||
companion object {
|
||||
@Suppress("LongParameterList")
|
||||
@@ -38,8 +35,6 @@ data class PostDetail(
|
||||
reply: PostDetail? = null,
|
||||
repost: PostDetail? = null,
|
||||
moveTo: PostDetail? = null,
|
||||
reactionsList: List<Reactions>,
|
||||
favourited: Boolean
|
||||
): PostDetail {
|
||||
return PostDetail(
|
||||
id = post.id.id,
|
||||
@@ -57,9 +52,7 @@ data class PostDetail(
|
||||
sensitive = post.sensitive,
|
||||
deleted = false,
|
||||
mediaDetailList = mediaList.map { MediaDetail.of(it) },
|
||||
moveTo = moveTo,
|
||||
reactionsList = reactionsList,
|
||||
favourited = favourited
|
||||
moveTo = moveTo
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
-3
@@ -1,3 +0,0 @@
|
||||
package dev.usbharu.hideout.core.application.reaction
|
||||
|
||||
data class CreateReaction(val postId: Long, val customEmojiId: Long?, val unicodeEmoji: String)
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
package dev.usbharu.hideout.core.application.reaction
|
||||
|
||||
data class RemoveReaction(
|
||||
val postId: Long,
|
||||
val customEmojiId: Long?,
|
||||
val unicodeEmoji: String
|
||||
)
|
||||
-65
@@ -1,65 +0,0 @@
|
||||
package dev.usbharu.hideout.core.application.reaction
|
||||
|
||||
import dev.usbharu.hideout.core.application.exception.PermissionDeniedException
|
||||
import dev.usbharu.hideout.core.application.shared.LocalUserAbstractApplicationService
|
||||
import dev.usbharu.hideout.core.application.shared.Transaction
|
||||
import dev.usbharu.hideout.core.domain.model.emoji.CustomEmojiRepository
|
||||
import dev.usbharu.hideout.core.domain.model.emoji.UnicodeEmoji
|
||||
import dev.usbharu.hideout.core.domain.model.post.PostId
|
||||
import dev.usbharu.hideout.core.domain.model.post.PostRepository
|
||||
import dev.usbharu.hideout.core.domain.model.reaction.Reaction
|
||||
import dev.usbharu.hideout.core.domain.model.reaction.ReactionId
|
||||
import dev.usbharu.hideout.core.domain.model.reaction.ReactionRepository
|
||||
import dev.usbharu.hideout.core.domain.model.support.principal.LocalUser
|
||||
import dev.usbharu.hideout.core.domain.service.emoji.UnicodeEmojiService
|
||||
import dev.usbharu.hideout.core.domain.service.post.IPostReadAccessControl
|
||||
import dev.usbharu.hideout.core.domain.shared.id.IdGenerateService
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.stereotype.Service
|
||||
import java.time.Instant
|
||||
|
||||
@Service
|
||||
class UserCreateReactionApplicationService(
|
||||
transaction: Transaction,
|
||||
private val idGenerateService: IdGenerateService,
|
||||
private val reactionRepository: ReactionRepository,
|
||||
private val postReadAccessControl: IPostReadAccessControl,
|
||||
private val postRepository: PostRepository,
|
||||
private val customEmojiRepository: CustomEmojiRepository,
|
||||
private val unicodeEmojiService: UnicodeEmojiService
|
||||
) :
|
||||
LocalUserAbstractApplicationService<CreateReaction, Unit>(
|
||||
transaction,
|
||||
logger
|
||||
) {
|
||||
override suspend fun internalExecute(command: CreateReaction, principal: LocalUser) {
|
||||
val postId = PostId(command.postId)
|
||||
val post = postRepository.findById(postId) ?: throw IllegalArgumentException("Post $postId not found.")
|
||||
if (postReadAccessControl.isAllow(post, principal).not()) {
|
||||
throw PermissionDeniedException()
|
||||
}
|
||||
|
||||
val customEmoji = command.customEmojiId?.let { customEmojiRepository.findById(it) }
|
||||
|
||||
val unicodeEmoji = if (unicodeEmojiService.isUnicodeEmoji(command.unicodeEmoji)) {
|
||||
command.unicodeEmoji
|
||||
} else {
|
||||
"❤"
|
||||
}
|
||||
|
||||
val reaction = Reaction.create(
|
||||
id = ReactionId(idGenerateService.generateId()),
|
||||
postId = postId,
|
||||
actorId = principal.actorId,
|
||||
customEmojiId = customEmoji?.id,
|
||||
unicodeEmoji = UnicodeEmoji(unicodeEmoji),
|
||||
createdAt = Instant.now()
|
||||
)
|
||||
|
||||
reactionRepository.save(reaction)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val logger = LoggerFactory.getLogger(UserCreateReactionApplicationService::class.java)
|
||||
}
|
||||
}
|
||||
-51
@@ -1,51 +0,0 @@
|
||||
package dev.usbharu.hideout.core.application.reaction
|
||||
|
||||
import dev.usbharu.hideout.core.application.shared.LocalUserAbstractApplicationService
|
||||
import dev.usbharu.hideout.core.application.shared.Transaction
|
||||
import dev.usbharu.hideout.core.domain.model.emoji.CustomEmojiRepository
|
||||
import dev.usbharu.hideout.core.domain.model.post.PostId
|
||||
import dev.usbharu.hideout.core.domain.model.reaction.ReactionRepository
|
||||
import dev.usbharu.hideout.core.domain.model.support.principal.LocalUser
|
||||
import dev.usbharu.hideout.core.domain.service.emoji.UnicodeEmojiService
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.stereotype.Service
|
||||
|
||||
@Service
|
||||
class UserRemoveReactionApplicationService(
|
||||
transaction: Transaction,
|
||||
private val customEmojiRepository: CustomEmojiRepository,
|
||||
private val reactionRepository: ReactionRepository,
|
||||
private val unicodeEmojiService: UnicodeEmojiService
|
||||
) :
|
||||
LocalUserAbstractApplicationService<RemoveReaction, Unit>(
|
||||
transaction,
|
||||
logger
|
||||
) {
|
||||
override suspend fun internalExecute(command: RemoveReaction, principal: LocalUser) {
|
||||
val postId = PostId(command.postId)
|
||||
|
||||
val customEmoji = command.customEmojiId?.let { customEmojiRepository.findById(it) }
|
||||
|
||||
val unicodeEmoji = if (unicodeEmojiService.isUnicodeEmoji(command.unicodeEmoji)) {
|
||||
command.unicodeEmoji
|
||||
} else {
|
||||
"❤"
|
||||
}
|
||||
val reaction =
|
||||
reactionRepository.findByPostIdAndActorIdAndCustomEmojiIdOrUnicodeEmoji(
|
||||
postId,
|
||||
principal.actorId,
|
||||
customEmoji?.id,
|
||||
unicodeEmoji
|
||||
)
|
||||
?: throw IllegalArgumentException("Reaction $postId ${principal.actorId} ${customEmoji?.id} $unicodeEmoji not found.")
|
||||
|
||||
reaction.delete()
|
||||
|
||||
reactionRepository.delete(reaction)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val logger = LoggerFactory.getLogger(UserRemoveReactionApplicationService::class.java)
|
||||
}
|
||||
}
|
||||
+2
-6
@@ -1,11 +1,7 @@
|
||||
package dev.usbharu.hideout.core.application.timeline
|
||||
|
||||
import dev.usbharu.hideout.core.domain.model.actor.ActorId
|
||||
import dev.usbharu.hideout.core.domain.model.timeline.TimelineId
|
||||
import dev.usbharu.hideout.core.domain.model.timelinerelationship.Visible
|
||||
import dev.usbharu.hideout.core.domain.model.timelinerelationship.TimelineRelationship
|
||||
|
||||
data class AddTimelineRelationship(
|
||||
val timelineId: TimelineId,
|
||||
val actorId: ActorId,
|
||||
val visible: Visible
|
||||
val timelineRelationship: TimelineRelationship
|
||||
)
|
||||
|
||||
-3
@@ -1,3 +0,0 @@
|
||||
package dev.usbharu.hideout.core.application.timeline
|
||||
|
||||
data class GetTimelines(val userDetailId: Long)
|
||||
+6
-12
@@ -47,9 +47,7 @@ class ReadTimelineApplicationService(
|
||||
it.replyPost,
|
||||
it.replyPostActor!!,
|
||||
it.replyPostActorIconMedia,
|
||||
it.replyPostMedias.orEmpty(),
|
||||
reactionsList = emptyList(),
|
||||
favourited = false,
|
||||
it.replyPostMedias.orEmpty()
|
||||
)
|
||||
} else {
|
||||
null
|
||||
@@ -58,12 +56,10 @@ class ReadTimelineApplicationService(
|
||||
val repost = if (it.repostPost != null) {
|
||||
@Suppress("UnsafeCallOnNullableType")
|
||||
PostDetail.of(
|
||||
post = it.repostPost,
|
||||
actor = it.repostPostActor!!,
|
||||
iconMedia = it.repostPostActorIconMedia,
|
||||
mediaList = it.repostPostMedias.orEmpty(),
|
||||
reactionsList = emptyList(),
|
||||
favourited = false
|
||||
it.repostPost,
|
||||
it.repostPostActor!!,
|
||||
it.repostPostActorIconMedia,
|
||||
it.repostPostMedias.orEmpty()
|
||||
)
|
||||
} else {
|
||||
null
|
||||
@@ -75,9 +71,7 @@ class ReadTimelineApplicationService(
|
||||
iconMedia = it.postActorIconMedia,
|
||||
mediaList = it.postMedias,
|
||||
reply = reply,
|
||||
repost = repost,
|
||||
reactionsList = emptyList(),
|
||||
favourited = it.favourited
|
||||
repost = repost
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
-5
@@ -1,5 +0,0 @@
|
||||
package dev.usbharu.hideout.core.application.timeline
|
||||
|
||||
import dev.usbharu.hideout.core.domain.model.timelinerelationship.TimelineRelationshipId
|
||||
|
||||
data class RemoveTimelineRelationship(val timelineRelationshipId: TimelineRelationshipId)
|
||||
+1
-22
@@ -1,22 +1,15 @@
|
||||
package dev.usbharu.hideout.core.application.timeline
|
||||
|
||||
import dev.usbharu.hideout.core.application.exception.PermissionDeniedException
|
||||
import dev.usbharu.hideout.core.application.shared.LocalUserAbstractApplicationService
|
||||
import dev.usbharu.hideout.core.application.shared.Transaction
|
||||
import dev.usbharu.hideout.core.domain.model.support.principal.LocalUser
|
||||
import dev.usbharu.hideout.core.domain.model.timeline.TimelineRepository
|
||||
import dev.usbharu.hideout.core.domain.model.timelinerelationship.TimelineRelationship
|
||||
import dev.usbharu.hideout.core.domain.model.timelinerelationship.TimelineRelationshipId
|
||||
import dev.usbharu.hideout.core.domain.model.timelinerelationship.TimelineRelationshipRepository
|
||||
import dev.usbharu.hideout.core.domain.shared.id.IdGenerateService
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.stereotype.Service
|
||||
|
||||
@Service
|
||||
class UserAddTimelineRelationshipApplicationService(
|
||||
private val timelineRelationshipRepository: TimelineRelationshipRepository,
|
||||
private val timelineRepository: TimelineRepository,
|
||||
private val idGenerateService: IdGenerateService,
|
||||
transaction: Transaction
|
||||
) :
|
||||
LocalUserAbstractApplicationService<AddTimelineRelationship, Unit>(
|
||||
@@ -24,21 +17,7 @@ class UserAddTimelineRelationshipApplicationService(
|
||||
logger
|
||||
) {
|
||||
override suspend fun internalExecute(command: AddTimelineRelationship, principal: LocalUser) {
|
||||
val timeline = timelineRepository.findById(command.timelineId)
|
||||
?: throw IllegalArgumentException("Timeline ${command.timelineId} not found.")
|
||||
|
||||
if (timeline.userDetailId != principal.userDetailId) {
|
||||
throw PermissionDeniedException()
|
||||
}
|
||||
|
||||
timelineRelationshipRepository.save(
|
||||
TimelineRelationship(
|
||||
TimelineRelationshipId(idGenerateService.generateId()),
|
||||
command.timelineId,
|
||||
command.actorId,
|
||||
command.visible
|
||||
)
|
||||
)
|
||||
timelineRelationshipRepository.save(command.timelineRelationship)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
-37
@@ -1,37 +0,0 @@
|
||||
package dev.usbharu.hideout.core.application.timeline
|
||||
|
||||
import dev.usbharu.hideout.core.application.model.Timeline
|
||||
import dev.usbharu.hideout.core.application.shared.AbstractApplicationService
|
||||
import dev.usbharu.hideout.core.application.shared.Transaction
|
||||
import dev.usbharu.hideout.core.domain.model.support.principal.Principal
|
||||
import dev.usbharu.hideout.core.domain.model.timeline.TimelineRepository
|
||||
import dev.usbharu.hideout.core.domain.model.timeline.TimelineVisibility
|
||||
import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailId
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.stereotype.Service
|
||||
|
||||
@Service
|
||||
class UserGetTimelinesApplicationService(transaction: Transaction, private val timelineRepository: TimelineRepository) :
|
||||
AbstractApplicationService<GetTimelines, List<Timeline>>(
|
||||
transaction,
|
||||
logger
|
||||
) {
|
||||
override suspend fun internalExecute(command: GetTimelines, principal: Principal): List<Timeline> {
|
||||
val userDetailId = UserDetailId(command.userDetailId)
|
||||
|
||||
val timelineVisibility = if (userDetailId == principal.userDetailId) {
|
||||
listOf(TimelineVisibility.PUBLIC, TimelineVisibility.UNLISTED, TimelineVisibility.PRIVATE)
|
||||
} else {
|
||||
listOf(TimelineVisibility.PUBLIC)
|
||||
}
|
||||
|
||||
val timelineList =
|
||||
timelineRepository.findAllByUserDetailIdAndVisibilityIn(userDetailId, timelineVisibility)
|
||||
|
||||
return timelineList.map { Timeline.of(it) }
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val logger = LoggerFactory.getLogger(UserGetTimelinesApplicationService::class.java)
|
||||
}
|
||||
}
|
||||
-44
@@ -1,44 +0,0 @@
|
||||
package dev.usbharu.hideout.core.application.timeline
|
||||
|
||||
import dev.usbharu.hideout.core.application.exception.PermissionDeniedException
|
||||
import dev.usbharu.hideout.core.application.shared.LocalUserAbstractApplicationService
|
||||
import dev.usbharu.hideout.core.application.shared.Transaction
|
||||
import dev.usbharu.hideout.core.domain.model.support.principal.LocalUser
|
||||
import dev.usbharu.hideout.core.domain.model.timeline.TimelineRepository
|
||||
import dev.usbharu.hideout.core.domain.model.timelinerelationship.TimelineRelationshipRepository
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.stereotype.Service
|
||||
|
||||
@Service
|
||||
class UserRemoveTimelineRelationshipApplicationService(
|
||||
transaction: Transaction,
|
||||
private val timelineRelationshipRepository: TimelineRelationshipRepository,
|
||||
private val timelineRepository: TimelineRepository
|
||||
) :
|
||||
LocalUserAbstractApplicationService<RemoveTimelineRelationship, Unit>(
|
||||
transaction,
|
||||
logger
|
||||
) {
|
||||
|
||||
override suspend fun internalExecute(command: RemoveTimelineRelationship, principal: LocalUser) {
|
||||
val timelineRelationship = (
|
||||
timelineRelationshipRepository.findById(command.timelineRelationshipId)
|
||||
?: throw IllegalArgumentException("TimelineRelationship ${command.timelineRelationshipId} not found.")
|
||||
)
|
||||
|
||||
val timeline = (
|
||||
timelineRepository.findById(timelineRelationship.timelineId)
|
||||
?: throw IllegalArgumentException("Timeline ${timelineRelationship.timelineId} not found.")
|
||||
)
|
||||
|
||||
if (timeline.userDetailId != principal.userDetailId) {
|
||||
throw PermissionDeniedException()
|
||||
}
|
||||
|
||||
timelineRelationshipRepository.delete(timelineRelationship)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val logger = LoggerFactory.getLogger(UserRemoveTimelineRelationshipApplicationService::class.java)
|
||||
}
|
||||
}
|
||||
-22
@@ -1,22 +0,0 @@
|
||||
package dev.usbharu.hideout.core.domain.event.reaction
|
||||
|
||||
import dev.usbharu.hideout.core.domain.model.reaction.Reaction
|
||||
import dev.usbharu.hideout.core.domain.model.reaction.ReactionId
|
||||
import dev.usbharu.hideout.core.domain.shared.domainevent.DomainEvent
|
||||
import dev.usbharu.hideout.core.domain.shared.domainevent.DomainEventBody
|
||||
|
||||
class ReactionEventFactory(private val reaction: Reaction) {
|
||||
fun createEvent(reactionEvent: ReactionEvent): DomainEvent<ReactionEventBody> =
|
||||
DomainEvent.create(reactionEvent.eventName, ReactionEventBody(reaction))
|
||||
}
|
||||
|
||||
class ReactionEventBody(
|
||||
reaction: Reaction
|
||||
) : DomainEventBody(mapOf("reactionId" to reaction.id)) {
|
||||
fun getReactionId(): ReactionId = toMap()["reactionId"] as ReactionId
|
||||
}
|
||||
|
||||
enum class ReactionEvent(val eventName: String) {
|
||||
CREATE("ReactionCreate"),
|
||||
DELETE("ReactionDelete"),
|
||||
}
|
||||
+1
-2
@@ -35,8 +35,7 @@ class RelationshipEventBody(
|
||||
}
|
||||
|
||||
enum class RelationshipEvent(val eventName: String) {
|
||||
ACCEPT_FOLLOW("RelationshipFollow"),
|
||||
REJECT_FOLLOW("RelationshipRejectFollow"),
|
||||
FOLLOW("RelationshipFollow"),
|
||||
UNFOLLOW("RelationshipUnfollow"),
|
||||
BLOCK("RelationshipBlock"),
|
||||
UNBLOCK("RelationshipUnblock"),
|
||||
|
||||
@@ -18,7 +18,7 @@ package dev.usbharu.hideout.core.domain.model.actor
|
||||
|
||||
import dev.usbharu.hideout.core.domain.event.actor.ActorDomainEventFactory
|
||||
import dev.usbharu.hideout.core.domain.event.actor.ActorEvent.*
|
||||
import dev.usbharu.hideout.core.domain.model.emoji.CustomEmojiId
|
||||
import dev.usbharu.hideout.core.domain.model.emoji.EmojiId
|
||||
import dev.usbharu.hideout.core.domain.model.instance.InstanceId
|
||||
import dev.usbharu.hideout.core.domain.model.media.MediaId
|
||||
import dev.usbharu.hideout.core.domain.model.support.domain.Domain
|
||||
@@ -52,7 +52,7 @@ class Actor(
|
||||
var lastUpdateAt: Instant = createdAt,
|
||||
alsoKnownAs: Set<ActorId> = emptySet(),
|
||||
moveTo: ActorId? = null,
|
||||
emojiIds: Set<CustomEmojiId>,
|
||||
emojiIds: Set<EmojiId>,
|
||||
deleted: Boolean,
|
||||
icon: MediaId?,
|
||||
banner: MediaId?,
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2024 usbharu
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.usbharu.hideout.core.domain.model.actor
|
||||
|
||||
enum class Role {
|
||||
LOCAL,
|
||||
MODERATOR,
|
||||
ADMINISTRATOR,
|
||||
REMOTE
|
||||
}
|
||||
+2
-6
@@ -36,7 +36,7 @@ sealed class Emoji {
|
||||
}
|
||||
|
||||
data class CustomEmoji(
|
||||
val id: CustomEmojiId,
|
||||
val id: EmojiId,
|
||||
override val name: String,
|
||||
override val domain: Domain,
|
||||
val instanceId: InstanceId,
|
||||
@@ -50,10 +50,6 @@ data class CustomEmoji(
|
||||
data class UnicodeEmoji(
|
||||
override val name: String
|
||||
) : Emoji() {
|
||||
override val domain: Domain = Companion.domain
|
||||
override val domain: Domain = Domain("unicode.org")
|
||||
override fun id(): String = name
|
||||
|
||||
companion object {
|
||||
val domain = Domain("unicode.org")
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@
|
||||
package dev.usbharu.hideout.core.domain.model.emoji
|
||||
|
||||
@JvmInline
|
||||
value class CustomEmojiId(val emojiId: Long) {
|
||||
value class EmojiId(val emojiId: Long) {
|
||||
init {
|
||||
require(0 <= emojiId)
|
||||
}
|
||||
@@ -20,7 +20,7 @@ import dev.usbharu.hideout.core.domain.event.post.PostDomainEventFactory
|
||||
import dev.usbharu.hideout.core.domain.event.post.PostEvent
|
||||
import dev.usbharu.hideout.core.domain.model.actor.Actor
|
||||
import dev.usbharu.hideout.core.domain.model.actor.ActorId
|
||||
import dev.usbharu.hideout.core.domain.model.emoji.CustomEmojiId
|
||||
import dev.usbharu.hideout.core.domain.model.emoji.EmojiId
|
||||
import dev.usbharu.hideout.core.domain.model.instance.InstanceId
|
||||
import dev.usbharu.hideout.core.domain.model.media.MediaId
|
||||
import dev.usbharu.hideout.core.domain.shared.domainevent.DomainEventStorable
|
||||
@@ -138,7 +138,7 @@ class Post(
|
||||
return content.text
|
||||
}
|
||||
|
||||
val emojiIds: List<CustomEmojiId>
|
||||
val emojiIds: List<EmojiId>
|
||||
get() {
|
||||
if (hide) {
|
||||
return PostContent.empty.emojiIds
|
||||
@@ -217,7 +217,7 @@ class Post(
|
||||
|
||||
override fun hashCode(): Int = id.hashCode()
|
||||
|
||||
fun reconstructWith(mediaIds: List<MediaId>, emojis: List<CustomEmojiId>, visibleActors: Set<ActorId>): Post {
|
||||
fun reconstructWith(mediaIds: List<MediaId>, emojis: List<EmojiId>, visibleActors: Set<ActorId>): Post {
|
||||
return Post(
|
||||
id = id,
|
||||
actorId = actorId,
|
||||
|
||||
+2
-2
@@ -16,9 +16,9 @@
|
||||
|
||||
package dev.usbharu.hideout.core.domain.model.post
|
||||
|
||||
import dev.usbharu.hideout.core.domain.model.emoji.CustomEmojiId
|
||||
import dev.usbharu.hideout.core.domain.model.emoji.EmojiId
|
||||
|
||||
data class PostContent(val text: String, val content: String, val emojiIds: List<CustomEmojiId>) {
|
||||
data class PostContent(val text: String, val content: String, val emojiIds: List<EmojiId>) {
|
||||
|
||||
companion object {
|
||||
val empty = PostContent("", "", emptyList())
|
||||
|
||||
-57
@@ -1,57 +0,0 @@
|
||||
package dev.usbharu.hideout.core.domain.model.reaction
|
||||
|
||||
import dev.usbharu.hideout.core.domain.event.reaction.ReactionEvent
|
||||
import dev.usbharu.hideout.core.domain.event.reaction.ReactionEventFactory
|
||||
import dev.usbharu.hideout.core.domain.model.actor.ActorId
|
||||
import dev.usbharu.hideout.core.domain.model.emoji.CustomEmojiId
|
||||
import dev.usbharu.hideout.core.domain.model.emoji.UnicodeEmoji
|
||||
import dev.usbharu.hideout.core.domain.model.post.PostId
|
||||
import dev.usbharu.hideout.core.domain.shared.domainevent.DomainEventStorable
|
||||
import java.time.Instant
|
||||
|
||||
class Reaction(
|
||||
val id: ReactionId,
|
||||
val postId: PostId,
|
||||
val actorId: ActorId,
|
||||
val customEmojiId: CustomEmojiId?,
|
||||
val unicodeEmoji: UnicodeEmoji,
|
||||
val createdAt: Instant
|
||||
) : DomainEventStorable() {
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as Reaction
|
||||
|
||||
return id == other.id
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return id.hashCode()
|
||||
}
|
||||
|
||||
fun delete() {
|
||||
addDomainEvent(ReactionEventFactory(this).createEvent(ReactionEvent.DELETE))
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun create(
|
||||
id: ReactionId,
|
||||
postId: PostId,
|
||||
actorId: ActorId,
|
||||
customEmojiId: CustomEmojiId?,
|
||||
unicodeEmoji: UnicodeEmoji,
|
||||
createdAt: Instant
|
||||
): Reaction {
|
||||
return Reaction(
|
||||
id,
|
||||
postId,
|
||||
actorId,
|
||||
customEmojiId,
|
||||
unicodeEmoji,
|
||||
createdAt
|
||||
).apply { addDomainEvent(ReactionEventFactory(this).createEvent(ReactionEvent.CREATE)) }
|
||||
}
|
||||
}
|
||||
}
|
||||
-4
@@ -1,4 +0,0 @@
|
||||
package dev.usbharu.hideout.core.domain.model.reaction
|
||||
|
||||
@JvmInline
|
||||
value class ReactionId(val value: Long)
|
||||
-26
@@ -1,26 +0,0 @@
|
||||
package dev.usbharu.hideout.core.domain.model.reaction
|
||||
|
||||
import dev.usbharu.hideout.core.domain.model.actor.ActorId
|
||||
import dev.usbharu.hideout.core.domain.model.emoji.CustomEmojiId
|
||||
import dev.usbharu.hideout.core.domain.model.post.PostId
|
||||
|
||||
interface ReactionRepository {
|
||||
suspend fun save(reaction: Reaction): Reaction
|
||||
suspend fun findById(reactionId: ReactionId): Reaction?
|
||||
suspend fun findByPostId(postId: PostId): List<Reaction>
|
||||
suspend fun existsByPostIdAndActorIdAndCustomEmojiIdOrUnicodeEmoji(
|
||||
postId: PostId,
|
||||
actorId: ActorId,
|
||||
customEmojiId: CustomEmojiId?,
|
||||
unicodeEmoji: String
|
||||
): Boolean
|
||||
|
||||
suspend fun findByPostIdAndActorIdAndCustomEmojiIdOrUnicodeEmoji(
|
||||
postId: PostId,
|
||||
actorId: ActorId,
|
||||
customEmojiId: CustomEmojiId?,
|
||||
unicodeEmoji: String
|
||||
): Reaction?
|
||||
|
||||
suspend fun delete(reaction: Reaction)
|
||||
}
|
||||
+8
-9
@@ -44,12 +44,15 @@ class Relationship(
|
||||
var mutingFollowRequest: Boolean = mutingFollowRequest
|
||||
private set
|
||||
|
||||
fun follow() {
|
||||
require(blocking.not())
|
||||
following = true
|
||||
addDomainEvent(RelationshipEventFactory(this).createEvent(RelationshipEvent.FOLLOW))
|
||||
}
|
||||
|
||||
fun unfollow() {
|
||||
following = false
|
||||
followRequesting = false
|
||||
val relationshipEventFactory = RelationshipEventFactory(this)
|
||||
addDomainEvent(relationshipEventFactory.createEvent(RelationshipEvent.UNFOLLOW))
|
||||
addDomainEvent(relationshipEventFactory.createEvent(RelationshipEvent.UNFOLLOW_REQUEST))
|
||||
addDomainEvent(RelationshipEventFactory(this).createEvent(RelationshipEvent.UNFOLLOW))
|
||||
}
|
||||
|
||||
fun block() {
|
||||
@@ -93,15 +96,11 @@ class Relationship(
|
||||
}
|
||||
|
||||
fun acceptFollowRequest() {
|
||||
require(blocking.not())
|
||||
following = true
|
||||
addDomainEvent(RelationshipEventFactory(this).createEvent(RelationshipEvent.ACCEPT_FOLLOW))
|
||||
follow()
|
||||
followRequesting = false
|
||||
}
|
||||
|
||||
fun rejectFollowRequest() {
|
||||
require(followRequesting)
|
||||
addDomainEvent(RelationshipEventFactory(this).createEvent(RelationshipEvent.REJECT_FOLLOW))
|
||||
followRequesting = false
|
||||
}
|
||||
|
||||
|
||||
+3
-10
@@ -1,6 +1,5 @@
|
||||
package dev.usbharu.hideout.core.domain.model.support.timelineobjectdetail
|
||||
|
||||
import dev.usbharu.hideout.core.application.model.Reactions
|
||||
import dev.usbharu.hideout.core.domain.model.actor.Actor
|
||||
import dev.usbharu.hideout.core.domain.model.media.Media
|
||||
import dev.usbharu.hideout.core.domain.model.post.Post
|
||||
@@ -30,9 +29,7 @@ data class TimelineObjectDetail(
|
||||
val isPureRepost: Boolean,
|
||||
val lastUpdateAt: Instant,
|
||||
val hasMediaInRepost: Boolean,
|
||||
val warnFilter: List<TimelineObjectWarnFilter>,
|
||||
val reactionsList: List<Reactions>,
|
||||
val favourited: Boolean
|
||||
val warnFilter: List<TimelineObjectWarnFilter>
|
||||
) {
|
||||
companion object {
|
||||
@Suppress("LongParameterList")
|
||||
@@ -51,9 +48,7 @@ data class TimelineObjectDetail(
|
||||
repostPostMedias: List<Media>?,
|
||||
repostPostActor: Actor?,
|
||||
repostPostActorIconMedia: Media?,
|
||||
warnFilter: List<TimelineObjectWarnFilter>,
|
||||
reactionsList: List<Reactions>,
|
||||
favourited: Boolean
|
||||
warnFilter: List<TimelineObjectWarnFilter>
|
||||
): TimelineObjectDetail {
|
||||
return TimelineObjectDetail(
|
||||
id = timelineObject.id,
|
||||
@@ -74,9 +69,7 @@ data class TimelineObjectDetail(
|
||||
isPureRepost = timelineObject.isPureRepost,
|
||||
lastUpdateAt = timelineObject.lastUpdatedAt,
|
||||
hasMediaInRepost = timelineObject.hasMediaInRepost,
|
||||
warnFilter = warnFilter,
|
||||
reactionsList = reactionsList,
|
||||
favourited = favourited
|
||||
warnFilter = warnFilter
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
-6
@@ -1,7 +1,5 @@
|
||||
package dev.usbharu.hideout.core.domain.model.timeline
|
||||
|
||||
import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailId
|
||||
|
||||
interface TimelineRepository {
|
||||
suspend fun save(timeline: Timeline): Timeline
|
||||
suspend fun delete(timeline: Timeline)
|
||||
@@ -9,8 +7,4 @@ interface TimelineRepository {
|
||||
suspend fun findByIds(ids: List<TimelineId>): List<Timeline>
|
||||
|
||||
suspend fun findById(id: TimelineId): Timeline?
|
||||
suspend fun findAllByUserDetailIdAndVisibilityIn(
|
||||
userDetailId: UserDetailId,
|
||||
visibility: List<TimelineVisibility>
|
||||
): List<Timeline>
|
||||
}
|
||||
|
||||
+7
-11
@@ -1,7 +1,7 @@
|
||||
package dev.usbharu.hideout.core.domain.model.timelineobject
|
||||
|
||||
import dev.usbharu.hideout.core.domain.model.actor.ActorId
|
||||
import dev.usbharu.hideout.core.domain.model.emoji.CustomEmojiId
|
||||
import dev.usbharu.hideout.core.domain.model.emoji.EmojiId
|
||||
import dev.usbharu.hideout.core.domain.model.filter.FilterResult
|
||||
import dev.usbharu.hideout.core.domain.model.media.MediaId
|
||||
import dev.usbharu.hideout.core.domain.model.post.Post
|
||||
@@ -28,12 +28,12 @@ class TimelineObject(
|
||||
visibility: Visibility,
|
||||
isPureRepost: Boolean,
|
||||
mediaIds: List<MediaId>,
|
||||
emojiIds: List<CustomEmojiId>,
|
||||
emojiIds: List<EmojiId>,
|
||||
visibleActors: List<ActorId>,
|
||||
hasMediaInRepost: Boolean,
|
||||
lastUpdatedAt: Instant,
|
||||
var warnFilters: List<TimelineObjectWarnFilter>,
|
||||
var favourited: Boolean
|
||||
|
||||
) {
|
||||
var isPureRepost = isPureRepost
|
||||
private set
|
||||
@@ -82,8 +82,7 @@ class TimelineObject(
|
||||
timeline: Timeline,
|
||||
post: Post,
|
||||
replyActorId: ActorId?,
|
||||
filterResults: List<FilterResult>,
|
||||
favourited: Boolean
|
||||
filterResults: List<FilterResult>
|
||||
): TimelineObject {
|
||||
return TimelineObject(
|
||||
id = timelineObjectId,
|
||||
@@ -103,8 +102,7 @@ class TimelineObject(
|
||||
visibleActors = post.visibleActors.toList(),
|
||||
hasMediaInRepost = false,
|
||||
lastUpdatedAt = Instant.now(),
|
||||
warnFilters = filterResults.map { TimelineObjectWarnFilter(it.filter.id, it.matchedKeyword) },
|
||||
favourited = favourited
|
||||
warnFilters = filterResults.map { TimelineObjectWarnFilter(it.filter.id, it.matchedKeyword) }
|
||||
)
|
||||
}
|
||||
|
||||
@@ -115,8 +113,7 @@ class TimelineObject(
|
||||
post: Post,
|
||||
replyActorId: ActorId?,
|
||||
repost: Post,
|
||||
filterResults: List<FilterResult>,
|
||||
favourited: Boolean
|
||||
filterResults: List<FilterResult>
|
||||
): TimelineObject {
|
||||
require(post.repostId == repost.id)
|
||||
|
||||
@@ -141,8 +138,7 @@ class TimelineObject(
|
||||
visibleActors = post.visibleActors.toList(),
|
||||
hasMediaInRepost = repost.mediaIds.isNotEmpty(),
|
||||
lastUpdatedAt = Instant.now(),
|
||||
warnFilters = filterResults.map { TimelineObjectWarnFilter(it.filter.id, it.matchedKeyword) },
|
||||
favourited = favourited
|
||||
warnFilters = filterResults.map { TimelineObjectWarnFilter(it.filter.id, it.matchedKeyword) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-14
@@ -8,20 +8,7 @@ class TimelineRelationship(
|
||||
val timelineId: TimelineId,
|
||||
val actorId: ActorId,
|
||||
val visible: Visible
|
||||
) {
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as TimelineRelationship
|
||||
|
||||
return id == other.id
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return id.hashCode()
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
enum class Visible {
|
||||
PUBLIC,
|
||||
|
||||
-3
@@ -1,13 +1,10 @@
|
||||
package dev.usbharu.hideout.core.domain.model.timelinerelationship
|
||||
|
||||
import dev.usbharu.hideout.core.domain.model.actor.ActorId
|
||||
import dev.usbharu.hideout.core.domain.model.timeline.TimelineId
|
||||
|
||||
interface TimelineRelationshipRepository {
|
||||
suspend fun save(timelineRelationship: TimelineRelationship): TimelineRelationship
|
||||
suspend fun delete(timelineRelationship: TimelineRelationship)
|
||||
|
||||
suspend fun findByActorId(actorId: ActorId): List<TimelineRelationship>
|
||||
suspend fun findById(timelineRelationshipId: TimelineRelationshipId): TimelineRelationship?
|
||||
suspend fun findByTimelineIdAndActorId(timelineId: TimelineId, actorId: ActorId): TimelineRelationship?
|
||||
}
|
||||
|
||||
-5
@@ -1,5 +0,0 @@
|
||||
package dev.usbharu.hideout.core.domain.service.emoji
|
||||
|
||||
interface UnicodeEmojiService {
|
||||
fun isUnicodeEmoji(emoji: String): Boolean
|
||||
}
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
package dev.usbharu.hideout.core.infrastructure.emojikt
|
||||
|
||||
import Emojis
|
||||
import dev.usbharu.hideout.core.domain.service.emoji.UnicodeEmojiService
|
||||
import org.springframework.stereotype.Service
|
||||
|
||||
@Service
|
||||
class EmojiKtUnicodeEmojiService : UnicodeEmojiService {
|
||||
override fun isUnicodeEmoji(emoji: String): Boolean {
|
||||
return Emojis.allEmojis.singleOrNull { it.char == emoji } != null
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -17,7 +17,7 @@
|
||||
package dev.usbharu.hideout.core.infrastructure.exposed
|
||||
|
||||
import dev.usbharu.hideout.core.domain.model.actor.*
|
||||
import dev.usbharu.hideout.core.domain.model.emoji.CustomEmojiId
|
||||
import dev.usbharu.hideout.core.domain.model.emoji.EmojiId
|
||||
import dev.usbharu.hideout.core.domain.model.instance.InstanceId
|
||||
import dev.usbharu.hideout.core.domain.model.media.MediaId
|
||||
import dev.usbharu.hideout.core.domain.model.support.domain.Domain
|
||||
@@ -57,7 +57,7 @@ class ActorResultRowMapper : ResultRowMapper<Actor> {
|
||||
emojiIds = resultRow[Actors.emojis]
|
||||
.split(",")
|
||||
.filter { it.isNotEmpty() }
|
||||
.map { CustomEmojiId(it.toLong()) }
|
||||
.map { EmojiId(it.toLong()) }
|
||||
.toSet(),
|
||||
deleted = resultRow[Actors.deleted],
|
||||
icon = resultRow[Actors.icon]?.let { MediaId(it) },
|
||||
|
||||
+2
-2
@@ -17,7 +17,7 @@
|
||||
package dev.usbharu.hideout.core.infrastructure.exposed
|
||||
|
||||
import dev.usbharu.hideout.core.domain.model.actor.ActorId
|
||||
import dev.usbharu.hideout.core.domain.model.emoji.CustomEmojiId
|
||||
import dev.usbharu.hideout.core.domain.model.emoji.EmojiId
|
||||
import dev.usbharu.hideout.core.domain.model.media.MediaId
|
||||
import dev.usbharu.hideout.core.domain.model.post.Post
|
||||
import dev.usbharu.hideout.core.infrastructure.exposedrepository.Posts
|
||||
@@ -55,7 +55,7 @@ class PostQueryMapper(private val postResultRowMapper: ResultRowMapper<Post>) :
|
||||
.mapNotNull { resultRow: ResultRow ->
|
||||
resultRow
|
||||
.getOrNull(PostsEmojis.emojiId)
|
||||
?.let { emojiId -> CustomEmojiId(emojiId) }
|
||||
?.let { emojiId -> EmojiId(emojiId) }
|
||||
},
|
||||
visibleActors = it.mapNotNull { resultRow: ResultRow ->
|
||||
resultRow
|
||||
|
||||
-73
@@ -1,73 +0,0 @@
|
||||
package dev.usbharu.hideout.core.infrastructure.exposedquery
|
||||
|
||||
import dev.usbharu.hideout.core.application.model.Reactions
|
||||
import dev.usbharu.hideout.core.domain.model.emoji.UnicodeEmoji
|
||||
import dev.usbharu.hideout.core.domain.model.post.PostId
|
||||
import dev.usbharu.hideout.core.infrastructure.exposedrepository.AbstractRepository
|
||||
import dev.usbharu.hideout.core.infrastructure.exposedrepository.CustomEmojis
|
||||
import dev.usbharu.hideout.core.infrastructure.exposedrepository.toCustomEmojiOrNull
|
||||
import dev.usbharu.hideout.core.infrastructure.exposedrepository.toReaction
|
||||
import dev.usbharu.hideout.core.query.reactions.ReactionsQueryService
|
||||
import org.jetbrains.exposed.sql.*
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.stereotype.Repository
|
||||
import java.net.URI
|
||||
import dev.usbharu.hideout.core.infrastructure.exposedrepository.Reactions as ExposedrepositoryReactions
|
||||
|
||||
@Repository
|
||||
class ExposedReactionsQueryService : ReactionsQueryService, AbstractRepository() {
|
||||
override suspend fun findAllByPostId(postId: PostId): List<Reactions> {
|
||||
return query {
|
||||
ExposedrepositoryReactions.leftJoin(CustomEmojis).selectAll()
|
||||
.where { ExposedrepositoryReactions.postId eq postId.id }
|
||||
.groupBy {
|
||||
it[ExposedrepositoryReactions.customEmojiId]?.toString()
|
||||
?: it[ExposedrepositoryReactions.unicodeEmoji]
|
||||
}
|
||||
.map { it.value }
|
||||
.map {
|
||||
Reactions.of(
|
||||
it.map { resultRow -> resultRow.toReaction() },
|
||||
it.first().toCustomEmojiOrNull()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun findAllByPostIdIn(postIds: List<PostId>): List<Reactions> {
|
||||
return query {
|
||||
val actorIdsQuery =
|
||||
ExposedrepositoryReactions.actorId.castTo<String>(VarCharColumnType()).groupConcat(",", true)
|
||||
|
||||
ExposedrepositoryReactions.leftJoin(CustomEmojis)
|
||||
.select(
|
||||
ExposedrepositoryReactions.postId,
|
||||
ExposedrepositoryReactions.postId.count(),
|
||||
ExposedrepositoryReactions.customEmojiId.max(),
|
||||
ExposedrepositoryReactions.unicodeEmoji.max<String, String>(),
|
||||
actorIdsQuery
|
||||
)
|
||||
.where { ExposedrepositoryReactions.postId inList postIds.map { it.id } }
|
||||
.groupBy(ExposedrepositoryReactions.postId)
|
||||
.map {
|
||||
Reactions(
|
||||
it[ExposedrepositoryReactions.postId],
|
||||
it[ExposedrepositoryReactions.postId.count()].toInt(),
|
||||
it.getOrNull(CustomEmojis.name)
|
||||
?: it[ExposedrepositoryReactions.unicodeEmoji.max<String, String>()]!!,
|
||||
it.getOrNull(CustomEmojis.domain) ?: UnicodeEmoji.domain.domain,
|
||||
it.getOrNull(CustomEmojis.url)?.let { it1 -> URI.create(it1) },
|
||||
it[actorIdsQuery].split(",").mapNotNull { it.toLongOrNull() }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override val logger: Logger
|
||||
get() = Companion.logger
|
||||
|
||||
companion object {
|
||||
private val logger = LoggerFactory.getLogger(ExposedReactionsQueryService::class.java)
|
||||
}
|
||||
}
|
||||
+2
-11
@@ -61,12 +61,6 @@ class ExposedUserTimelineQueryService : UserTimelineQueryService, AbstractReposi
|
||||
.leftJoin(iconMedia, { Actors.icon }, { iconMedia[Media.id] })
|
||||
.leftJoin(PostsMedia, { authorizedQuery[Posts.id] }, { PostsMedia.postId })
|
||||
.leftJoin(Media, { PostsMedia.mediaId }, { Media.id })
|
||||
.leftJoin(
|
||||
Reactions,
|
||||
{ authorizedQuery[Posts.id] },
|
||||
{ Reactions.postId },
|
||||
{ Reactions.id isDistinctFrom principal.actorId.id }
|
||||
)
|
||||
.selectAll()
|
||||
.where { authorizedQuery[Posts.id] inList idList.map { it.id } }
|
||||
.groupBy { it[authorizedQuery[Posts.id]] }
|
||||
@@ -75,8 +69,7 @@ class ExposedUserTimelineQueryService : UserTimelineQueryService, AbstractReposi
|
||||
toPostDetail(it.first(), authorizedQuery, iconMedia).copy(
|
||||
mediaDetailList = it.mapNotNull { resultRow ->
|
||||
resultRow.toMediaOrNull()?.let { it1 -> MediaDetail.of(it1) }
|
||||
},
|
||||
favourited = it.any { it.getOrNull(Reactions.actorId) != null }
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -107,9 +100,7 @@ class ExposedUserTimelineQueryService : UserTimelineQueryService, AbstractReposi
|
||||
sensitive = it[authorizedQuery[Posts.sensitive]],
|
||||
deleted = it[authorizedQuery[Posts.deleted]],
|
||||
mediaDetailList = emptyList(),
|
||||
moveTo = null,
|
||||
emptyList(),
|
||||
favourited = false
|
||||
moveTo = null
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+24
-11
@@ -17,8 +17,8 @@
|
||||
package dev.usbharu.hideout.core.infrastructure.exposedrepository
|
||||
|
||||
import dev.usbharu.hideout.core.domain.model.emoji.CustomEmoji
|
||||
import dev.usbharu.hideout.core.domain.model.emoji.CustomEmojiId
|
||||
import dev.usbharu.hideout.core.domain.model.emoji.CustomEmojiRepository
|
||||
import dev.usbharu.hideout.core.domain.model.emoji.EmojiId
|
||||
import dev.usbharu.hideout.core.domain.model.instance.InstanceId
|
||||
import dev.usbharu.hideout.core.domain.model.support.domain.Domain
|
||||
import org.jetbrains.exposed.sql.*
|
||||
@@ -37,14 +37,27 @@ class CustomEmojiRepositoryImpl : CustomEmojiRepository,
|
||||
get() = Companion.logger
|
||||
|
||||
override suspend fun save(customEmoji: CustomEmoji): CustomEmoji = query {
|
||||
CustomEmojis.upsert {
|
||||
it[id] = customEmoji.id.emojiId
|
||||
it[name] = customEmoji.name
|
||||
it[domain] = customEmoji.domain.domain
|
||||
it[instanceId] = customEmoji.instanceId.instanceId
|
||||
it[url] = customEmoji.url.toString()
|
||||
it[category] = customEmoji.category
|
||||
it[createdAt] = customEmoji.createdAt
|
||||
val singleOrNull =
|
||||
CustomEmojis.selectAll().where { CustomEmojis.id eq customEmoji.id.emojiId }.forUpdate().singleOrNull()
|
||||
if (singleOrNull == null) {
|
||||
CustomEmojis.insert {
|
||||
it[id] = customEmoji.id.emojiId
|
||||
it[name] = customEmoji.name
|
||||
it[domain] = customEmoji.domain.domain
|
||||
it[instanceId] = customEmoji.instanceId.instanceId
|
||||
it[url] = customEmoji.url.toString()
|
||||
it[category] = customEmoji.category
|
||||
it[createdAt] = customEmoji.createdAt
|
||||
}
|
||||
} else {
|
||||
CustomEmojis.update({ CustomEmojis.id eq customEmoji.id.emojiId }) {
|
||||
it[name] = customEmoji.name
|
||||
it[domain] = customEmoji.domain.domain
|
||||
it[instanceId] = customEmoji.instanceId.instanceId
|
||||
it[url] = customEmoji.url.toString()
|
||||
it[category] = customEmoji.category
|
||||
it[createdAt] = customEmoji.createdAt
|
||||
}
|
||||
}
|
||||
return@query customEmoji
|
||||
}
|
||||
@@ -81,7 +94,7 @@ class CustomEmojiRepositoryImpl : CustomEmojiRepository,
|
||||
}
|
||||
|
||||
fun ResultRow.toCustomEmoji(): CustomEmoji = CustomEmoji(
|
||||
id = CustomEmojiId(this[CustomEmojis.id]),
|
||||
id = EmojiId(this[CustomEmojis.id]),
|
||||
name = this[CustomEmojis.name],
|
||||
domain = Domain(this[CustomEmojis.domain]),
|
||||
instanceId = InstanceId(this[CustomEmojis.instanceId]),
|
||||
@@ -92,7 +105,7 @@ fun ResultRow.toCustomEmoji(): CustomEmoji = CustomEmoji(
|
||||
|
||||
fun ResultRow.toCustomEmojiOrNull(): CustomEmoji? {
|
||||
return CustomEmoji(
|
||||
id = CustomEmojiId(this.getOrNull(CustomEmojis.id) ?: return null),
|
||||
id = EmojiId(this.getOrNull(CustomEmojis.id) ?: return null),
|
||||
name = this.getOrNull(CustomEmojis.name) ?: return null,
|
||||
domain = Domain(this.getOrNull(CustomEmojis.domain) ?: return null),
|
||||
instanceId = InstanceId(this.getOrNull(CustomEmojis.instanceId) ?: return null),
|
||||
|
||||
+1
-1
@@ -168,7 +168,7 @@ class ExposedPostRepository(
|
||||
Posts.id eq id.id
|
||||
}
|
||||
.let(postQueryMapper::map)
|
||||
.firstOrNull()
|
||||
.first()
|
||||
}
|
||||
|
||||
override suspend fun findAllById(ids: List<PostId>): List<Post> {
|
||||
|
||||
-128
@@ -1,128 +0,0 @@
|
||||
package dev.usbharu.hideout.core.infrastructure.exposedrepository
|
||||
|
||||
import dev.usbharu.hideout.core.domain.model.actor.ActorId
|
||||
import dev.usbharu.hideout.core.domain.model.emoji.CustomEmojiId
|
||||
import dev.usbharu.hideout.core.domain.model.emoji.UnicodeEmoji
|
||||
import dev.usbharu.hideout.core.domain.model.post.PostId
|
||||
import dev.usbharu.hideout.core.domain.model.reaction.Reaction
|
||||
import dev.usbharu.hideout.core.domain.model.reaction.ReactionId
|
||||
import dev.usbharu.hideout.core.domain.model.reaction.ReactionRepository
|
||||
import dev.usbharu.hideout.core.domain.shared.domainevent.DomainEventPublisher
|
||||
import dev.usbharu.hideout.core.domain.shared.repository.DomainEventPublishableRepository
|
||||
import org.jetbrains.exposed.sql.*
|
||||
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
|
||||
import org.jetbrains.exposed.sql.javatime.timestamp
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.stereotype.Repository
|
||||
|
||||
@Repository
|
||||
class ExposedReactionRepository(override val domainEventPublisher: DomainEventPublisher) :
|
||||
ReactionRepository,
|
||||
AbstractRepository(),
|
||||
DomainEventPublishableRepository<Reaction> {
|
||||
|
||||
override val logger: Logger
|
||||
get() = Companion.logger
|
||||
|
||||
override suspend fun save(reaction: Reaction): Reaction {
|
||||
return query {
|
||||
Reactions.upsert {
|
||||
it[Reactions.id] = reaction.id.value
|
||||
it[Reactions.postId] = reaction.postId.id
|
||||
it[Reactions.actorId] = reaction.actorId.id
|
||||
it[Reactions.customEmojiId] = reaction.customEmojiId?.emojiId
|
||||
it[Reactions.unicodeEmoji] = reaction.unicodeEmoji.name
|
||||
it[Reactions.createdAt] = reaction.createdAt
|
||||
}
|
||||
onComplete {
|
||||
update(reaction)
|
||||
}
|
||||
reaction
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun findById(reactionId: ReactionId): Reaction? {
|
||||
return query {
|
||||
Reactions.selectAll().where {
|
||||
Reactions.id eq reactionId.value
|
||||
}.singleOrNull()?.toReaction()
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun findByPostId(postId: PostId): List<Reaction> {
|
||||
return query {
|
||||
Reactions.selectAll().where {
|
||||
Reactions.postId eq postId.id
|
||||
}.map { it.toReaction() }
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun existsByPostIdAndActorIdAndCustomEmojiIdOrUnicodeEmoji(
|
||||
postId: PostId,
|
||||
actorId: ActorId,
|
||||
customEmojiId: CustomEmojiId?,
|
||||
unicodeEmoji: String
|
||||
): Boolean {
|
||||
return query {
|
||||
Reactions.selectAll().where {
|
||||
Reactions.postId.eq(postId.id).and(Reactions.actorId eq actorId.id)
|
||||
.and(
|
||||
(Reactions.customEmojiId eq customEmojiId?.emojiId or (Reactions.unicodeEmoji eq unicodeEmoji))
|
||||
)
|
||||
}.empty().not()
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun delete(reaction: Reaction) {
|
||||
return query {
|
||||
Reactions.deleteWhere {
|
||||
Reactions.id eq reaction.id.value
|
||||
}
|
||||
onComplete {
|
||||
update(reaction)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun findByPostIdAndActorIdAndCustomEmojiIdOrUnicodeEmoji(
|
||||
postId: PostId,
|
||||
actorId: ActorId,
|
||||
customEmojiId: CustomEmojiId?,
|
||||
unicodeEmoji: String
|
||||
): Reaction? {
|
||||
return query {
|
||||
Reactions.selectAll().where {
|
||||
Reactions.postId.eq(postId.id).and(Reactions.actorId eq actorId.id)
|
||||
.and(
|
||||
(Reactions.customEmojiId eq customEmojiId?.emojiId or (Reactions.unicodeEmoji eq unicodeEmoji))
|
||||
)
|
||||
}.limit(1).singleOrNull()?.toReaction()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val logger = LoggerFactory.getLogger(ExposedReactionRepository::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
fun ResultRow.toReaction(): Reaction {
|
||||
return Reaction(
|
||||
ReactionId(this[Reactions.id]),
|
||||
PostId(this[Reactions.postId]),
|
||||
ActorId(this[Reactions.actorId]),
|
||||
this[Reactions.customEmojiId]?.let { CustomEmojiId(it) },
|
||||
UnicodeEmoji(this[Reactions.unicodeEmoji]),
|
||||
this[Reactions.createdAt]
|
||||
)
|
||||
}
|
||||
|
||||
object Reactions : Table("reactions") {
|
||||
val id = long("id")
|
||||
val postId = long("post_id").references(Posts.id)
|
||||
val actorId = long("actor_id").references(Actors.id)
|
||||
val customEmojiId = long("custom_emoji_id").references(CustomEmojis.id).nullable()
|
||||
val unicodeEmoji = varchar("unicode_emoji", 100)
|
||||
val createdAt = timestamp("created_at")
|
||||
override val primaryKey: PrimaryKey = PrimaryKey(id)
|
||||
}
|
||||
+1
-17
@@ -19,7 +19,7 @@ class ExposedTimelineRelationshipRepository : AbstractRepository(), TimelineRela
|
||||
|
||||
override suspend fun save(timelineRelationship: TimelineRelationship): TimelineRelationship {
|
||||
query {
|
||||
TimelineRelationships.upsert {
|
||||
TimelineRelationships.insert {
|
||||
it[id] = timelineRelationship.id.value
|
||||
it[timelineId] = timelineRelationship.timelineId.value
|
||||
it[actorId] = timelineRelationship.actorId.id
|
||||
@@ -45,22 +45,6 @@ class ExposedTimelineRelationshipRepository : AbstractRepository(), TimelineRela
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun findById(timelineRelationshipId: TimelineRelationshipId): TimelineRelationship? {
|
||||
return query {
|
||||
TimelineRelationships.selectAll().where {
|
||||
TimelineRelationships.id eq timelineRelationshipId.value
|
||||
}.singleOrNull()?.toTimelineRelationship()
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun findByTimelineIdAndActorId(timelineId: TimelineId, actorId: ActorId): TimelineRelationship? {
|
||||
return query {
|
||||
TimelineRelationships.selectAll().where {
|
||||
TimelineRelationships.timelineId eq timelineId.value and (TimelineRelationships.actorId eq actorId.id)
|
||||
}.singleOrNull()?.toTimelineRelationship()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val logger = LoggerFactory.getLogger(ExposedTimelineRelationshipRepository::class.java)
|
||||
}
|
||||
|
||||
+1
-12
@@ -20,7 +20,7 @@ class ExposedTimelineRepository(override val domainEventPublisher: DomainEventPu
|
||||
|
||||
override suspend fun save(timeline: Timeline): Timeline {
|
||||
query {
|
||||
Timelines.upsert {
|
||||
Timelines.insert {
|
||||
it[id] = timeline.id.value
|
||||
it[userDetailId] = timeline.userDetailId.id
|
||||
it[name] = timeline.name.value
|
||||
@@ -58,17 +58,6 @@ class ExposedTimelineRepository(override val domainEventPublisher: DomainEventPu
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun findAllByUserDetailIdAndVisibilityIn(
|
||||
userDetailId: UserDetailId,
|
||||
visibility: List<TimelineVisibility>
|
||||
): List<Timeline> {
|
||||
return query {
|
||||
Timelines.selectAll().where {
|
||||
Timelines.userDetailId eq userDetailId.id and (Timelines.visibility inList visibility.map { it.name })
|
||||
}.map { it.toTimeline() }
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val logger = LoggerFactory.getLogger(ExposedTimelineRepository::class.java.name)
|
||||
}
|
||||
|
||||
+29
-14
@@ -33,21 +33,36 @@ class InstanceRepositoryImpl : InstanceRepository,
|
||||
get() = Companion.logger
|
||||
|
||||
override suspend fun save(instance: InstanceEntity): InstanceEntity = query {
|
||||
Instance.upsert {
|
||||
it[id] = instance.id.instanceId
|
||||
it[name] = instance.name.name
|
||||
it[description] = instance.description.description
|
||||
it[url] = instance.url.toString()
|
||||
it[iconUrl] = instance.iconUrl.toString()
|
||||
it[sharedInbox] = instance.sharedInbox?.toString()
|
||||
it[software] = instance.software.software
|
||||
it[version] = instance.version.version
|
||||
it[isBlocked] = instance.isBlocked
|
||||
it[isMuted] = instance.isMuted
|
||||
it[moderationNote] = instance.moderationNote.note
|
||||
it[createdAt] = instance.createdAt
|
||||
if (Instance.selectAll().where { Instance.id.eq(instance.id.instanceId) }.forUpdate().empty()) {
|
||||
Instance.insert {
|
||||
it[id] = instance.id.instanceId
|
||||
it[name] = instance.name.name
|
||||
it[description] = instance.description.description
|
||||
it[url] = instance.url.toString()
|
||||
it[iconUrl] = instance.iconUrl.toString()
|
||||
it[sharedInbox] = instance.sharedInbox?.toString()
|
||||
it[software] = instance.software.software
|
||||
it[version] = instance.version.version
|
||||
it[isBlocked] = instance.isBlocked
|
||||
it[isMuted] = instance.isMuted
|
||||
it[moderationNote] = instance.moderationNote.note
|
||||
it[createdAt] = instance.createdAt
|
||||
}
|
||||
} else {
|
||||
Instance.update({ Instance.id eq instance.id.instanceId }) {
|
||||
it[name] = instance.name.name
|
||||
it[description] = instance.description.description
|
||||
it[url] = instance.url.toString()
|
||||
it[iconUrl] = instance.iconUrl.toString()
|
||||
it[sharedInbox] = instance.sharedInbox?.toString()
|
||||
it[software] = instance.software.software
|
||||
it[version] = instance.version.version
|
||||
it[isBlocked] = instance.isBlocked
|
||||
it[isMuted] = instance.isMuted
|
||||
it[moderationNote] = instance.moderationNote.note
|
||||
it[createdAt] = instance.createdAt
|
||||
}
|
||||
}
|
||||
|
||||
return@query instance
|
||||
}
|
||||
|
||||
|
||||
+31
-16
@@ -31,22 +31,6 @@ class MediaRepositoryImpl : MediaRepository, AbstractRepository() {
|
||||
override val logger: Logger
|
||||
get() = Companion.logger
|
||||
|
||||
override suspend fun save(media: EntityMedia): EntityMedia = query {
|
||||
Media.upsert {
|
||||
it[id] = media.id.id
|
||||
it[name] = media.name.name
|
||||
it[url] = media.url.toString()
|
||||
it[remoteUrl] = media.remoteUrl?.toString()
|
||||
it[thumbnailUrl] = media.thumbnailUrl?.toString()
|
||||
it[type] = media.type.name
|
||||
it[blurhash] = media.blurHash?.hash
|
||||
it[mimeType] = media.mimeType.type + "/" + media.mimeType.subtype
|
||||
it[description] = media.description?.description
|
||||
it[actorId] = media.actorId.id
|
||||
}
|
||||
return@query media
|
||||
}
|
||||
|
||||
override suspend fun findById(id: MediaId): dev.usbharu.hideout.core.domain.model.media.Media? {
|
||||
return query {
|
||||
return@query Media
|
||||
@@ -71,6 +55,37 @@ class MediaRepositoryImpl : MediaRepository, AbstractRepository() {
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun save(media: EntityMedia): EntityMedia = query {
|
||||
if (Media.selectAll().where { Media.id eq media.id.id }.forUpdate().singleOrNull() != null
|
||||
) {
|
||||
Media.update({ Media.id eq media.id.id }) {
|
||||
it[name] = media.name.name
|
||||
it[url] = media.url.toString()
|
||||
it[remoteUrl] = media.remoteUrl?.toString()
|
||||
it[thumbnailUrl] = media.thumbnailUrl?.toString()
|
||||
it[type] = media.type.name
|
||||
it[blurhash] = media.blurHash?.hash
|
||||
it[mimeType] = media.mimeType.type + "/" + media.mimeType.subtype
|
||||
it[description] = media.description?.description
|
||||
it[actorId] = media.actorId.id
|
||||
}
|
||||
} else {
|
||||
Media.insert {
|
||||
it[id] = media.id.id
|
||||
it[name] = media.name.name
|
||||
it[url] = media.url.toString()
|
||||
it[remoteUrl] = media.remoteUrl?.toString()
|
||||
it[thumbnailUrl] = media.thumbnailUrl?.toString()
|
||||
it[type] = media.type.name
|
||||
it[blurhash] = media.blurHash?.hash
|
||||
it[mimeType] = media.mimeType.type + "/" + media.mimeType.subtype
|
||||
it[description] = media.description?.description
|
||||
it[actorId] = media.actorId.id
|
||||
}
|
||||
}
|
||||
return@query media
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val logger = LoggerFactory.getLogger(MediaRepositoryImpl::class.java)
|
||||
}
|
||||
|
||||
+19
-8
@@ -41,15 +41,26 @@ class UserDetailRepositoryImpl(override val domainEventPublisher: DomainEventPub
|
||||
|
||||
override suspend fun save(userDetail: UserDetail): UserDetail {
|
||||
val userDetail1 = query {
|
||||
UserDetails.upsert {
|
||||
it[id] = userDetail.id.id
|
||||
it[actorId] = userDetail.actorId.id
|
||||
it[password] = userDetail.password.password
|
||||
it[autoAcceptFolloweeFollowRequest] = userDetail.autoAcceptFolloweeFollowRequest
|
||||
it[lastMigration] = userDetail.lastMigration
|
||||
it[homeTimelineId] = userDetail.homeTimelineId?.value
|
||||
val singleOrNull =
|
||||
UserDetails.selectAll().where { UserDetails.id eq userDetail.id.id }.forUpdate().singleOrNull()
|
||||
if (singleOrNull == null) {
|
||||
UserDetails.insert {
|
||||
it[id] = userDetail.id.id
|
||||
it[actorId] = userDetail.actorId.id
|
||||
it[password] = userDetail.password.password
|
||||
it[autoAcceptFolloweeFollowRequest] = userDetail.autoAcceptFolloweeFollowRequest
|
||||
it[lastMigration] = userDetail.lastMigration
|
||||
it[homeTimelineId] = userDetail.homeTimelineId?.value
|
||||
}
|
||||
} else {
|
||||
UserDetails.update({ UserDetails.id eq userDetail.id.id }) {
|
||||
it[actorId] = userDetail.actorId.id
|
||||
it[password] = userDetail.password.password
|
||||
it[autoAcceptFolloweeFollowRequest] = userDetail.autoAcceptFolloweeFollowRequest
|
||||
it[lastMigration] = userDetail.lastMigration
|
||||
it[homeTimelineId] = userDetail.homeTimelineId?.value
|
||||
}
|
||||
}
|
||||
|
||||
onComplete {
|
||||
update(userDetail)
|
||||
}
|
||||
|
||||
+5
-8
@@ -1,7 +1,7 @@
|
||||
package dev.usbharu.hideout.core.infrastructure.mongorepository
|
||||
|
||||
import dev.usbharu.hideout.core.domain.model.actor.ActorId
|
||||
import dev.usbharu.hideout.core.domain.model.emoji.CustomEmojiId
|
||||
import dev.usbharu.hideout.core.domain.model.emoji.EmojiId
|
||||
import dev.usbharu.hideout.core.domain.model.filter.FilterId
|
||||
import dev.usbharu.hideout.core.domain.model.media.MediaId
|
||||
import dev.usbharu.hideout.core.domain.model.post.PostId
|
||||
@@ -133,8 +133,7 @@ data class SpringDataMongoTimelineObject(
|
||||
val visibleActors: List<Long>,
|
||||
val hasMediaInRepost: Boolean,
|
||||
val lastUpdatedAt: Long,
|
||||
val warnFilters: List<SpringDataMongoTimelineObjectWarnFilter>,
|
||||
val favourited: Boolean
|
||||
val warnFilters: List<SpringDataMongoTimelineObjectWarnFilter>
|
||||
) {
|
||||
|
||||
fun toTimelineObject(): TimelineObject {
|
||||
@@ -152,12 +151,11 @@ data class SpringDataMongoTimelineObject(
|
||||
visibility = visibility,
|
||||
isPureRepost = isPureRepost,
|
||||
mediaIds = mediaIds.map { MediaId(it) },
|
||||
emojiIds = emojiIds.map { CustomEmojiId(it) },
|
||||
emojiIds = emojiIds.map { EmojiId(it) },
|
||||
visibleActors = visibleActors.map { ActorId(it) },
|
||||
hasMediaInRepost = hasMediaInRepost,
|
||||
lastUpdatedAt = Instant.ofEpochSecond(lastUpdatedAt),
|
||||
warnFilters = warnFilters.map { it.toTimelineObjectWarnFilter() },
|
||||
favourited = favourited
|
||||
warnFilters = warnFilters.map { it.toTimelineObjectWarnFilter() }
|
||||
)
|
||||
}
|
||||
|
||||
@@ -181,8 +179,7 @@ data class SpringDataMongoTimelineObject(
|
||||
visibleActors = timelineObject.visibleActors.map { it.id },
|
||||
hasMediaInRepost = timelineObject.hasMediaInRepost,
|
||||
lastUpdatedAt = timelineObject.lastUpdatedAt.epochSecond,
|
||||
warnFilters = timelineObject.warnFilters.map { SpringDataMongoTimelineObjectWarnFilter.of(it) },
|
||||
favourited = timelineObject.favourited
|
||||
warnFilters = timelineObject.warnFilters.map { SpringDataMongoTimelineObjectWarnFilter.of(it) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@ class SPAInterceptor : HandlerInterceptor {
|
||||
return
|
||||
}
|
||||
|
||||
if (request.getSession(false)?.getAttribute("s") == "f") {
|
||||
if (request.session.getAttribute("s") == "f") {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
+3
-13
@@ -1,6 +1,5 @@
|
||||
package dev.usbharu.hideout.core.infrastructure.timeline
|
||||
|
||||
import dev.usbharu.hideout.core.application.model.Reactions
|
||||
import dev.usbharu.hideout.core.domain.model.actor.Actor
|
||||
import dev.usbharu.hideout.core.domain.model.actor.ActorId
|
||||
import dev.usbharu.hideout.core.domain.model.filter.Filter
|
||||
@@ -76,8 +75,7 @@ abstract class AbstractTimelineStore(private val idGenerateService: IdGenerateSe
|
||||
post = post,
|
||||
replyActorId = replyActorId,
|
||||
repost = repost,
|
||||
filterResults = applyFilters.filterResults,
|
||||
favourited = false
|
||||
filterResults = applyFilters.filterResults
|
||||
)
|
||||
}
|
||||
|
||||
@@ -86,8 +84,7 @@ abstract class AbstractTimelineStore(private val idGenerateService: IdGenerateSe
|
||||
timeline = timeline,
|
||||
post = post,
|
||||
replyActorId = replyActorId,
|
||||
filterResults = applyFilters.filterResults,
|
||||
favourited = false
|
||||
filterResults = applyFilters.filterResults
|
||||
)
|
||||
}
|
||||
|
||||
@@ -259,8 +256,6 @@ abstract class AbstractTimelineStore(private val idGenerateService: IdGenerateSe
|
||||
actors.mapNotNull { it.value.icon }
|
||||
)
|
||||
|
||||
val reactions = getReactions(posts.map { it.id })
|
||||
|
||||
return PaginationList(
|
||||
timelineObjectList.mapNotNull<TimelineObject, TimelineObjectDetail> {
|
||||
val timelineUserDetail = userDetails[it.userDetailId] ?: return@mapNotNull null
|
||||
@@ -273,7 +268,6 @@ abstract class AbstractTimelineStore(private val idGenerateService: IdGenerateSe
|
||||
val repost = postMap[it.repostId]
|
||||
val repostMedias = repost?.post?.mediaIds?.mapNotNull { mediaId -> mediaMap[mediaId] }
|
||||
val repostActor = actors[it.repostActorId]
|
||||
val reactionsList = reactions[it.postId].orEmpty()
|
||||
TimelineObjectDetail.of(
|
||||
timelineObject = it,
|
||||
timelineUserDetail = timelineUserDetail,
|
||||
@@ -294,9 +288,7 @@ abstract class AbstractTimelineStore(private val idGenerateService: IdGenerateSe
|
||||
filterResult.filter.id,
|
||||
filterResult.matchedKeyword
|
||||
)
|
||||
},
|
||||
reactionsList = reactionsList,
|
||||
favourited = it.favourited
|
||||
}
|
||||
)
|
||||
},
|
||||
timelineObjectList.lastOrNull()?.postId,
|
||||
@@ -308,7 +300,5 @@ abstract class AbstractTimelineStore(private val idGenerateService: IdGenerateSe
|
||||
|
||||
protected abstract suspend fun getMedias(mediaIds: List<MediaId>): Map<MediaId, Media>
|
||||
|
||||
protected abstract suspend fun getReactions(postIds: List<PostId>): Map<PostId, List<Reactions>>
|
||||
|
||||
protected abstract suspend fun getUserDetails(userDetailIdList: List<UserDetailId>): Map<UserDetailId, UserDetail>
|
||||
}
|
||||
|
||||
+1
-8
@@ -1,6 +1,5 @@
|
||||
package dev.usbharu.hideout.core.infrastructure.timeline
|
||||
|
||||
import dev.usbharu.hideout.core.application.model.Reactions
|
||||
import dev.usbharu.hideout.core.config.DefaultTimelineStoreConfig
|
||||
import dev.usbharu.hideout.core.domain.model.actor.Actor
|
||||
import dev.usbharu.hideout.core.domain.model.actor.ActorId
|
||||
@@ -33,7 +32,6 @@ import dev.usbharu.hideout.core.domain.service.filter.FilterDomainService
|
||||
import dev.usbharu.hideout.core.domain.service.post.IPostReadAccessControl
|
||||
import dev.usbharu.hideout.core.domain.shared.id.IdGenerateService
|
||||
import dev.usbharu.hideout.core.external.timeline.ReadTimelineOption
|
||||
import dev.usbharu.hideout.core.query.reactions.ReactionsQueryService
|
||||
import org.springframework.stereotype.Component
|
||||
import java.time.Instant
|
||||
|
||||
@@ -51,8 +49,7 @@ open class DefaultTimelineStore(
|
||||
private val userDetailRepository: UserDetailRepository,
|
||||
private val actorRepository: ActorRepository,
|
||||
private val mediaRepository: MediaRepository,
|
||||
private val postIPostReadAccessControl: IPostReadAccessControl,
|
||||
private val reactionsQueryService: ReactionsQueryService,
|
||||
private val postIPostReadAccessControl: IPostReadAccessControl
|
||||
) : AbstractTimelineStore(idGenerateService) {
|
||||
override suspend fun getTimelines(actorId: ActorId): List<Timeline> {
|
||||
return timelineRepository.findByIds(
|
||||
@@ -160,10 +157,6 @@ open class DefaultTimelineStore(
|
||||
override suspend fun getMedias(mediaIds: List<MediaId>): Map<MediaId, Media> =
|
||||
mediaRepository.findByIds(mediaIds).associateBy { it.id }
|
||||
|
||||
override suspend fun getReactions(postIds: List<PostId>): Map<PostId, List<Reactions>> {
|
||||
return reactionsQueryService.findAllByPostIdIn(postIds).groupBy { PostId(it.postId) }
|
||||
}
|
||||
|
||||
override suspend fun getUserDetails(userDetailIdList: List<UserDetailId>): Map<UserDetailId, UserDetail> =
|
||||
userDetailRepository.findAllById(userDetailIdList).associateBy { it.id }
|
||||
}
|
||||
|
||||
+1
-36
@@ -4,25 +4,18 @@ 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.application.reaction.CreateReaction
|
||||
import dev.usbharu.hideout.core.application.reaction.RemoveReaction
|
||||
import dev.usbharu.hideout.core.application.reaction.UserCreateReactionApplicationService
|
||||
import dev.usbharu.hideout.core.application.reaction.UserRemoveReactionApplicationService
|
||||
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.PathVariable
|
||||
import org.springframework.web.bind.annotation.PostMapping
|
||||
|
||||
@Controller
|
||||
class PostsController(
|
||||
private val getPostDetailApplicationService: GetPostDetailApplicationService,
|
||||
private val springSecurityFormLoginPrincipalContextHolder: SpringSecurityFormLoginPrincipalContextHolder,
|
||||
private val getLocalInstanceApplicationService: GetLocalInstanceApplicationService,
|
||||
private val userCreateReactionApplicationService: UserCreateReactionApplicationService,
|
||||
private val userRemoveReactionApplicationService: UserRemoveReactionApplicationService
|
||||
private val getLocalInstanceApplicationService: GetLocalInstanceApplicationService
|
||||
) {
|
||||
@GetMapping("/users/{name}/posts/{id}")
|
||||
suspend fun postById(@PathVariable id: Long, model: Model): String {
|
||||
@@ -38,32 +31,4 @@ class PostsController(
|
||||
|
||||
return "postById"
|
||||
}
|
||||
|
||||
@PostMapping("/users/{name}/posts/{id}/favourite")
|
||||
suspend fun favourite(@PathVariable id: Long, @PathVariable name: String): String {
|
||||
val principal = springSecurityFormLoginPrincipalContextHolder.getPrincipal()
|
||||
userCreateReactionApplicationService.execute(
|
||||
CreateReaction(
|
||||
id,
|
||||
null,
|
||||
"❤"
|
||||
),
|
||||
principal
|
||||
)
|
||||
return "redirect:/users/$name/posts/$id"
|
||||
}
|
||||
|
||||
@PostMapping("/users/{name}/posts/{id}/unfavourite")
|
||||
suspend fun unfavourite(@PathVariable id: Long, @PathVariable name: String): String {
|
||||
val principal = springSecurityFormLoginPrincipalContextHolder.getPrincipal()
|
||||
userRemoveReactionApplicationService.execute(
|
||||
RemoveReaction(
|
||||
id,
|
||||
null,
|
||||
"❤"
|
||||
),
|
||||
principal
|
||||
)
|
||||
return "redirect:/users/$name/posts/$id"
|
||||
}
|
||||
}
|
||||
|
||||
+1
-41
@@ -3,24 +3,16 @@ package dev.usbharu.hideout.core.interfaces.web.user
|
||||
import dev.usbharu.hideout.core.application.actor.GetActorDetail
|
||||
import dev.usbharu.hideout.core.application.actor.GetActorDetailApplicationService
|
||||
import dev.usbharu.hideout.core.application.instance.GetLocalInstanceApplicationService
|
||||
import dev.usbharu.hideout.core.application.relationship.followrequest.FollowRequest
|
||||
import dev.usbharu.hideout.core.application.relationship.followrequest.UserFollowRequestApplicationService
|
||||
import dev.usbharu.hideout.core.application.relationship.get.GetRelationship
|
||||
import dev.usbharu.hideout.core.application.relationship.get.GetRelationshipApplicationService
|
||||
import dev.usbharu.hideout.core.application.relationship.unfollow.Unfollow
|
||||
import dev.usbharu.hideout.core.application.relationship.unfollow.UserUnfollowApplicationService
|
||||
import dev.usbharu.hideout.core.application.timeline.GetUserTimeline
|
||||
import dev.usbharu.hideout.core.application.timeline.GetUserTimelineApplicationService
|
||||
import dev.usbharu.hideout.core.domain.model.support.acct.Acct
|
||||
import dev.usbharu.hideout.core.domain.model.support.page.Page
|
||||
import dev.usbharu.hideout.core.domain.model.support.principal.Anonymous
|
||||
import dev.usbharu.hideout.core.domain.model.support.principal.LocalUser
|
||||
import dev.usbharu.hideout.core.infrastructure.springframework.SpringSecurityFormLoginPrincipalContextHolder
|
||||
import org.springframework.stereotype.Controller
|
||||
import org.springframework.ui.Model
|
||||
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.RequestParam
|
||||
|
||||
@Controller
|
||||
@@ -28,11 +20,7 @@ class UserController(
|
||||
private val getLocalInstanceApplicationService: GetLocalInstanceApplicationService,
|
||||
private val getUserDetailApplicationService: GetActorDetailApplicationService,
|
||||
private val springSecurityFormLoginPrincipalContextHolder: SpringSecurityFormLoginPrincipalContextHolder,
|
||||
private val getUserTimelineApplicationService: GetUserTimelineApplicationService,
|
||||
private val userFollowRequestApplicationService: UserFollowRequestApplicationService,
|
||||
private val getActorDetailApplicationService: GetActorDetailApplicationService,
|
||||
private val userUnfollowApplicationService: UserUnfollowApplicationService,
|
||||
private val userGetRelationshipApplicationService: GetRelationshipApplicationService
|
||||
private val getUserTimelineApplicationService: GetUserTimelineApplicationService
|
||||
) {
|
||||
@GetMapping("/users/{name}")
|
||||
suspend fun userById(
|
||||
@@ -50,14 +38,6 @@ class UserController(
|
||||
"user",
|
||||
actorDetail
|
||||
)
|
||||
val relationship =
|
||||
if (principal is LocalUser) {
|
||||
userGetRelationshipApplicationService.execute(GetRelationship(actorDetail.id), principal)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
model.addAttribute("relationship", relationship)
|
||||
model.addAttribute(
|
||||
"userTimeline",
|
||||
getUserTimelineApplicationService.execute(
|
||||
@@ -70,24 +50,4 @@ class UserController(
|
||||
)
|
||||
return "userById"
|
||||
}
|
||||
|
||||
@PostMapping("/users/{name}/follow")
|
||||
suspend fun follow(@PathVariable name: String): String {
|
||||
val principal = springSecurityFormLoginPrincipalContextHolder.getPrincipal()
|
||||
|
||||
val actorDetail = getActorDetailApplicationService.execute(GetActorDetail(Acct.of(name), null), principal)
|
||||
userFollowRequestApplicationService.execute(FollowRequest((actorDetail.id)), principal)
|
||||
|
||||
return "redirect:/users/$name"
|
||||
}
|
||||
|
||||
@PostMapping("/users/{name}/unfollow")
|
||||
suspend fun unfollow(@PathVariable name: String): String {
|
||||
val principal = springSecurityFormLoginPrincipalContextHolder.getPrincipal()
|
||||
|
||||
val actorDetail = getActorDetailApplicationService.execute(GetActorDetail(Acct.of(name), null), principal)
|
||||
userUnfollowApplicationService.execute(Unfollow((actorDetail.id)), principal)
|
||||
|
||||
return "redirect:/users/$name"
|
||||
}
|
||||
}
|
||||
|
||||
-9
@@ -1,9 +0,0 @@
|
||||
package dev.usbharu.hideout.core.query.reactions
|
||||
|
||||
import dev.usbharu.hideout.core.application.model.Reactions
|
||||
import dev.usbharu.hideout.core.domain.model.post.PostId
|
||||
|
||||
interface ReactionsQueryService {
|
||||
suspend fun findAllByPostId(postId: PostId): List<Reactions>
|
||||
suspend fun findAllByPostIdIn(postIds: List<PostId>): List<Reactions>
|
||||
}
|
||||
@@ -4,8 +4,6 @@ hideout:
|
||||
private: true
|
||||
|
||||
spring:
|
||||
application:
|
||||
name: hideout
|
||||
data:
|
||||
mongodb:
|
||||
auto-index-creation: true
|
||||
|
||||
@@ -318,17 +318,4 @@ create table if not exists filter_keywords
|
||||
keyword varchar(1000) not null,
|
||||
mode varchar(100) not null,
|
||||
constraint fk_filter_keywords_filter_id__id foreign key (filter_id) references filters (id) on delete cascade on update cascade
|
||||
);
|
||||
|
||||
create table if not exists reactions
|
||||
(
|
||||
id bigint primary key,
|
||||
post_id bigint not null,
|
||||
actor_id bigint not null,
|
||||
custom_emoji_id bigint null,
|
||||
unicode_emoji varchar(100) not null,
|
||||
created_at timestamp not null,
|
||||
constraint fk_reactions_post_id__id foreign key (post_id) references posts (id) on delete cascade on update cascade,
|
||||
constraint fk_reactions_actor_id__id foreign key (actor_id) references actors (id) on delete cascade on update cascade,
|
||||
unique (post_id, actor_id, created_at, unicode_emoji)
|
||||
);
|
||||
)
|
||||
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Configuration status="WARN">
|
||||
<Appenders>
|
||||
<Console name="Console" target="SYSTEM_OUT">
|
||||
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%.15t] %highlight{%-5level} %logger{36} - %msg%n"/>
|
||||
</Console>
|
||||
</Appenders>
|
||||
<Loggers>
|
||||
<Root level="INFO">
|
||||
<AppenderRef ref="Console"/>
|
||||
</Root>
|
||||
<Logger name="dev.usbharu.owl.broker.service.QueuedTaskAssignerImpl" level="TRACE"/>
|
||||
<Logger name="org.mongodb.driver.cluster" level="INFO"/>
|
||||
<Logger name="org.apache.tomcat.util.net.NioEndpoint" level="INFO"/>
|
||||
<!-- <Logger name="Exposed" level="DEBUG"/>-->
|
||||
<Logger name="sun.rmi" level="INFO"/>
|
||||
<Logger name="javax.management.remote.rmi" level="INFO"/>
|
||||
</Loggers>
|
||||
</Configuration>
|
||||
@@ -1,15 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<property name="LOG_FILE" value="logs/logFile.log"/>
|
||||
<property name="CONSOLE_LOG_THRESHOLD" value="${CONSOLE_LOG_THRESHOLD:-INFO}"/>
|
||||
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
|
||||
<include resource="org/springframework/boot/logging/logback/console-appender.xml"/>
|
||||
<include resource="org/springframework/boot/logging/logback/file-appender.xml"/>
|
||||
<include resource="co/elastic/logging/logback/boot/ecs-console-appender.xml"/>
|
||||
<include resource="co/elastic/logging/logback/boot/ecs-file-appender.xml"/>
|
||||
<root level="TRACE">
|
||||
<appender-ref ref="CONSOLE"/>
|
||||
<appender-ref ref="ECS_JSON_FILE"/>
|
||||
<appender-ref ref="FILE"/>
|
||||
</root>
|
||||
</configuration>
|
||||
@@ -0,0 +1,35 @@
|
||||
<configuration>
|
||||
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>logFile.log</file>
|
||||
<encoder>
|
||||
<charset>UTF-8</charset>
|
||||
<pattern>%d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level [%X{x-request-id}] %logger{36} - %msg%n</pattern>
|
||||
</encoder>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<!-- daily rollover -->
|
||||
<fileNamePattern>logFile.%d{yyyy-MM-dd_HH}.log</fileNamePattern>
|
||||
|
||||
<!-- keep 30 days worth of history -->
|
||||
<maxHistory>30</maxHistory>
|
||||
</rollingPolicy>
|
||||
</appender>
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level [%X{x-request-id},%X{x-job-id}] %logger{36} -
|
||||
%msg%n
|
||||
</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
<root level="DEBUG">
|
||||
<appender-ref ref="STDOUT"/>
|
||||
<appender-ref ref="FILE"/>
|
||||
</root>
|
||||
<logger name="org.eclipse.jetty" level="INFO"/>
|
||||
<logger name="io.netty" level="INFO"/>
|
||||
<logger name="kjob.core.internal.scheduler.JobServiceImpl" level="INFO"/>
|
||||
<logger name="Exposed" level="DEBUG"/>
|
||||
<logger name="io.ktor.server.plugins.contentnegotiation" level="INFO"/>
|
||||
<logger name="org.springframework.web.filter.CommonsRequestLoggingFilter" level="DEBUG"/>
|
||||
<logger name="org.mongodb.driver.protocol.command" level="INFO"/>
|
||||
<logger name="dev.usbharu" level="TRACE"/>
|
||||
</configuration>
|
||||
@@ -44,27 +44,10 @@
|
||||
|
||||
<div class="post-controller" th:fragment="single-post-controller(post)">
|
||||
<!--/*@thymesVar id="post" type="dev.usbharu.hideout.core.application.post.PostDetail"*/-->
|
||||
<th:block th:if="${post.favourited}">
|
||||
<form method="post" th:action="@{/users/a/posts/{id}/unfavourite(id=${post.id})}">
|
||||
<a th:href="${'/publish?reply_to=' + post.id}">Reply</a>
|
||||
<input type="submit" value="[❤]">
|
||||
<a th:href="${post.apId}">
|
||||
<time th:datetime="${post.createdAt}"
|
||||
th:text="${#temporals.format(post.createdAt, 'yyyy-MM-dd HH:mm')}"></time>
|
||||
</a>
|
||||
</form>
|
||||
</th:block>
|
||||
<th:block th:unless="${post.favourited}">
|
||||
<form method="post" th:action="@{/users/a/posts/{id}/favourite(id=${post.id})}">
|
||||
<a th:href="${'/publish?reply_to=' + post.id}">Reply</a>
|
||||
<input type="submit" value="❤">
|
||||
<a th:href="${post.apId}">
|
||||
<time th:datetime="${post.createdAt}"
|
||||
th:text="${#temporals.format(post.createdAt, 'yyyy-MM-dd HH:mm')}"></time>
|
||||
</a>
|
||||
</form>
|
||||
</th:block>
|
||||
|
||||
<a th:href="${'/publish?reply_to=' + post.id}">Reply</a>
|
||||
<a th:href="${post.apId}">
|
||||
<time th:datetime="${post.createdAt}" th:text="${#temporals.format(post.createdAt, 'yyyy-MM-dd HH:mm')}"></time>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
@@ -19,17 +19,6 @@
|
||||
<h2 th:text="${user.screenName}"></h2>
|
||||
</th:block>
|
||||
<p th:text="'@'+${user.name} + '@' + ${user.host}"></p>
|
||||
<th:block th:if="${relationship != null}">
|
||||
<form method="post" th:action="@{/users/{name}/unfollow(name=${user.name+'@'+user.host})}"
|
||||
th:if="${relationship.following}">
|
||||
<input type="submit" value="Unfollow">
|
||||
</form>
|
||||
<form method="post" th:action="@{/users/{name}/follow(name=${user.name+'@'+user.host})}"
|
||||
th:unless="${relationship.following}">
|
||||
<input type="submit" value="Follow">
|
||||
</form>
|
||||
</th:block>
|
||||
|
||||
</div>
|
||||
<div>
|
||||
<p th:text="${user.description}"></p>
|
||||
|
||||
+160
@@ -0,0 +1,160 @@
|
||||
package dev.usbharu.hideout.core.application.actor
|
||||
|
||||
import dev.usbharu.hideout.core.config.ApplicationConfig
|
||||
import dev.usbharu.hideout.core.domain.model.actor.ActorId
|
||||
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
|
||||
import dev.usbharu.hideout.core.domain.model.actor.TestActorFactory
|
||||
import dev.usbharu.hideout.core.domain.model.media.*
|
||||
import dev.usbharu.hideout.core.domain.model.support.acct.Acct
|
||||
import dev.usbharu.hideout.core.domain.model.support.principal.Anonymous
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.assertThrows
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
import org.mockito.InjectMocks
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Spy
|
||||
import org.mockito.junit.jupiter.MockitoExtension
|
||||
import org.mockito.kotlin.*
|
||||
import utils.TestTransaction
|
||||
import java.net.URI
|
||||
|
||||
@ExtendWith(MockitoExtension::class)
|
||||
class GetActorDetailApplicationServiceTest {
|
||||
|
||||
@InjectMocks
|
||||
lateinit var service: GetActorDetailApplicationService
|
||||
|
||||
@Mock
|
||||
lateinit var actorRepository: ActorRepository
|
||||
|
||||
@Mock
|
||||
lateinit var mediaRepository: MediaRepository
|
||||
|
||||
@Spy
|
||||
val applicationConfig = ApplicationConfig(URI.create("http://localhost:8081").toURL())
|
||||
|
||||
@Spy
|
||||
val transaction = TestTransaction
|
||||
|
||||
@Test
|
||||
fun idとname両方nullならエラー() = runTest {
|
||||
assertThrows<IllegalArgumentException> {
|
||||
service.execute(GetActorDetail(null, null), Anonymous)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun idがnullじゃない場合idから取得() = runTest {
|
||||
val actor = TestActorFactory.create(id = 1)
|
||||
whenever(actorRepository.findById(ActorId(1))).doReturn(actor)
|
||||
|
||||
val actual = service.execute(GetActorDetail(null, 1), Anonymous)
|
||||
|
||||
assertEquals(actual, ActorDetail.of(actor, null, null))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun idが存在しないとエラー() = runTest {
|
||||
assertThrows<IllegalArgumentException> {
|
||||
service.execute(GetActorDetail(null, 2), Anonymous)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun idがnullでacctがnullじゃない場合acctから取得() = runTest {
|
||||
val actor = TestActorFactory.create(actorName = "test", domain = "example.com")
|
||||
whenever(actorRepository.findByNameAndDomain("test", "example.com")).thenReturn(actor)
|
||||
|
||||
val actual = service.execute(GetActorDetail(Acct("test", "example.com"), null), Anonymous)
|
||||
|
||||
assertEquals(actual, ActorDetail.of(actor, null, null))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun acctのhostが空ならローカルのhostが使われる() = runTest {
|
||||
val actor = TestActorFactory.create(actorName = "test", domain = "localhost")
|
||||
whenever(actorRepository.findByNameAndDomain("test", "localhost")).thenReturn(actor)
|
||||
|
||||
val actual = service.execute(GetActorDetail(Acct("test", ""), null), Anonymous)
|
||||
|
||||
assertEquals(actual, ActorDetail.of(actor, null, null))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun acctが存在しないとエラー() = runTest {
|
||||
assertThrows<IllegalArgumentException> {
|
||||
service.execute(GetActorDetail(Acct("test", "example.com"), null), Anonymous)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun idとacctがnullじゃない場合idが優先される() = runTest {
|
||||
val actor = TestActorFactory.create(id = 1)
|
||||
whenever(actorRepository.findById(ActorId(1))).doReturn(actor)
|
||||
|
||||
val actual = service.execute(GetActorDetail(null, 1), Anonymous)
|
||||
|
||||
assertEquals(actual, ActorDetail.of(actor, null, null))
|
||||
verify(actorRepository, never()).findByNameAndDomain(any(), any())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun iconがnullじゃない時取得する() = runTest {
|
||||
val actor = TestActorFactory.create(id = 1, icon = 1)
|
||||
whenever(actorRepository.findById(ActorId(1))).doReturn(actor)
|
||||
whenever(mediaRepository.findById(MediaId(1))).doReturn(
|
||||
Media(
|
||||
id = MediaId(1),
|
||||
name = MediaName(""),
|
||||
url = URI.create("http://example.com"),
|
||||
remoteUrl = null,
|
||||
thumbnailUrl = null,
|
||||
type = FileType.Image,
|
||||
mimeType = MimeType("image", "jpeg", FileType.Image),
|
||||
blurHash = null,
|
||||
description = null,
|
||||
actorId = ActorId(1)
|
||||
)
|
||||
)
|
||||
|
||||
val actual = service.execute(GetActorDetail(null, 1), Anonymous)
|
||||
|
||||
assertEquals(actual, ActorDetail.of(actor, URI.create("http://example.com"), null))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun bannerがnullじゃない時取得する() = runTest {
|
||||
val actor = TestActorFactory.create(id = 1, banner = 1)
|
||||
whenever(actorRepository.findById(ActorId(1))).doReturn(actor)
|
||||
whenever(mediaRepository.findById(MediaId(1))).doReturn(
|
||||
Media(
|
||||
id = MediaId(1),
|
||||
name = MediaName(""),
|
||||
url = URI.create("http://example.com"),
|
||||
remoteUrl = null,
|
||||
thumbnailUrl = null,
|
||||
type = FileType.Image,
|
||||
mimeType = MimeType("image", "jpeg", FileType.Image),
|
||||
blurHash = null,
|
||||
description = null,
|
||||
actorId = ActorId(1)
|
||||
)
|
||||
)
|
||||
|
||||
val actual = service.execute(GetActorDetail(null, 1), Anonymous)
|
||||
|
||||
assertEquals(actual, ActorDetail.of(actor, null, URI.create("http://example.com")))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun iconとbannerが見つからなかった場合null() = runTest {
|
||||
val actor = TestActorFactory.create(id = 1, icon = 1, banner = 1)
|
||||
whenever(actorRepository.findById(ActorId(1))).doReturn(actor)
|
||||
|
||||
val actual = service.execute(GetActorDetail(null, 1), Anonymous)
|
||||
|
||||
assertEquals(actual, ActorDetail.of(actor, null, null))
|
||||
}
|
||||
}
|
||||
+7
-5
@@ -1,7 +1,8 @@
|
||||
package dev.usbharu.hideout.core.domain.model.actor
|
||||
|
||||
import dev.usbharu.hideout.core.domain.model.emoji.CustomEmojiId
|
||||
import dev.usbharu.hideout.core.domain.model.emoji.EmojiId
|
||||
import dev.usbharu.hideout.core.domain.model.instance.InstanceId
|
||||
import dev.usbharu.hideout.core.domain.model.media.MediaId
|
||||
import dev.usbharu.hideout.core.domain.model.support.domain.Domain
|
||||
import dev.usbharu.hideout.core.infrastructure.other.TwitterSnowflakeIdGenerateService
|
||||
import kotlinx.coroutines.runBlocking
|
||||
@@ -35,9 +36,10 @@ object TestActorFactory {
|
||||
suspend: Boolean = false,
|
||||
alsoKnownAs: Set<ActorId> = emptySet(),
|
||||
moveTo: Long? = null,
|
||||
emojiIds: Set<CustomEmojiId> = emptySet(),
|
||||
emojiIds: Set<EmojiId> = emptySet(),
|
||||
deleted: Boolean = false,
|
||||
roles: Set<Role> = emptySet(),
|
||||
icon: Long? = null,
|
||||
banner: Long? = null
|
||||
): Actor {
|
||||
return runBlocking {
|
||||
Actor(
|
||||
@@ -66,8 +68,8 @@ object TestActorFactory {
|
||||
moveTo = moveTo?.let { ActorId(it) },
|
||||
emojiIds = emojiIds,
|
||||
deleted = deleted,
|
||||
icon = null,
|
||||
banner = null,
|
||||
icon = icon?.let { MediaId(it) },
|
||||
banner = banner?.let { MediaId(it) },
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
+3
-3
@@ -3,18 +3,18 @@ package dev.usbharu.hideout.core.domain.model.emoji
|
||||
import org.junit.jupiter.api.Assertions.assertDoesNotThrow
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
class CustomEmojiIdTest {
|
||||
class EmojiIdTest {
|
||||
@Test
|
||||
fun emojiIdは0以上である必要がある() {
|
||||
org.junit.jupiter.api.assertThrows<IllegalArgumentException> {
|
||||
CustomEmojiId(-1)
|
||||
EmojiId(-1)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun emojiIdは0以上なら設定できる() {
|
||||
assertDoesNotThrow {
|
||||
CustomEmojiId(1)
|
||||
EmojiId(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import dev.usbharu.hideout.core.domain.event.post.PostEvent
|
||||
import dev.usbharu.hideout.core.domain.model.actor.ActorId
|
||||
import dev.usbharu.hideout.core.domain.model.actor.ActorPublicKey
|
||||
import dev.usbharu.hideout.core.domain.model.actor.TestActorFactory
|
||||
import dev.usbharu.hideout.core.domain.model.emoji.CustomEmojiId
|
||||
import dev.usbharu.hideout.core.domain.model.emoji.EmojiId
|
||||
import dev.usbharu.hideout.core.domain.model.media.MediaId
|
||||
import org.junit.jupiter.api.Assertions.assertTrue
|
||||
import org.junit.jupiter.api.Test
|
||||
@@ -447,7 +447,7 @@ class PostTest {
|
||||
@Test
|
||||
fun `emojiIds hideがtrueの時empty`() {
|
||||
val actor = TestActorFactory.create()
|
||||
val emojiIds = listOf(CustomEmojiId(1), CustomEmojiId(2))
|
||||
val emojiIds = listOf(EmojiId(1), EmojiId(2))
|
||||
val post = Post.create(
|
||||
id = PostId(1),
|
||||
actorId = actor.id,
|
||||
@@ -473,7 +473,7 @@ class PostTest {
|
||||
@Test
|
||||
fun `emojiIds hideがfalseの時中身が返される`() {
|
||||
val actor = TestActorFactory.create()
|
||||
val emojiIds = listOf(CustomEmojiId(1), CustomEmojiId(2))
|
||||
val emojiIds = listOf(EmojiId(1), EmojiId(2))
|
||||
val post = Post.create(
|
||||
id = PostId(1),
|
||||
actorId = actor.id,
|
||||
@@ -500,7 +500,7 @@ class PostTest {
|
||||
val post = TestPostFactory.create()
|
||||
val mediaIds = listOf<MediaId>(MediaId(1))
|
||||
val visibleActors = setOf<ActorId>((ActorId(2)))
|
||||
val emojis = listOf<CustomEmojiId>(CustomEmojiId(3))
|
||||
val emojis = listOf<EmojiId>(EmojiId(3))
|
||||
val reconstructWith = post.reconstructWith(mediaIds, emojis, visibleActors)
|
||||
|
||||
assertEquals(mediaIds, reconstructWith.mediaIds)
|
||||
@@ -511,7 +511,7 @@ class PostTest {
|
||||
@Test
|
||||
fun `mediaIds hideがtrueの時emptyが返される`() {
|
||||
val actor = TestActorFactory.create()
|
||||
val emojiIds = listOf(CustomEmojiId(1), CustomEmojiId(2))
|
||||
val emojiIds = listOf(EmojiId(1), EmojiId(2))
|
||||
val mediaIds = listOf(MediaId(1))
|
||||
val post = Post.create(
|
||||
id = PostId(1),
|
||||
@@ -538,7 +538,7 @@ class PostTest {
|
||||
@Test
|
||||
fun `mediaIds hideがfalseの時中身が返される`() {
|
||||
val actor = TestActorFactory.create()
|
||||
val emojiIds = listOf(CustomEmojiId(1), CustomEmojiId(2))
|
||||
val emojiIds = listOf(EmojiId(1), EmojiId(2))
|
||||
val mediaIds = listOf(MediaId(2))
|
||||
val post = Post.create(
|
||||
id = PostId(1),
|
||||
@@ -603,7 +603,7 @@ class PostTest {
|
||||
fun `restore 指定された引数で再構成されCHECKUPDATEイベントが発生する`() {
|
||||
val post = TestPostFactory.create(deleted = true)
|
||||
|
||||
val postContent = PostContent("aiueo", "aiueo", listOf(CustomEmojiId(1)))
|
||||
val postContent = PostContent("aiueo", "aiueo", listOf(EmojiId(1)))
|
||||
val overview = PostOverview("overview")
|
||||
val mediaIds = listOf(MediaId(1))
|
||||
post.restore(
|
||||
@@ -622,7 +622,7 @@ class PostTest {
|
||||
fun deletedがfalseの時失敗する() {
|
||||
val post = TestPostFactory.create(deleted = false)
|
||||
|
||||
val postContent = PostContent("aiueo", "aiueo", listOf(CustomEmojiId(1)))
|
||||
val postContent = PostContent("aiueo", "aiueo", listOf(EmojiId(1)))
|
||||
val overview = PostOverview("overview")
|
||||
val mediaIds = listOf(MediaId(1))
|
||||
assertThrows<IllegalArgumentException> {
|
||||
|
||||
-16
@@ -1,16 +0,0 @@
|
||||
package dev.usbharu.hideout.core.infrastructure.emojikt
|
||||
|
||||
import org.junit.jupiter.api.Assertions.assertTrue
|
||||
import org.junit.jupiter.params.ParameterizedTest
|
||||
import org.junit.jupiter.params.provider.ValueSource
|
||||
|
||||
class EmojiKtUnicodeEmojiServiceTest {
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = ["❤", "👱", "☠️", "⁉️"])
|
||||
fun 絵文字の判定ができる(s: String) {
|
||||
assertTrue(EmojiKtUnicodeEmojiService().isUnicodeEmoji(s))
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
-4
@@ -19,7 +19,6 @@ import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailRepository
|
||||
import dev.usbharu.hideout.core.domain.service.filter.FilterDomainService
|
||||
import dev.usbharu.hideout.core.domain.service.post.IPostReadAccessControl
|
||||
import dev.usbharu.hideout.core.infrastructure.other.TwitterSnowflakeIdGenerateService
|
||||
import dev.usbharu.hideout.core.query.reactions.ReactionsQueryService
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.jupiter.api.Test
|
||||
@@ -65,9 +64,6 @@ class DefaultTimelineStoreTest {
|
||||
@Mock
|
||||
lateinit var iPostReadAccessControl: IPostReadAccessControl
|
||||
|
||||
@Mock
|
||||
lateinit var reactionsQueryService: ReactionsQueryService
|
||||
|
||||
@Spy
|
||||
val defaultTimelineStoreConfig = DefaultTimelineStoreConfig(500)
|
||||
|
||||
|
||||
@@ -41,12 +41,19 @@ repositories {
|
||||
}
|
||||
}
|
||||
|
||||
configurations {
|
||||
all {
|
||||
exclude("org.springframework.boot", "spring-boot-starter-logging")
|
||||
exclude("ch.qos.logback", "logback-classic")
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
detektPlugins(libs.detekt.formatting)
|
||||
implementation("org.springframework.boot:spring-boot-starter-web")
|
||||
implementation("org.springframework.boot:spring-boot-starter-security")
|
||||
implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310")
|
||||
implementation("org.springframework.boot:spring-boot-starter-log4j2")
|
||||
|
||||
implementation("dev.usbharu:hideout-core:0.0.1")
|
||||
|
||||
|
||||
+1
-21
@@ -18,10 +18,6 @@ package dev.usbharu.hideout.mastodon.interfaces.api
|
||||
|
||||
import dev.usbharu.hideout.core.application.post.RegisterLocalPost
|
||||
import dev.usbharu.hideout.core.application.post.RegisterLocalPostApplicationService
|
||||
import dev.usbharu.hideout.core.application.reaction.CreateReaction
|
||||
import dev.usbharu.hideout.core.application.reaction.RemoveReaction
|
||||
import dev.usbharu.hideout.core.application.reaction.UserCreateReactionApplicationService
|
||||
import dev.usbharu.hideout.core.application.reaction.UserRemoveReactionApplicationService
|
||||
import dev.usbharu.hideout.core.domain.model.post.Visibility
|
||||
import dev.usbharu.hideout.core.infrastructure.springframework.oauth2.SpringSecurityOauth2PrincipalContextHolder
|
||||
import dev.usbharu.hideout.mastodon.application.status.GetStatus
|
||||
@@ -36,9 +32,7 @@ import org.springframework.stereotype.Controller
|
||||
class SpringStatusApi(
|
||||
private val registerLocalPostApplicationService: RegisterLocalPostApplicationService,
|
||||
private val getStatusApplicationService: GetStatusApplicationService,
|
||||
private val principalContextHolder: SpringSecurityOauth2PrincipalContextHolder,
|
||||
private val userCreateReactionApplicationService: UserCreateReactionApplicationService,
|
||||
private val userRemoveReactionApplicationService: UserRemoveReactionApplicationService
|
||||
private val principalContextHolder: SpringSecurityOauth2PrincipalContextHolder
|
||||
) : StatusApi {
|
||||
override suspend fun apiV1StatusesIdEmojiReactionsEmojiDelete(id: String, emoji: String): ResponseEntity<Status> =
|
||||
super.apiV1StatusesIdEmojiReactionsEmojiDelete(id, emoji)
|
||||
@@ -55,20 +49,6 @@ class SpringStatusApi(
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun apiV1StatusesIdFavouritePost(id: String): ResponseEntity<Status> {
|
||||
val principal = principalContextHolder.getPrincipal()
|
||||
|
||||
userCreateReactionApplicationService.execute(CreateReaction(postId = id.toLong(), null, "❤"), principal)
|
||||
return ResponseEntity.ok(getStatusApplicationService.execute(GetStatus(id), principal))
|
||||
}
|
||||
|
||||
override suspend fun apiV1StatusesIdUnfavouritePost(id: String): ResponseEntity<Status> {
|
||||
val principal = principalContextHolder.getPrincipal()
|
||||
|
||||
userRemoveReactionApplicationService.execute(RemoveReaction(postId = id.toLong(), null, "❤"), principal)
|
||||
return ResponseEntity.ok(getStatusApplicationService.execute(GetStatus(id), principal))
|
||||
}
|
||||
|
||||
override suspend fun apiV1StatusesPost(statusesRequest: StatusesRequest): ResponseEntity<Status> {
|
||||
val principal = principalContextHolder.getPrincipal()
|
||||
val execute = registerLocalPostApplicationService.execute(
|
||||
|
||||
@@ -177,48 +177,6 @@ paths:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Status"
|
||||
|
||||
/api/v1/statuses/{id}/favourite:
|
||||
post:
|
||||
tags:
|
||||
- status
|
||||
security:
|
||||
- OAuth2:
|
||||
- "write:favourites"
|
||||
parameters:
|
||||
- in: path
|
||||
name: id
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
200:
|
||||
description: 成功
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Status"
|
||||
|
||||
/api/v1/statuses/{id}/unfavourite:
|
||||
post:
|
||||
tags:
|
||||
- status
|
||||
security:
|
||||
- OAuth2:
|
||||
- "write:favourites"
|
||||
parameters:
|
||||
- in: path
|
||||
name: id
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
200:
|
||||
description: 成功
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Status"
|
||||
|
||||
/api/v1/statuses/{id}/emoji_reactions/{emoji}:
|
||||
put:
|
||||
tags:
|
||||
|
||||
+4
-6
@@ -4,7 +4,7 @@ kotlin = "2.0.20"
|
||||
ktor = "2.3.12"
|
||||
exposed = "0.54.0"
|
||||
javacv-ffmpeg = "6.1.1-1.5.10"
|
||||
detekt = "1.23.7"
|
||||
detekt = "1.23.6"
|
||||
coroutines = "1.8.1"
|
||||
swagger = "2.2.23"
|
||||
tika = "2.9.2"
|
||||
@@ -65,7 +65,7 @@ jackson-module-kotlin = { module = "com.fasterxml.jackson.module:jackson-module-
|
||||
|
||||
blurhash = { module = "io.trbl:blurhash", version = "1.0.0" }
|
||||
|
||||
aws-s3 = { module = "software.amazon.awssdk:s3", version = "2.27.21" }
|
||||
aws-s3 = { module = "software.amazon.awssdk:s3", version = "2.27.20" }
|
||||
|
||||
jsoup = { module = "org.jsoup:jsoup", version = "1.18.1" }
|
||||
|
||||
@@ -96,16 +96,14 @@ protoc = { module = "com.google.protobuf:protoc", version.ref = "protobuf" }
|
||||
koin-bom = { module = "io.insert-koin:koin-bom", version = "3.5.6" }
|
||||
koin-core = { module = "io.insert-koin:koin-core" }
|
||||
|
||||
log4j2-slf4j = { module = "org.apache.logging.log4j:log4j-slf4j2-impl", version = "2.24.0" }
|
||||
log4j2-slf4j = { module = "org.apache.logging.log4j:log4j-slf4j2-impl", version = "2.23.1" }
|
||||
|
||||
mongodb-kotlin-coroutine = { module = "org.mongodb:mongodb-driver-kotlin-coroutine", version = "5.1.4" }
|
||||
|
||||
mockito-kotlin = { module = "org.mockito.kotlin:mockito-kotlin", version = "5.4.0" }
|
||||
|
||||
http-signature = { module = "dev.usbharu:http-signature", version = "1.0.0" }
|
||||
emoji-kt = { module = "dev.usbharu:emoji-kt", version = "2.0.1" }
|
||||
|
||||
logback-ecs-encoder = { module = "co.elastic.logging:logback-ecs-encoder", version = "1.6.0" }
|
||||
emoji-kt = { module = "dev.usbharu:emoji-kt", version = "2.0.0" }
|
||||
|
||||
[bundles]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user