Merge pull request #561 from usbharu/detekt

Detektをhideout-mastodonにも適用するように
This commit is contained in:
usbharu 2024-08-24 00:32:04 +09:00 committed by GitHub
commit f9c10eeb7a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
64 changed files with 382 additions and 333 deletions

View File

@ -46,7 +46,7 @@ jobs:
gradle-home-cache-cleanup: true gradle-home-cache-cleanup: true
- name: Build - name: Build
run: ./hideout-core/gradlew :hideout-core:classes --no-daemon run: ./gradlew classes --no-daemon
unit-test: unit-test:
name: Unit Test name: Unit Test
@ -115,7 +115,7 @@ jobs:
gradle-home-cache-cleanup: true gradle-home-cache-cleanup: true
- name: Build with Gradle - name: Build with Gradle
run: ./hideout-core/gradlew :hideout-core:detektMain run: ./gradlew :hideout-core:detektMain :hideout-mastodon:detektMain
- name: Auto Commit - name: Auto Commit
if: ${{ always() }} if: ${{ always() }}

View File

@ -0,0 +1,3 @@
package dev.usbharu.hideout.core.application.actor
data class SuspendLocalActor(val actorId: Long)

View File

@ -16,22 +16,29 @@
package dev.usbharu.hideout.core.application.actor 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.application.shared.Transaction
import dev.usbharu.hideout.core.domain.model.actor.ActorId 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.ActorRepository
import dev.usbharu.hideout.core.domain.model.support.principal.LocalUser
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service import org.springframework.stereotype.Service
@Service @Service
class SuspendLocalActorApplicationService( class SuspendLocalActorApplicationService(
private val transaction: Transaction, transaction: Transaction,
private val actorRepository: ActorRepository, private val actorRepository: ActorRepository,
) { ) : LocalUserAbstractApplicationService<SuspendLocalActor, Unit>(transaction, logger) {
suspend fun suspend(actorId: Long, executor: ActorId) {
transaction.transaction {
val id = ActorId(actorId)
val actor = actorRepository.findById(id)!! override suspend fun internalExecute(command: SuspendLocalActor, principal: LocalUser) {
actor.suspend = true 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)
} }
} }

View File

@ -0,0 +1,3 @@
package dev.usbharu.hideout.core.application.actor
data class UnsuspendLocalActor(val actorId: Long)

View File

@ -16,21 +16,29 @@
package dev.usbharu.hideout.core.application.actor 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.application.shared.Transaction
import dev.usbharu.hideout.core.domain.model.actor.ActorId 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.ActorRepository
import dev.usbharu.hideout.core.domain.model.support.principal.LocalUser
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service import org.springframework.stereotype.Service
@Service @Service
class UnsuspendLocalActorApplicationService( class UnsuspendLocalActorApplicationService(
private val transaction: Transaction, transaction: Transaction,
private val actorRepository: ActorRepository, private val actorRepository: ActorRepository,
) { ) : LocalUserAbstractApplicationService<UnsuspendLocalActor, Unit>(transaction, logger) {
suspend fun unsuspend(actorId: Long, executor: Long) {
transaction.transaction {
val findById = actorRepository.findById(ActorId(actorId))!!
findById.suspend = false 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)
} }
} }

View File

@ -20,5 +20,3 @@ class RegisterLocalUserSetHomeTimelineSubscriber(
} }
} }
} }
// todo userdetailにdomain event付けて createのイベントで反応させる タイムラインを新しく一つ作って userdetailのhometimelineに紐づけて自分自身をtimleine relationshipに入れる

View File

@ -5,7 +5,6 @@ import dev.usbharu.hideout.core.application.timeline.TimelineAddPostApplicationS
import dev.usbharu.hideout.core.domain.event.post.PostEvent import dev.usbharu.hideout.core.domain.event.post.PostEvent
import dev.usbharu.hideout.core.domain.event.post.PostEventBody import dev.usbharu.hideout.core.domain.event.post.PostEventBody
import dev.usbharu.hideout.core.domain.model.support.principal.Anonymous import dev.usbharu.hideout.core.domain.model.support.principal.Anonymous
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Component import org.springframework.stereotype.Component
@Component @Component
@ -18,8 +17,4 @@ class TimelinePostCreateSubscriber(
timelineAddPostApplicationService.execute(AddPost(it.body.getPostId()), Anonymous) timelineAddPostApplicationService.execute(AddPost(it.body.getPostId()), Anonymous)
} }
} }
companion object {
private val logger = LoggerFactory.getLogger(TimelinePostCreateSubscriber::class.java)
}
} }

View File

@ -1,5 +1,6 @@
package dev.usbharu.hideout.core.application.domainevent.subscribers package dev.usbharu.hideout.core.application.domainevent.subscribers
import dev.usbharu.hideout.core.application.exception.InternalServerException
import dev.usbharu.hideout.core.application.timeline.AddTimelineRelationship import dev.usbharu.hideout.core.application.timeline.AddTimelineRelationship
import dev.usbharu.hideout.core.application.timeline.UserAddTimelineRelationshipApplicationService 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.RelationshipEvent
@ -23,11 +24,14 @@ class TimelineRelationshipFollowSubscriber(
init { init {
domainEventSubscriber.subscribe<RelationshipEventBody>(RelationshipEvent.FOLLOW.eventName) { domainEventSubscriber.subscribe<RelationshipEventBody>(RelationshipEvent.FOLLOW.eventName) {
val relationship = it.body.getRelationship() val relationship = it.body.getRelationship()
val userDetail = userDetailRepository.findByActorId(relationship.actorId.id) ?: throw Exception() val userDetail = userDetailRepository.findByActorId(relationship.actorId.id)
?: throw InternalServerException("Userdetail ${relationship.actorId} not found by actorid.")
if (userDetail.homeTimelineId == null) { if (userDetail.homeTimelineId == null) {
logger.warn("Home timeline for ${relationship.actorId} is not found") logger.warn("Home timeline for ${relationship.actorId} is not found")
return@subscribe return@subscribe
} }
@Suppress("UnsafeCallOnNullableType")
userAddTimelineRelationshipApplicationService.execute( userAddTimelineRelationshipApplicationService.execute(
AddTimelineRelationship( AddTimelineRelationship(
TimelineRelationship( TimelineRelationship(

View File

@ -23,6 +23,7 @@ class GetLocalInstanceApplicationService(
override suspend fun internalExecute(command: Unit, principal: Principal): Instance { override suspend fun internalExecute(command: Unit, principal: Principal): Instance {
if (cachedInstance != null) { if (cachedInstance != null) {
@Suppress("UnsafeCallOnNullableType")
return cachedInstance!! return cachedInstance!!
} }
@ -32,6 +33,7 @@ class GetLocalInstanceApplicationService(
) )
cachedInstance = Instance.of(instance) cachedInstance = Instance.of(instance)
@Suppress("UnsafeCallOnNullableType")
return cachedInstance!! return cachedInstance!!
} }

View File

@ -17,14 +17,14 @@ data class ActorDetail(
companion object { companion object {
fun of(actor: Actor, iconMedia: Media?): ActorDetail { fun of(actor: Actor, iconMedia: Media?): ActorDetail {
return ActorDetail( return ActorDetail(
actor.id.id, actorId = actor.id.id,
actor.instance.instanceId, instanceId = actor.instance.instanceId,
actor.name.name, name = actor.name.name,
actor.domain.domain, domain = actor.domain.domain,
actor.screenName.screenName, screenName = actor.screenName.screenName,
actor.url, url = actor.url,
actor.locked, locked = actor.locked,
iconMedia?.url icon = iconMedia?.url
) )
} }
} }

View File

@ -16,6 +16,7 @@
package dev.usbharu.hideout.core.application.post package dev.usbharu.hideout.core.application.post
import dev.usbharu.hideout.core.application.exception.InternalServerException
import dev.usbharu.hideout.core.application.exception.PermissionDeniedException import dev.usbharu.hideout.core.application.exception.PermissionDeniedException
import dev.usbharu.hideout.core.application.shared.LocalUserAbstractApplicationService import dev.usbharu.hideout.core.application.shared.LocalUserAbstractApplicationService
import dev.usbharu.hideout.core.application.shared.Transaction import dev.usbharu.hideout.core.application.shared.Transaction
@ -34,11 +35,13 @@ class DeleteLocalPostApplicationService(
) : LocalUserAbstractApplicationService<DeleteLocalPost, Unit>(transaction, logger) { ) : LocalUserAbstractApplicationService<DeleteLocalPost, Unit>(transaction, logger) {
override suspend fun internalExecute(command: DeleteLocalPost, principal: LocalUser) { override suspend fun internalExecute(command: DeleteLocalPost, principal: LocalUser) {
val findById = postRepository.findById(PostId(command.postId))!! val findById = postRepository.findById(PostId(command.postId))
?: throw IllegalArgumentException("Post ${command.postId} not found.")
if (findById.actorId != principal.actorId) { if (findById.actorId != principal.actorId) {
throw PermissionDeniedException() throw PermissionDeniedException()
} }
val actor = actorRepository.findById(principal.actorId)!! val actor = actorRepository.findById(principal.actorId)
?: throw InternalServerException("Actor ${principal.actorId} not found.")
findById.delete(actor) findById.delete(actor)
postRepository.save(findById) postRepository.save(findById)
} }

View File

@ -39,13 +39,13 @@ class GetPostDetailApplicationService(
val mediaList = mediaRepository.findByIds(post.mediaIds) val mediaList = mediaRepository.findByIds(post.mediaIds)
return PostDetail.of( return PostDetail.of(
post, post = post,
actor, actor = actor,
iconMedia, iconMedia = iconMedia,
mediaList, mediaList = mediaList,
post.replyId?.let { fetchChild(it, actor, iconMedia, principal) }, reply = post.replyId?.let { fetchChild(it, actor, iconMedia, principal) },
post.repostId?.let { fetchChild(it, actor, iconMedia, principal) }, repost = post.repostId?.let { fetchChild(it, actor, iconMedia, principal) },
post.moveTo?.let { fetchChild(it, actor, iconMedia, principal) }, moveTo = post.moveTo?.let { fetchChild(it, actor, iconMedia, principal) },
) )
} }

View File

@ -26,6 +26,7 @@ data class PostDetail(
val moveTo: PostDetail? val moveTo: PostDetail?
) { ) {
companion object { companion object {
@Suppress("LongParameterList")
fun of( fun of(
post: Post, post: Post,
actor: Actor, actor: Actor,

View File

@ -41,7 +41,7 @@ class UserRejectFollowRequestApplicationService(
val targetId = ActorId(command.sourceActorId) val targetId = ActorId(command.sourceActorId)
val relationship = relationshipRepository.findByActorIdAndTargetId(targetId, actor.id) val relationship = relationshipRepository.findByActorIdAndTargetId(targetId, actor.id)
?: throw Exception("Follow request not found") ?: throw IllegalArgumentException("Follow request not found")
relationship.rejectFollowRequest() relationship.rejectFollowRequest()

View File

@ -35,10 +35,6 @@ class UserUnmuteApplicationService(
private val actorRepository: ActorRepository, private val actorRepository: ActorRepository,
) : ) :
LocalUserAbstractApplicationService<Unmute, Unit>(transaction, logger) { LocalUserAbstractApplicationService<Unmute, Unit>(transaction, logger) {
companion object {
private val logger = LoggerFactory.getLogger(UserBlockApplicationService::class.java)
}
override suspend fun internalExecute(command: Unmute, principal: LocalUser) { override suspend fun internalExecute(command: Unmute, principal: LocalUser) {
val actor = actorRepository.findById(principal.actorId) val actor = actorRepository.findById(principal.actorId)
?: throw InternalServerException("Actor ${principal.actorId} not found.") ?: throw InternalServerException("Actor ${principal.actorId} not found.")
@ -53,4 +49,8 @@ class UserUnmuteApplicationService(
relationshipRepository.save(relationship) relationshipRepository.save(relationship)
} }
companion object {
private val logger = LoggerFactory.getLogger(UserBlockApplicationService::class.java)
}
} }

View File

@ -35,7 +35,7 @@ abstract class AbstractApplicationService<T : Any, R>(
} catch (e: CancellationException) { } catch (e: CancellationException) {
logger.debug("Coroutine canceled", e) logger.debug("Coroutine canceled", e)
throw e throw e
} catch (e: Exception) { } catch (@Suppress("TooGenericExceptionCaught") e: Exception) {
logger.warn("Command execution error", e) logger.warn("Command execution error", e)
throw e throw e
} }

View File

@ -42,6 +42,7 @@ class ReadTimelineApplicationService(
val postDetailList = timeline.map { val postDetailList = timeline.map {
val reply = if (it.replyPost != null) { val reply = if (it.replyPost != null) {
@Suppress("UnsafeCallOnNullableType")
PostDetail.of( PostDetail.of(
it.replyPost, it.replyPost,
it.replyPostActor!!, it.replyPostActor!!,
@ -53,6 +54,7 @@ class ReadTimelineApplicationService(
} }
val repost = if (it.repostPost != null) { val repost = if (it.repostPost != null) {
@Suppress("UnsafeCallOnNullableType")
PostDetail.of( PostDetail.of(
it.repostPost, it.repostPost,
it.repostPostActor!!, it.repostPostActor!!,
@ -64,12 +66,12 @@ class ReadTimelineApplicationService(
} }
PostDetail.of( PostDetail.of(
it.post, post = it.post,
it.postActor, actor = it.postActor,
it.postActorIconMedia, iconMedia = it.postActorIconMedia,
it.postMedias, mediaList = it.postMedias,
reply, reply = reply,
repost repost = repost
) )
} }

View File

@ -34,7 +34,7 @@ class PostDomainEventFactory(private val post: Post, private val actor: Actor? =
class PostEventBody(post: PostId, actor: ActorId?) : DomainEventBody(mapOf("post" to post, "actor" to actor)) { class PostEventBody(post: PostId, actor: ActorId?) : DomainEventBody(mapOf("post" to post, "actor" to actor)) {
fun getPostId(): PostId = toMap()["post"] as PostId fun getPostId(): PostId = toMap()["post"] as PostId
fun getActorId(): ActorId? = toMap()["actor"] as ActorId? fun getActorId(): ActorId? = toMap()["actor"] as? ActorId
} }
enum class PostEvent(val eventName: String) { enum class PostEvent(val eventName: String) {

View File

@ -31,9 +31,7 @@ class RelationshipEventBody(
relationship: Relationship, relationship: Relationship,
override val principal: Principal override val principal: Principal
) : DomainEventBody(mapOf("relationship" to relationship), principal) { ) : DomainEventBody(mapOf("relationship" to relationship), principal) {
fun getRelationship(): Relationship { fun getRelationship(): Relationship = toMap()["relationship"] as Relationship
return toMap()["relationship"] as Relationship
}
} }
enum class RelationshipEvent(val eventName: String) { enum class RelationshipEvent(val eventName: String) {

View File

@ -11,9 +11,7 @@ class TimelineEventFactory(private val timeline: Timeline) {
} }
class TimelineEventBody(timelineId: TimelineId) : DomainEventBody(mapOf("timeline" to timelineId)) { class TimelineEventBody(timelineId: TimelineId) : DomainEventBody(mapOf("timeline" to timelineId)) {
fun getTimelineId(): TimelineId { fun getTimelineId(): TimelineId = toMap()["timeline"] as TimelineId
return toMap()["timeline"] as TimelineId
}
} }
enum class TimelineEvent(val eventName: String) { enum class TimelineEvent(val eventName: String) {

View File

@ -19,9 +19,7 @@ class UserDetailEventBody(userDetail: UserDetailId) : DomainEventBody(
"userDetail" to userDetail "userDetail" to userDetail
) )
) { ) {
fun getUserDetail(): UserDetailId { fun getUserDetail(): UserDetailId = toMap()["userDetail"] as UserDetailId
return toMap()["userDetail"] as UserDetailId
}
} }
enum class UserDetailEvent(val eventName: String) { enum class UserDetailEvent(val eventName: String) {

View File

@ -65,9 +65,7 @@ class Filter(
return id == other.id return id == other.id
} }
override fun hashCode(): Int { override fun hashCode(): Int = id.hashCode()
return id.hashCode()
}
companion object { companion object {
fun isAllow(user: UserDetail, action: Action, resource: Filter): Boolean { fun isAllow(user: UserDetail, action: Action, resource: Filter): Boolean {

View File

@ -19,6 +19,7 @@ package dev.usbharu.hideout.core.domain.model.media
import dev.usbharu.hideout.core.domain.model.actor.ActorId import dev.usbharu.hideout.core.domain.model.actor.ActorId
import java.net.URI import java.net.URI
@Suppress("LongParameterList")
class Media( class Media(
val id: MediaId, val id: MediaId,
val name: MediaName, val name: MediaName,
@ -47,9 +48,7 @@ class Media(
return id == other.id return id == other.id
} }
override fun hashCode(): Int { override fun hashCode(): Int = id.hashCode()
return id.hashCode()
}
override fun toString(): String { override fun toString(): String {
return "Media(" + return "Media(" +

View File

@ -201,7 +201,7 @@ class Post(
var moveTo = moveTo var moveTo = moveTo
private set private set
fun moveTo(moveTo: PostId, actor: Actor) { fun moveTo(moveTo: PostId) {
require(this.moveTo == null) require(this.moveTo == null)
this.moveTo = moveTo this.moveTo = moveTo
} }

View File

@ -27,6 +27,8 @@ interface PostRepository {
suspend fun findAllById(ids: List<PostId>): List<Post> suspend fun findAllById(ids: List<PostId>): List<Post>
suspend fun findByActorId(id: ActorId, page: Page? = null): PaginationList<Post, PostId> suspend fun findByActorId(id: ActorId, page: Page? = null): PaginationList<Post, PostId>
suspend fun delete(post: Post) suspend fun delete(post: Post)
@Suppress("FunctionMaxLength")
suspend fun findByActorIdAndVisibilityInList( suspend fun findByActorIdAndVisibilityInList(
actorId: ActorId, actorId: ActorId,
visibilityList: List<Visibility>, visibilityList: List<Visibility>,

View File

@ -18,6 +18,7 @@ package dev.usbharu.hideout.core.domain.model.relationship
import dev.usbharu.hideout.core.domain.model.actor.ActorId import dev.usbharu.hideout.core.domain.model.actor.ActorId
@Suppress("FunctionMaxLength")
interface RelationshipRepository { interface RelationshipRepository {
suspend fun save(relationship: Relationship): Relationship suspend fun save(relationship: Relationship): Relationship
suspend fun delete(relationship: Relationship) suspend fun delete(relationship: Relationship)

View File

@ -4,7 +4,5 @@ data class Acct(
val userpart: String, val userpart: String,
val host: String val host: String
) { ) {
override fun toString(): String { override fun toString(): String = "acct:$userpart@$host"
return "acct:$userpart@$host"
}
} }

View File

@ -32,6 +32,7 @@ data class TimelineObjectDetail(
val warnFilter: List<TimelineObjectWarnFilter> val warnFilter: List<TimelineObjectWarnFilter>
) { ) {
companion object { companion object {
@Suppress("LongParameterList")
fun of( fun of(
timelineObject: TimelineObject, timelineObject: TimelineObject,
timelineUserDetail: UserDetail, timelineUserDetail: UserDetail,

View File

@ -16,6 +16,9 @@ class Timeline(
var visibility = visibility var visibility = visibility
private set private set
var name = name
private set
fun setVisibility(visibility: TimelineVisibility, userDetail: UserDetail) { fun setVisibility(visibility: TimelineVisibility, userDetail: UserDetail) {
check(isSystem.not()) check(isSystem.not())
require(userDetailId == userDetail.id) require(userDetailId == userDetail.id)
@ -23,9 +26,6 @@ class Timeline(
addDomainEvent(TimelineEventFactory(this).createEvent(TimelineEvent.CHANGE_VISIBILITY)) addDomainEvent(TimelineEventFactory(this).createEvent(TimelineEvent.CHANGE_VISIBILITY))
} }
var name = name
private set
companion object { companion object {
fun create( fun create(
id: TimelineId, id: TimelineId,

View File

@ -13,6 +13,7 @@ import dev.usbharu.hideout.core.domain.model.timeline.TimelineId
import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailId import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailId
import java.time.Instant import java.time.Instant
@Suppress("LongParameterList")
class TimelineObject( class TimelineObject(
val id: TimelineObjectId, val id: TimelineObjectId,
val userDetailId: UserDetailId, val userDetailId: UserDetailId,
@ -59,7 +60,10 @@ class TimelineObject(
emojiIds = post.emojiIds.toList() emojiIds = post.emojiIds.toList()
lastUpdatedAt = Instant.now() lastUpdatedAt = Instant.now()
isPureRepost = isPureRepost =
post.repostId != null && post.replyId == null && post.text.isEmpty() && post.overview?.overview.isNullOrEmpty() post.repostId != null &&
post.replyId == null &&
post.text.isEmpty() &&
post.overview?.overview.isNullOrEmpty()
warnFilters = filterResults.map { TimelineObjectWarnFilter(it.filter.id, it.matchedKeyword) } warnFilters = filterResults.map { TimelineObjectWarnFilter(it.filter.id, it.matchedKeyword) }
} }
@ -102,6 +106,7 @@ class TimelineObject(
) )
} }
@Suppress("LongParameterList")
fun create( fun create(
timelineObjectId: TimelineObjectId, timelineObjectId: TimelineObjectId,
timeline: Timeline, timeline: Timeline,

View File

@ -44,6 +44,7 @@ class UserDetail(
override fun hashCode(): Int = id.hashCode() override fun hashCode(): Int = id.hashCode()
companion object { companion object {
@Suppress("LongParameterList")
fun create( fun create(
id: UserDetailId, id: UserDetailId,
actorId: ActorId, actorId: ActorId,

View File

@ -14,6 +14,9 @@ import org.springframework.stereotype.Repository
@Repository @Repository
class ExposedPrincipalQueryService : PrincipalQueryService, AbstractRepository() { class ExposedPrincipalQueryService : PrincipalQueryService, AbstractRepository() {
override val logger: Logger
get() = Companion.logger
override suspend fun findByUserDetailId(userDetailId: UserDetailId): PrincipalDTO { override suspend fun findByUserDetailId(userDetailId: UserDetailId): PrincipalDTO {
return query { return query {
UserDetails.leftJoin(Actors).selectAll().where { UserDetails.id eq userDetailId.id }.single() UserDetails.leftJoin(Actors).selectAll().where { UserDetails.id eq userDetailId.id }.single()
@ -28,9 +31,6 @@ class ExposedPrincipalQueryService : PrincipalQueryService, AbstractRepository()
} }
} }
override val logger: Logger
get() = Companion.logger
companion object { companion object {
private val logger: Logger = LoggerFactory.getLogger(ExposedPrincipalQueryService::class.java) private val logger: Logger = LoggerFactory.getLogger(ExposedPrincipalQueryService::class.java)
} }

View File

@ -152,8 +152,8 @@ class ExposedPostRepository(
this[PostsVisibleActors.actorId] = it.second this[PostsVisibleActors.actorId] = it.second
} }
onComplete { onComplete {
posts.forEach { posts.forEach { post: Post ->
update(it) update(post)
} }
} }
} }

View File

@ -15,6 +15,9 @@ class ExposedTimelineRepository(override val domainEventPublisher: DomainEventPu
TimelineRepository, TimelineRepository,
AbstractRepository(), AbstractRepository(),
DomainEventPublishableRepository<Timeline> { DomainEventPublishableRepository<Timeline> {
override val logger: Logger
get() = Companion.logger
override suspend fun save(timeline: Timeline): Timeline { override suspend fun save(timeline: Timeline): Timeline {
query { query {
Timelines.insert { Timelines.insert {
@ -58,9 +61,6 @@ class ExposedTimelineRepository(override val domainEventPublisher: DomainEventPu
companion object { companion object {
private val logger = LoggerFactory.getLogger(ExposedTimelineRepository::class.java.name) private val logger = LoggerFactory.getLogger(ExposedTimelineRepository::class.java.name)
} }
override val logger: Logger
get() = Companion.logger
} }
fun ResultRow.toTimeline(): Timeline { fun ResultRow.toTimeline(): Timeline {

View File

@ -109,12 +109,12 @@ class UserDetailRepositoryImpl(override val domainEventPublisher: DomainEventPub
} }
private fun userDetail(it: ResultRow) = UserDetail( private fun userDetail(it: ResultRow) = UserDetail(
UserDetailId(it[UserDetails.id]), id = UserDetailId(it[UserDetails.id]),
ActorId(it[UserDetails.actorId]), actorId = ActorId(it[UserDetails.actorId]),
UserDetailHashedPassword(it[UserDetails.password]), password = UserDetailHashedPassword(it[UserDetails.password]),
it[UserDetails.autoAcceptFolloweeFollowRequest], autoAcceptFolloweeFollowRequest = it[UserDetails.autoAcceptFolloweeFollowRequest],
it[UserDetails.lastMigration], lastMigration = it[UserDetails.lastMigration],
it[UserDetails.homeTimelineId]?.let { it1 -> TimelineId(it1) } homeTimelineId = it[UserDetails.homeTimelineId]?.let { it1 -> TimelineId(it1) }
) )
companion object { companion object {

View File

@ -1,5 +1,6 @@
package dev.usbharu.hideout.core.infrastructure.media.image package dev.usbharu.hideout.core.infrastructure.media.image
import dev.usbharu.hideout.core.application.exception.InternalServerException
import dev.usbharu.hideout.core.config.ImageIOImageConfig import dev.usbharu.hideout.core.config.ImageIOImageConfig
import dev.usbharu.hideout.core.domain.model.media.FileType import dev.usbharu.hideout.core.domain.model.media.FileType
import dev.usbharu.hideout.core.domain.model.media.MimeType import dev.usbharu.hideout.core.domain.model.media.MimeType
@ -59,7 +60,7 @@ class ImageIOImageProcessor(
tempFile.outputStream().use { tempFile.outputStream().use {
if (ImageIO.write(bufferedImage, imageIOImageConfig.format, it).not()) { if (ImageIO.write(bufferedImage, imageIOImageConfig.format, it).not()) {
logger.warn("Failed to save a temporary file. type: {} ,path: {}", imageIOImageConfig.format, tempFile) logger.warn("Failed to save a temporary file. type: {} ,path: {}", imageIOImageConfig.format, tempFile)
throw Exception("Failed to save a temporary file.") throw InternalServerException("Failed to save a temporary file.")
} }
} }

View File

@ -46,9 +46,8 @@ class MongoInternalTimelineObjectRepository(
return timelineObjectList return timelineObjectList
} }
override suspend fun findByPostId(postId: PostId): List<TimelineObject> { override suspend fun findByPostId(postId: PostId): List<TimelineObject> =
return springDataMongoTimelineObjectRepository.findByPostId(postId.id).map { it.toTimelineObject() }.toList() springDataMongoTimelineObjectRepository.findByPostId(postId.id).map { it.toTimelineObject() }.toList()
}
override suspend fun deleteByPostId(postId: PostId) { override suspend fun deleteByPostId(postId: PostId) {
springDataMongoTimelineObjectRepository.deleteByPostId(postId.id) springDataMongoTimelineObjectRepository.deleteByPostId(postId.id)
@ -139,48 +138,48 @@ data class SpringDataMongoTimelineObject(
fun toTimelineObject(): TimelineObject { fun toTimelineObject(): TimelineObject {
return TimelineObject( return TimelineObject(
TimelineObjectId(id), id = TimelineObjectId(id),
UserDetailId(userDetailId), userDetailId = UserDetailId(userDetailId),
TimelineId(timelineId), timelineId = TimelineId(timelineId),
PostId(postId), postId = PostId(postId),
ActorId(postActorId), postActorId = ActorId(postActorId),
Instant.ofEpochSecond(postCreatedAt), postCreatedAt = Instant.ofEpochSecond(postCreatedAt),
replyId?.let { PostId(it) }, replyId = replyId?.let { PostId(it) },
replyActorId?.let { ActorId(it) }, replyActorId = replyActorId?.let { ActorId(it) },
repostId?.let { PostId(it) }, repostId = repostId?.let { PostId(it) },
repostActorId?.let { ActorId(it) }, repostActorId = repostActorId?.let { ActorId(it) },
visibility, visibility = visibility,
isPureRepost, isPureRepost = isPureRepost,
mediaIds.map { MediaId(it) }, mediaIds = mediaIds.map { MediaId(it) },
emojiIds.map { EmojiId(it) }, emojiIds = emojiIds.map { EmojiId(it) },
visibleActors.map { ActorId(it) }, visibleActors = visibleActors.map { ActorId(it) },
hasMediaInRepost, hasMediaInRepost = hasMediaInRepost,
Instant.ofEpochSecond(lastUpdatedAt), lastUpdatedAt = Instant.ofEpochSecond(lastUpdatedAt),
warnFilters.map { it.toTimelineObjectWarnFilter() } warnFilters = warnFilters.map { it.toTimelineObjectWarnFilter() }
) )
} }
companion object { companion object {
fun of(timelineObject: TimelineObject): SpringDataMongoTimelineObject { fun of(timelineObject: TimelineObject): SpringDataMongoTimelineObject {
return SpringDataMongoTimelineObject( return SpringDataMongoTimelineObject(
timelineObject.id.value, id = timelineObject.id.value,
timelineObject.userDetailId.id, userDetailId = timelineObject.userDetailId.id,
timelineObject.timelineId.value, timelineId = timelineObject.timelineId.value,
timelineObject.postId.id, postId = timelineObject.postId.id,
timelineObject.postActorId.id, postActorId = timelineObject.postActorId.id,
timelineObject.postCreatedAt.epochSecond, postCreatedAt = timelineObject.postCreatedAt.epochSecond,
timelineObject.replyId?.id, replyId = timelineObject.replyId?.id,
timelineObject.replyActorId?.id, replyActorId = timelineObject.replyActorId?.id,
timelineObject.repostId?.id, repostId = timelineObject.repostId?.id,
timelineObject.repostActorId?.id, repostActorId = timelineObject.repostActorId?.id,
timelineObject.visibility, visibility = timelineObject.visibility,
timelineObject.isPureRepost, isPureRepost = timelineObject.isPureRepost,
timelineObject.mediaIds.map { it.id }, mediaIds = timelineObject.mediaIds.map { it.id },
timelineObject.emojiIds.map { it.emojiId }, emojiIds = timelineObject.emojiIds.map { it.emojiId },
timelineObject.visibleActors.map { it.id }, visibleActors = timelineObject.visibleActors.map { it.id },
timelineObject.hasMediaInRepost, hasMediaInRepost = timelineObject.hasMediaInRepost,
timelineObject.lastUpdatedAt.epochSecond, lastUpdatedAt = timelineObject.lastUpdatedAt.epochSecond,
timelineObject.warnFilters.map { SpringDataMongoTimelineObjectWarnFilter.of(it) } warnFilters = timelineObject.warnFilters.map { SpringDataMongoTimelineObjectWarnFilter.of(it) }
) )
} }
} }
@ -208,6 +207,7 @@ data class SpringDataMongoTimelineObjectWarnFilter(
} }
} }
@Suppress("FunctionMaxLength")
interface SpringDataMongoTimelineObjectRepository : CoroutineCrudRepository<SpringDataMongoTimelineObject, Long> { interface SpringDataMongoTimelineObjectRepository : CoroutineCrudRepository<SpringDataMongoTimelineObject, Long> {
fun findByPostId(postId: Long): Flow<SpringDataMongoTimelineObject> fun findByPostId(postId: Long): Flow<SpringDataMongoTimelineObject>
@ -217,8 +217,6 @@ interface SpringDataMongoTimelineObjectRepository : CoroutineCrudRepository<Spri
suspend fun deleteByTimelineId(timelineId: Long) suspend fun deleteByTimelineId(timelineId: Long)
suspend fun findByTimelineId(timelineId: TimelineId): Flow<SpringDataMongoTimelineObject>
suspend fun findFirstByTimelineIdAndPostIdGreaterThanOrderByIdAsc( suspend fun findFirstByTimelineIdAndPostIdGreaterThanOrderByIdAsc(
timelineId: Long, timelineId: Long,
postId: Long postId: Long

View File

@ -23,7 +23,7 @@ class SpringFrameworkDomainEventSubscriber : DomainEventSubscriber {
map[domainEvent.name]?.forEach { map[domainEvent.name]?.forEach {
try { try {
it.invoke(domainEvent) it.invoke(domainEvent)
} catch (e: Exception) { } catch (@Suppress("TooGenericExceptionCaught") e: Exception) {
logger.error("", e) logger.error("", e)
} }
} }

View File

@ -58,7 +58,9 @@ abstract class AbstractTimelineStore(private val idGenerateService: IdGenerateSe
if (timeline.visibility == TimelineVisibility.PUBLIC && post.visibility != Visibility.PUBLIC) { if (timeline.visibility == TimelineVisibility.PUBLIC && post.visibility != Visibility.PUBLIC) {
return null return null
} }
if (timeline.visibility == TimelineVisibility.UNLISTED && (post.visibility != Visibility.PUBLIC || post.visibility != Visibility.UNLISTED)) { if (timeline.visibility == TimelineVisibility.UNLISTED &&
(post.visibility != Visibility.PUBLIC || post.visibility != Visibility.UNLISTED)
) {
return null return null
} }
@ -68,21 +70,21 @@ abstract class AbstractTimelineStore(private val idGenerateService: IdGenerateSe
if (repost != null) { if (repost != null) {
return TimelineObject.create( return TimelineObject.create(
TimelineObjectId(idGenerateService.generateId()), timelineObjectId = TimelineObjectId(idGenerateService.generateId()),
timeline, timeline = timeline,
post, post = post,
replyActorId, replyActorId = replyActorId,
repost, repost = repost,
applyFilters.filterResults filterResults = applyFilters.filterResults
) )
} }
return TimelineObject.create( return TimelineObject.create(
TimelineObjectId(idGenerateService.generateId()), timelineObjectId = TimelineObjectId(idGenerateService.generateId()),
timeline, timeline = timeline,
post, post = post,
replyActorId, replyActorId = replyActorId,
applyFilters.filterResults filterResults = applyFilters.filterResults
) )
} }
@ -106,7 +108,10 @@ abstract class AbstractTimelineStore(private val idGenerateService: IdGenerateSe
protected abstract suspend fun removeTimelineObject(timelineId: TimelineId) protected abstract suspend fun removeTimelineObject(timelineId: TimelineId)
protected abstract suspend fun getPostsByTimelineRelationshipList(timelineRelationshipList: List<TimelineRelationship>): List<Post> @Suppress("FunctionMaxLength")
protected abstract suspend fun getPostsByTimelineRelationshipList(
timelineRelationshipList: List<TimelineRelationship>
): List<Post>
protected abstract suspend fun getPostsByPostId(postIds: List<PostId>, principal: Principal): List<Post> protected abstract suspend fun getPostsByPostId(postIds: List<PostId>, principal: Principal): List<Post>
@ -116,6 +121,7 @@ abstract class AbstractTimelineStore(private val idGenerateService: IdGenerateSe
page: Page? page: Page?
): PaginationList<TimelineObject, PostId> ): PaginationList<TimelineObject, PostId>
@Suppress("RedundantHigherOrderMapUsage") // if式に対応していないため
override suspend fun updatePost(post: Post) { override suspend fun updatePost(post: Post) {
val timelineObjectByPostId = getTimelineObjectByPostId(post.id) val timelineObjectByPostId = getTimelineObjectByPostId(post.id)
@ -236,16 +242,19 @@ abstract class AbstractTimelineStore(private val idGenerateService: IdGenerateSe
val actors = val actors =
getActors( getActors(
timelineObjectList.map { timelineObjectList.map { it.postActorId } +
it.postActorId timelineObjectList.mapNotNull { it.repostActorId } +
} + timelineObjectList.mapNotNull { it.repostActorId } + timelineObjectList.mapNotNull { it.replyActorId } timelineObjectList.mapNotNull { it.replyActorId }
) )
val postMap = posts.associate { post -> val postMap = posts.associate { post ->
post.id to applyFilters(post, newerFilters) post.id to applyFilters(post, newerFilters)
} }
val mediaMap = getMedias(posts.flatMap { it.mediaIds } + actors.mapNotNull { it.value.icon }) val mediaMap = getMedias(
posts.flatMap { it.mediaIds } +
actors.mapNotNull { it.value.icon }
)
return PaginationList( return PaginationList(
timelineObjectList.mapNotNull<TimelineObject, TimelineObjectDetail> { timelineObjectList.mapNotNull<TimelineObject, TimelineObjectDetail> {
@ -274,10 +283,10 @@ abstract class AbstractTimelineStore(private val idGenerateService: IdGenerateSe
repostPostMedias = repostMedias, repostPostMedias = repostMedias,
repostPostActor = repostActor, repostPostActor = repostActor,
repostPostActorIconMedia = mediaMap[repostActor?.icon], repostPostActorIconMedia = mediaMap[repostActor?.icon],
warnFilter = it.warnFilters + post.filterResults.map { warnFilter = it.warnFilters + post.filterResults.map { filterResult ->
TimelineObjectWarnFilter( TimelineObjectWarnFilter(
it.filter.id, filterResult.filter.id,
it.matchedKeyword filterResult.matchedKeyword
) )
} }
) )

View File

@ -36,6 +36,7 @@ import org.springframework.stereotype.Component
import java.time.Instant import java.time.Instant
@Component @Component
@Suppress("LongParameterList")
open class DefaultTimelineStore( open class DefaultTimelineStore(
private val timelineRepository: TimelineRepository, private val timelineRepository: TimelineRepository,
private val timelineRelationshipRepository: TimelineRelationshipRepository, private val timelineRelationshipRepository: TimelineRelationshipRepository,
@ -59,25 +60,18 @@ open class DefaultTimelineStore(
) )
} }
override suspend fun getTimeline(timelineId: TimelineId): Timeline? { override suspend fun getTimeline(timelineId: TimelineId): Timeline? = timelineRepository.findById(timelineId)
return timelineRepository.findById(timelineId)
}
override suspend fun getFilters(userDetailId: UserDetailId): List<Filter> { override suspend fun getFilters(userDetailId: UserDetailId): List<Filter> =
return filterRepository.findByUserDetailId(userDetailId) filterRepository.findByUserDetailId(userDetailId)
}
override suspend fun getNewerFilters(userDetailId: UserDetailId, lastUpdateAt: Instant): List<Filter> { override suspend fun getNewerFilters(userDetailId: UserDetailId, lastUpdateAt: Instant): List<Filter> =
return filterRepository.findByUserDetailId(userDetailId) filterRepository.findByUserDetailId(userDetailId)
}
override suspend fun applyFilters(post: Post, filters: List<Filter>): FilteredPost { override suspend fun applyFilters(post: Post, filters: List<Filter>): FilteredPost =
return filterDomainService.apply(post, FilterContext.HOME, filters) filterDomainService.apply(post, FilterContext.HOME, filters)
}
override suspend fun getPost(postId: PostId): Post? { override suspend fun getPost(postId: PostId): Post? = postRepository.findById(postId)
return postRepository.findById(postId)
}
override suspend fun insertTimelineObject(timelineObjectList: List<TimelineObject>) { override suspend fun insertTimelineObject(timelineObjectList: List<TimelineObject>) {
internalTimelineObjectRepository.saveAll(timelineObjectList) internalTimelineObjectRepository.saveAll(timelineObjectList)
@ -87,9 +81,8 @@ open class DefaultTimelineStore(
internalTimelineObjectRepository.saveAll(timelineObjectList) internalTimelineObjectRepository.saveAll(timelineObjectList)
} }
override suspend fun getTimelineObjectByPostId(postId: PostId): List<TimelineObject> { override suspend fun getTimelineObjectByPostId(postId: PostId): List<TimelineObject> =
return internalTimelineObjectRepository.findByPostId(postId) internalTimelineObjectRepository.findByPostId(postId)
}
override suspend fun removeTimelineObject(postId: PostId) { override suspend fun removeTimelineObject(postId: PostId) {
internalTimelineObjectRepository.deleteByPostId(postId) internalTimelineObjectRepository.deleteByPostId(postId)
@ -103,9 +96,8 @@ open class DefaultTimelineStore(
internalTimelineObjectRepository.deleteByTimelineId(timelineId) internalTimelineObjectRepository.deleteByTimelineId(timelineId)
} }
override suspend fun getPostsByTimelineRelationshipList(timelineRelationshipList: List<TimelineRelationship>): List<Post> { override suspend fun getPostsByTimelineRelationshipList(timelineRelationshipList: List<TimelineRelationship>): List<Post> =
return timelineRelationshipList.flatMap { getActorPost(it.actorId, visibilities(it)) } timelineRelationshipList.flatMap { getActorPost(it.actorId, visibilities(it)) }
}
override suspend fun getPostsByPostId(postIds: List<PostId>, principal: Principal): List<Post> { override suspend fun getPostsByPostId(postIds: List<PostId>, principal: Principal): List<Post> {
val findAllById = postRepository.findAllById(postIds) val findAllById = postRepository.findAllById(postIds)
@ -136,6 +128,7 @@ open class DefaultTimelineStore(
) )
} }
@Suppress("UnsafeCallOnNullableType")
override suspend fun getNextPaging( override suspend fun getNextPaging(
timelineId: TimelineId, timelineId: TimelineId,
page: Page? page: Page?
@ -158,15 +151,12 @@ open class DefaultTimelineStore(
return PaginationList(emptyList(), page?.maxId?.let { PostId(it) }, page?.minId?.let { PostId(it) }) return PaginationList(emptyList(), page?.maxId?.let { PostId(it) }, page?.minId?.let { PostId(it) })
} }
override suspend fun getActors(actorIds: List<ActorId>): Map<ActorId, Actor> { override suspend fun getActors(actorIds: List<ActorId>): Map<ActorId, Actor> =
return actorRepository.findAllById(actorIds).associateBy { it.id } actorRepository.findAllById(actorIds).associateBy { it.id }
}
override suspend fun getMedias(mediaIds: List<MediaId>): Map<MediaId, Media> { override suspend fun getMedias(mediaIds: List<MediaId>): Map<MediaId, Media> =
return mediaRepository.findByIds(mediaIds).associateBy { it.id } mediaRepository.findByIds(mediaIds).associateBy { it.id }
}
override suspend fun getUserDetails(userDetailIdList: List<UserDetailId>): Map<UserDetailId, UserDetail> { override suspend fun getUserDetails(userDetailIdList: List<UserDetailId>): Map<UserDetailId, UserDetail> =
return userDetailRepository.findAllById(userDetailIdList).associateBy { it.id } userDetailRepository.findAllById(userDetailIdList).associateBy { it.id }
}
} }

View File

@ -30,6 +30,8 @@ class PublishController(
} }
val instance = getLocalInstanceApplicationService.execute(Unit, principal) val instance = getLocalInstanceApplicationService.execute(Unit, principal)
@Suppress("UnsafeCallOnNullableType")
val userDetail = getUserDetailApplicationService.execute(GetUserDetail(principal.userDetailId!!.id), principal) val userDetail = getUserDetailApplicationService.execute(GetUserDetail(principal.userDetailId!!.id), principal)
model.addAttribute("instance", instance) model.addAttribute("instance", instance)
model.addAttribute("user", userDetail) model.addAttribute("user", userDetail)

View File

@ -32,7 +32,8 @@ class TimelineController(
?: throw InternalServerException("UserDetail not found.") ?: throw InternalServerException("UserDetail not found.")
} }
val homeTimelineId = userDetail.homeTimelineId!! val homeTimelineId =
userDetail.homeTimelineId ?: throw InternalServerException("HomeTimeline ${userDetail.id} is null.")
val execute = readTimelineApplicationService.execute( val execute = readTimelineApplicationService.execute(
ReadTimeline( ReadTimeline(
timelineId = homeTimelineId.value, timelineId = homeTimelineId.value,

View File

@ -677,7 +677,7 @@ class PostTest {
val actor = TestActorFactory.create(post.actorId.id) val actor = TestActorFactory.create(post.actorId.id)
assertThrows<IllegalArgumentException> { assertThrows<IllegalArgumentException> {
post.moveTo(PostId(2), actor) post.moveTo(PostId(2))
} }
} }
@ -687,7 +687,7 @@ class PostTest {
val actor = TestActorFactory.create(post.actorId.id) val actor = TestActorFactory.create(post.actorId.id)
assertDoesNotThrow { assertDoesNotThrow {
post.moveTo(PostId(2), actor) post.moveTo(PostId(2))
} }
assertEquals(PostId(2), post.moveTo) assertEquals(PostId(2), post.moveTo)

View File

@ -5,6 +5,7 @@ plugins {
alias(libs.plugins.openapi.generator) alias(libs.plugins.openapi.generator)
alias(libs.plugins.spring.boot) alias(libs.plugins.spring.boot)
alias(libs.plugins.kotlin.spring) alias(libs.plugins.kotlin.spring)
alias(libs.plugins.detekt)
} }
@ -48,6 +49,7 @@ configurations {
} }
dependencies { dependencies {
detektPlugins(libs.detekt.formatting)
implementation("org.springframework.boot:spring-boot-starter-web") implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-security") implementation("org.springframework.boot:spring-boot-starter-security")
implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310") implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310")
@ -115,3 +117,35 @@ sourceSets.main {
) )
} }
detekt {
parallel = true
config.setFrom(files("../detekt.yml"))
buildUponDefaultConfig = true
basePath = "${rootDir.absolutePath}/src/main/kotlin"
autoCorrect = true
}
configurations.matching { it.name == "detekt" }.all {
resolutionStrategy.eachDependency {
if (requested.group == "org.jetbrains.kotlin") {
useVersion(io.gitlab.arturbosch.detekt.getSupportedKotlinVersion())
}
}
}
tasks.withType<io.gitlab.arturbosch.detekt.Detekt> {
exclude("**/generated/**")
doFirst {
}
setSource("src/main/kotlin")
exclude("build/")
}
tasks.withType<io.gitlab.arturbosch.detekt.Detekt>().configureEach {
exclude("**/org/koin/ksp/generated/**", "**/generated/**")
}
tasks.withType<io.gitlab.arturbosch.detekt.DetektCreateBaselineTask>().configureEach {
exclude("**/org/koin/ksp/generated/**", "**/generated/**")
}

View File

@ -31,10 +31,11 @@ class GetAccountApplicationService(private val accountQueryService: AccountQuery
logger logger
) { ) {
override suspend fun internalExecute(command: GetAccount, principal: LocalUser): Account { override suspend fun internalExecute(command: GetAccount, principal: LocalUser): Account {
return accountQueryService.findById(command.accountId.toLong()) ?: throw Exception("Account not found") return accountQueryService.findById(command.accountId.toLong())
?: throw IllegalArgumentException("Account ${command.accountId} not found")
} }
companion object { companion object {
private val logger = LoggerFactory.getLogger(GetAccountApplicationService::class.java) private val logger = LoggerFactory.getLogger(GetAccountApplicationService::class.java)
} }
} }

View File

@ -28,7 +28,8 @@ import org.springframework.stereotype.Service
@Service @Service
class DeleteFilterV1ApplicationService(private val filterRepository: FilterRepository, transaction: Transaction) : class DeleteFilterV1ApplicationService(private val filterRepository: FilterRepository, transaction: Transaction) :
LocalUserAbstractApplicationService<DeleteFilterV1, Unit>( LocalUserAbstractApplicationService<DeleteFilterV1, Unit>(
transaction, logger transaction,
logger
) { ) {
override suspend fun internalExecute(command: DeleteFilterV1, principal: LocalUser) { override suspend fun internalExecute(command: DeleteFilterV1, principal: LocalUser) {
val filter = filterRepository.findByFilterKeywordId(FilterKeywordId(command.filterKeywordId)) val filter = filterRepository.findByFilterKeywordId(FilterKeywordId(command.filterKeywordId))
@ -42,4 +43,4 @@ class DeleteFilterV1ApplicationService(private val filterRepository: FilterRepos
companion object { companion object {
private val logger = LoggerFactory.getLogger(DeleteFilterV1ApplicationService::class.java) private val logger = LoggerFactory.getLogger(DeleteFilterV1ApplicationService::class.java)
} }
} }

View File

@ -16,4 +16,4 @@
package dev.usbharu.hideout.mastodon.application.filter package dev.usbharu.hideout.mastodon.application.filter
data class GetFilterV1(val filterKeywordId: Long) data class GetFilterV1(val filterKeywordId: Long)

View File

@ -31,7 +31,8 @@ import org.springframework.stereotype.Repository
@Repository @Repository
class GetFilterV1ApplicationService(private val filterRepository: FilterRepository, transaction: Transaction) : class GetFilterV1ApplicationService(private val filterRepository: FilterRepository, transaction: Transaction) :
AbstractApplicationService<GetFilterV1, V1Filter>( AbstractApplicationService<GetFilterV1, V1Filter>(
transaction, logger transaction,
logger
) { ) {
override suspend fun internalExecute(command: GetFilterV1, principal: Principal): V1Filter { override suspend fun internalExecute(command: GetFilterV1, principal: Principal): V1Filter {
val filter = filterRepository.findByFilterKeywordId(FilterKeywordId(command.filterKeywordId)) val filter = filterRepository.findByFilterKeywordId(FilterKeywordId(command.filterKeywordId))
@ -63,4 +64,4 @@ class GetFilterV1ApplicationService(private val filterRepository: FilterReposito
companion object { companion object {
private val logger = LoggerFactory.getLogger(GetFilterV1ApplicationService::class.java) private val logger = LoggerFactory.getLogger(GetFilterV1ApplicationService::class.java)
} }
} }

View File

@ -32,13 +32,12 @@ class GetStatusApplicationService(
transaction, transaction,
logger logger
) { ) {
companion object {
val logger = LoggerFactory.getLogger(GetStatusApplicationService::class.java)!!
}
override suspend fun internalExecute(command: GetStatus, principal: Principal): Status { override suspend fun internalExecute(command: GetStatus, principal: Principal): Status {
return statusQueryService.findByPostId(command.id.toLong(), principal) return statusQueryService.findByPostId(command.id.toLong(), principal)
?: throw IllegalArgumentException("Post ${command.id} not found.") ?: throw IllegalArgumentException("Post ${command.id} not found.")
} }
}
companion object {
val logger = LoggerFactory.getLogger(GetStatusApplicationService::class.java)!!
}
}

View File

@ -109,4 +109,4 @@ class MastodonSecurityConfig {
return http.build() return http.build()
} }
} }

View File

@ -29,4 +29,4 @@ class RoleHierarchyAuthorizationManagerFactory(private val roleHierarchy: RoleHi
hasAuthority.setRoleHierarchy(roleHierarchy) hasAuthority.setRoleHierarchy(roleHierarchy)
return hasAuthority return hasAuthority
} }
} }

View File

@ -25,7 +25,7 @@ import org.jetbrains.exposed.sql.selectAll
import org.springframework.stereotype.Repository import org.springframework.stereotype.Repository
@Repository @Repository
class AccountQueryServiceImpl(private val applicationConfig: ApplicationConfig) : AccountQueryService { class ExposedAccountQueryServiceImpl(private val applicationConfig: ApplicationConfig) : AccountQueryService {
override suspend fun findById(accountId: Long): Account? { override suspend fun findById(accountId: Long): Account? {
val query = Actors.selectAll().where { Actors.id eq accountId } val query = Actors.selectAll().where { Actors.id eq accountId }
@ -70,4 +70,4 @@ class AccountQueryServiceImpl(private val applicationConfig: ApplicationConfig)
followingCount = resultRow[Actors.followingCount], followingCount = resultRow[Actors.followingCount],
) )
} }
} }

View File

@ -56,14 +56,15 @@ class StatusQueryServiceImpl : StatusQueryService {
.leftJoin( .leftJoin(
relationshipsAlias, relationshipsAlias,
onColumn = { Posts.actorId }, onColumn = { Posts.actorId },
otherColumn = { relationshipsAlias[Relationships.targetActorId] }) otherColumn = { relationshipsAlias[Relationships.targetActorId] }
)
.select(Posts.columns) .select(Posts.columns)
.where { .where {
Posts.visibility eq Visibility.PUBLIC.name or Posts.visibility eq Visibility.PUBLIC.name or
(Posts.visibility eq Visibility.UNLISTED.name) or (Posts.visibility eq Visibility.UNLISTED.name) or
(Posts.visibility eq Visibility.DIRECT.name and (PostsVisibleActors.actorId eq principal.actorId.id)) or (Posts.visibility eq Visibility.DIRECT.name and (PostsVisibleActors.actorId eq principal.actorId.id)) or
(Posts.visibility eq Visibility.FOLLOWERS.name and (Relationships.blocking eq false and (relationshipsAlias[Relationships.following] eq true))) or (Posts.visibility eq Visibility.FOLLOWERS.name and (Relationships.blocking eq false and (relationshipsAlias[Relationships.following] eq true))) or
(Posts.actorId eq principal.actorId.id) (Posts.actorId eq principal.actorId.id)
} }
.alias("authorized_table") .alias("authorized_table")
} }
@ -321,4 +322,4 @@ fun EntityMedia.toMediaAttachments(): MediaAttachment = MediaAttachment(
description = description?.description, description = description?.description,
blurhash = blurHash?.hash, blurhash = blurHash?.hash,
textUrl = url.toString() textUrl = url.toString()
) )

View File

@ -48,6 +48,7 @@ import org.springframework.http.ResponseEntity
import org.springframework.stereotype.Controller import org.springframework.stereotype.Controller
@Controller @Controller
@Suppress("LongParameterList")
class SpringAccountApi( class SpringAccountApi(
private val getUserDetailApplicationService: GetUserDetailApplicationService, private val getUserDetailApplicationService: GetUserDetailApplicationService,
private val getAccountApplicationService: GetAccountApplicationService, private val getAccountApplicationService: GetAccountApplicationService,
@ -64,7 +65,6 @@ class SpringAccountApi(
private val principalContextHolder: SpringSecurityOauth2PrincipalContextHolder private val principalContextHolder: SpringSecurityOauth2PrincipalContextHolder
) : AccountApi { ) : AccountApi {
override suspend fun apiV1AccountsIdBlockPost(id: String): ResponseEntity<Relationship> { override suspend fun apiV1AccountsIdBlockPost(id: String): ResponseEntity<Relationship> {
userBlockApplicationService.execute(Block(id.toLong()), principalContextHolder.getPrincipal()) userBlockApplicationService.execute(Block(id.toLong()), principalContextHolder.getPrincipal())
return fetchRelationship(id) return fetchRelationship(id)
@ -74,9 +74,9 @@ class SpringAccountApi(
id: String, id: String,
followRequestBody: FollowRequestBody?, followRequestBody: FollowRequestBody?,
): ResponseEntity<Relationship> { ): ResponseEntity<Relationship> {
userFollowRequestApplicationService.execute( userFollowRequestApplicationService.execute(
FollowRequest(id.toLong()), principalContextHolder.getPrincipal() FollowRequest(id.toLong()),
principalContextHolder.getPrincipal()
) )
return fetchRelationship(id) return fetchRelationship(id)
} }
@ -110,53 +110,57 @@ class SpringAccountApi(
override suspend fun apiV1AccountsIdGet(id: String): ResponseEntity<Account> { override suspend fun apiV1AccountsIdGet(id: String): ResponseEntity<Account> {
return ResponseEntity.ok( return ResponseEntity.ok(
getAccountApplicationService.execute( getAccountApplicationService.execute(
GetAccount(id), principalContextHolder.getPrincipal() GetAccount(id),
principalContextHolder.getPrincipal()
) )
) )
} }
override suspend fun apiV1AccountsIdMutePost(id: String): ResponseEntity<Relationship> { override suspend fun apiV1AccountsIdMutePost(id: String): ResponseEntity<Relationship> {
userMuteApplicationService.execute( userMuteApplicationService.execute(
Mute(id.toLong()), principalContextHolder.getPrincipal() Mute(id.toLong()),
principalContextHolder.getPrincipal()
) )
return fetchRelationship(id) return fetchRelationship(id)
} }
override suspend fun apiV1AccountsIdRemoveFromFollowersPost(id: String): ResponseEntity<Relationship> { override suspend fun apiV1AccountsIdRemoveFromFollowersPost(id: String): ResponseEntity<Relationship> {
userRemoveFromFollowersApplicationService.execute( userRemoveFromFollowersApplicationService.execute(
RemoveFromFollowers(id.toLong()), principalContextHolder.getPrincipal() RemoveFromFollowers(id.toLong()),
principalContextHolder.getPrincipal()
) )
return fetchRelationship(id) return fetchRelationship(id)
} }
override suspend fun apiV1AccountsIdUnblockPost(id: String): ResponseEntity<Relationship> { override suspend fun apiV1AccountsIdUnblockPost(id: String): ResponseEntity<Relationship> {
userUnblockApplicationService.execute( userUnblockApplicationService.execute(
Unblock(id.toLong()), principalContextHolder.getPrincipal() Unblock(id.toLong()),
principalContextHolder.getPrincipal()
) )
return fetchRelationship(id) return fetchRelationship(id)
} }
override suspend fun apiV1AccountsIdUnfollowPost(id: String): ResponseEntity<Relationship> { override suspend fun apiV1AccountsIdUnfollowPost(id: String): ResponseEntity<Relationship> {
userUnfollowApplicationService.execute( userUnfollowApplicationService.execute(
Unfollow(id.toLong()), principalContextHolder.getPrincipal() Unfollow(id.toLong()),
principalContextHolder.getPrincipal()
) )
return fetchRelationship(id) return fetchRelationship(id)
} }
override suspend fun apiV1AccountsIdUnmutePost(id: String): ResponseEntity<Relationship> { override suspend fun apiV1AccountsIdUnmutePost(id: String): ResponseEntity<Relationship> {
userUnmuteApplicationService.execute( userUnmuteApplicationService.execute(
Unmute(id.toLong()), principalContextHolder.getPrincipal() Unmute(id.toLong()),
principalContextHolder.getPrincipal()
) )
return fetchRelationship(id) return fetchRelationship(id)
} }
override suspend fun apiV1AccountsPost(accountsCreateRequest: AccountsCreateRequest): ResponseEntity<Unit> { override suspend fun apiV1AccountsPost(accountsCreateRequest: AccountsCreateRequest): ResponseEntity<Unit> =
return super.apiV1AccountsPost(accountsCreateRequest) super.apiV1AccountsPost(accountsCreateRequest)
}
override suspend fun apiV1AccountsUpdateCredentialsPatch(updateCredentials: UpdateCredentials?): ResponseEntity<Account> { override suspend fun apiV1AccountsUpdateCredentialsPatch(updateCredentials: UpdateCredentials?): ResponseEntity<Account> =
return super.apiV1AccountsUpdateCredentialsPatch(updateCredentials) super.apiV1AccountsUpdateCredentialsPatch(updateCredentials)
}
override suspend fun apiV1AccountsVerifyCredentialsGet(): ResponseEntity<CredentialAccount> { override suspend fun apiV1AccountsVerifyCredentialsGet(): ResponseEntity<CredentialAccount> {
val principal = principalContextHolder.getPrincipal() val principal = principalContextHolder.getPrincipal()
@ -164,7 +168,8 @@ class SpringAccountApi(
getUserDetailApplicationService.execute( getUserDetailApplicationService.execute(
GetUserDetail( GetUserDetail(
principal.userDetailId?.id ?: throw PermissionDeniedException() principal.userDetailId?.id ?: throw PermissionDeniedException()
), principal ),
principal
) )
return ResponseEntity.ok( return ResponseEntity.ok(
@ -215,19 +220,18 @@ class SpringAccountApi(
} }
override suspend fun apiV1FollowRequestsAccountIdAuthorizePost(accountId: String): ResponseEntity<Relationship> { override suspend fun apiV1FollowRequestsAccountIdAuthorizePost(accountId: String): ResponseEntity<Relationship> {
userAcceptFollowRequestApplicationService.execute( userAcceptFollowRequestApplicationService.execute(
AcceptFollowRequest(accountId.toLong()), principalContextHolder.getPrincipal() AcceptFollowRequest(accountId.toLong()),
principalContextHolder.getPrincipal()
) )
return fetchRelationship(accountId) return fetchRelationship(accountId)
} }
override suspend fun apiV1FollowRequestsAccountIdRejectPost(accountId: String): ResponseEntity<Relationship> { override suspend fun apiV1FollowRequestsAccountIdRejectPost(accountId: String): ResponseEntity<Relationship> {
userRejectFollowRequestApplicationService.execute( userRejectFollowRequestApplicationService.execute(
RejectFollowRequest(accountId.toLong()), principalContextHolder.getPrincipal() RejectFollowRequest(accountId.toLong()),
principalContextHolder.getPrincipal()
) )
return fetchRelationship(accountId) return fetchRelationship(accountId)
} }
}
}

View File

@ -29,7 +29,6 @@ import java.net.URI
@Controller @Controller
class SpringAppApi(private val registerApplicationApplicationService: RegisterApplicationApplicationService) : AppApi { class SpringAppApi(private val registerApplicationApplicationService: RegisterApplicationApplicationService) : AppApi {
override suspend fun apiV1AppsPost(appsRequest: AppsRequest): ResponseEntity<Application> { override suspend fun apiV1AppsPost(appsRequest: AppsRequest): ResponseEntity<Application> {
val registerApplication = RegisterApplication( val registerApplication = RegisterApplication(
appsRequest.clientName, appsRequest.clientName,
setOf(URI.create(appsRequest.redirectUris)), setOf(URI.create(appsRequest.redirectUris)),
@ -39,13 +38,13 @@ class SpringAppApi(private val registerApplicationApplicationService: RegisterAp
val registeredApplication = registerApplicationApplicationService.execute(registerApplication, Anonymous) val registeredApplication = registerApplicationApplicationService.execute(registerApplication, Anonymous)
return ResponseEntity.ok( return ResponseEntity.ok(
Application( Application(
registeredApplication.name, name = registeredApplication.name,
"invalid-vapid-key", vapidKey = "invalid-vapid-key",
null, website = null,
registeredApplication.clientId, clientId = registeredApplication.clientId,
registeredApplication.clientSecret, clientSecret = registeredApplication.clientSecret,
appsRequest.redirectUris redirectUri = appsRequest.redirectUris
) )
) )
} }
} }

View File

@ -47,7 +47,8 @@ class SpringFilterApi(
override suspend fun apiV1FiltersIdDelete(id: String): ResponseEntity<Any> { override suspend fun apiV1FiltersIdDelete(id: String): ResponseEntity<Any> {
return ResponseEntity.ok( return ResponseEntity.ok(
deleteFilterV1ApplicationService.execute( deleteFilterV1ApplicationService.execute(
DeleteFilterV1(id.toLong()), principalContextHolder.getPrincipal() DeleteFilterV1(id.toLong()),
principalContextHolder.getPrincipal()
) )
) )
} }
@ -55,7 +56,8 @@ class SpringFilterApi(
override suspend fun apiV1FiltersIdGet(id: String): ResponseEntity<V1Filter> { override suspend fun apiV1FiltersIdGet(id: String): ResponseEntity<V1Filter> {
return ResponseEntity.ok( return ResponseEntity.ok(
getFilterV1ApplicationService.execute( getFilterV1ApplicationService.execute(
GetFilterV1(id.toLong()), principalContextHolder.getPrincipal() GetFilterV1(id.toLong()),
principalContextHolder.getPrincipal()
) )
) )
} }
@ -67,12 +69,9 @@ class SpringFilterApi(
irreversible: Boolean?, irreversible: Boolean?,
wholeWord: Boolean?, wholeWord: Boolean?,
expiresIn: Int?, expiresIn: Int?,
): ResponseEntity<V1Filter> { ): ResponseEntity<V1Filter> = super.apiV1FiltersIdPut(id, phrase, context, irreversible, wholeWord, expiresIn)
return super.apiV1FiltersIdPut(id, phrase, context, irreversible, wholeWord, expiresIn)
}
override suspend fun apiV1FiltersPost(v1FilterPostRequest: V1FilterPostRequest): ResponseEntity<V1Filter> { override suspend fun apiV1FiltersPost(v1FilterPostRequest: V1FilterPostRequest): ResponseEntity<V1Filter> {
val filterMode = if (v1FilterPostRequest.wholeWord == true) { val filterMode = if (v1FilterPostRequest.wholeWord == true) {
FilterMode.WHOLE_WORD FilterMode.WHOLE_WORD
} else { } else {
@ -89,13 +88,17 @@ class SpringFilterApi(
}.toSet() }.toSet()
val filter = userRegisterFilterApplicationService.execute( val filter = userRegisterFilterApplicationService.execute(
RegisterFilter( RegisterFilter(
v1FilterPostRequest.phrase, filterContext, FilterAction.WARN, v1FilterPostRequest.phrase,
filterContext,
FilterAction.WARN,
setOf(RegisterFilterKeyword(v1FilterPostRequest.phrase, filterMode)) setOf(RegisterFilterKeyword(v1FilterPostRequest.phrase, filterMode))
), principalContextHolder.getPrincipal() ),
principalContextHolder.getPrincipal()
) )
return ResponseEntity.ok( return ResponseEntity.ok(
getFilterV1ApplicationService.execute( getFilterV1ApplicationService.execute(
GetFilterV1(filter.filterKeywords.first().id), principalContextHolder.getPrincipal() GetFilterV1(filter.filterKeywords.first().id),
principalContextHolder.getPrincipal()
) )
) )
} }
@ -103,27 +106,25 @@ class SpringFilterApi(
override suspend fun apiV2FiltersFilterIdKeywordsPost( override suspend fun apiV2FiltersFilterIdKeywordsPost(
filterId: String, filterId: String,
filterKeywordsPostRequest: FilterKeywordsPostRequest, filterKeywordsPostRequest: FilterKeywordsPostRequest,
): ResponseEntity<FilterKeyword> { ): ResponseEntity<FilterKeyword> = super.apiV2FiltersFilterIdKeywordsPost(filterId, filterKeywordsPostRequest)
return super.apiV2FiltersFilterIdKeywordsPost(filterId, filterKeywordsPostRequest)
}
override suspend fun apiV2FiltersFilterIdStatusesPost( override suspend fun apiV2FiltersFilterIdStatusesPost(
filterId: String, filterId: String,
filterStatusRequest: FilterStatusRequest, filterStatusRequest: FilterStatusRequest,
): ResponseEntity<FilterStatus> { ): ResponseEntity<FilterStatus> = super.apiV2FiltersFilterIdStatusesPost(filterId, filterStatusRequest)
return super.apiV2FiltersFilterIdStatusesPost(filterId, filterStatusRequest)
}
override suspend fun apiV2FiltersIdDelete(id: String): ResponseEntity<Any> { override suspend fun apiV2FiltersIdDelete(id: String): ResponseEntity<Any> {
userDeleteFilterApplicationService.execute( userDeleteFilterApplicationService.execute(
DeleteFilter(id.toLong()), principalContextHolder.getPrincipal() DeleteFilter(id.toLong()),
principalContextHolder.getPrincipal()
) )
return ResponseEntity.ok(Unit) return ResponseEntity.ok(Unit)
} }
override suspend fun apiV2FiltersIdGet(id: String): ResponseEntity<Filter> { override suspend fun apiV2FiltersIdGet(id: String): ResponseEntity<Filter> {
val filter = userGetFilterApplicationService.execute( val filter = userGetFilterApplicationService.execute(
GetFilter(id.toLong()), principalContextHolder.getPrincipal() GetFilter(id.toLong()),
principalContextHolder.getPrincipal()
) )
return ResponseEntity.ok( return ResponseEntity.ok(
filter(filter) filter(filter)
@ -146,7 +147,6 @@ class SpringFilterApi(
filterAction = when (filter.filterAction) { filterAction = when (filter.filterAction) {
FilterAction.WARN -> Filter.FilterAction.warn FilterAction.WARN -> Filter.FilterAction.warn
FilterAction.HIDE -> Filter.FilterAction.hide FilterAction.HIDE -> Filter.FilterAction.hide
}, },
keywords = filter.filterKeywords.map { keywords = filter.filterKeywords.map {
FilterKeyword( FilterKeyword(
@ -154,7 +154,8 @@ class SpringFilterApi(
it.keyword, it.keyword,
it.filterMode == FilterMode.WHOLE_WORD it.filterMode == FilterMode.WHOLE_WORD
) )
}, statuses = null },
statuses = null
) )
override suspend fun apiV2FiltersIdPut( override suspend fun apiV2FiltersIdPut(
@ -164,29 +165,23 @@ class SpringFilterApi(
filterAction: String?, filterAction: String?,
expiresIn: Int?, expiresIn: Int?,
keywordsAttributes: List<FilterPubRequestKeyword>?, keywordsAttributes: List<FilterPubRequestKeyword>?,
): ResponseEntity<Filter> { ): ResponseEntity<Filter> =
return super.apiV2FiltersIdPut(id, title, context, filterAction, expiresIn, keywordsAttributes) super.apiV2FiltersIdPut(id, title, context, filterAction, expiresIn, keywordsAttributes)
}
override suspend fun apiV2FiltersKeywordsIdDelete(id: String): ResponseEntity<Any> { override suspend fun apiV2FiltersKeywordsIdDelete(id: String): ResponseEntity<Any> =
return super.apiV2FiltersKeywordsIdDelete(id) super.apiV2FiltersKeywordsIdDelete(id)
}
override suspend fun apiV2FiltersKeywordsIdGet(id: String): ResponseEntity<FilterKeyword> { override suspend fun apiV2FiltersKeywordsIdGet(id: String): ResponseEntity<FilterKeyword> =
return super.apiV2FiltersKeywordsIdGet(id) super.apiV2FiltersKeywordsIdGet(id)
}
override suspend fun apiV2FiltersKeywordsIdPut( override suspend fun apiV2FiltersKeywordsIdPut(
id: String, id: String,
keyword: String?, keyword: String?,
wholeWord: Boolean?, wholeWord: Boolean?,
regex: Boolean?, regex: Boolean?,
): ResponseEntity<FilterKeyword> { ): ResponseEntity<FilterKeyword> = super.apiV2FiltersKeywordsIdPut(id, keyword, wholeWord, regex)
return super.apiV2FiltersKeywordsIdPut(id, keyword, wholeWord, regex)
}
override suspend fun apiV2FiltersPost(filterPostRequest: FilterPostRequest): ResponseEntity<Filter> { override suspend fun apiV2FiltersPost(filterPostRequest: FilterPostRequest): ResponseEntity<Filter> {
val filter = userRegisterFilterApplicationService.execute( val filter = userRegisterFilterApplicationService.execute(
RegisterFilter( RegisterFilter(
filterName = filterPostRequest.title, filterName = filterPostRequest.title,
@ -216,16 +211,15 @@ class SpringFilterApi(
} }
) )
}.toSet() }.toSet()
), principalContextHolder.getPrincipal() ),
principalContextHolder.getPrincipal()
) )
return ResponseEntity.ok(filter(filter)) return ResponseEntity.ok(filter(filter))
} }
override suspend fun apiV2FiltersStatusesIdDelete(id: String): ResponseEntity<Any> { override suspend fun apiV2FiltersStatusesIdDelete(id: String): ResponseEntity<Any> =
return ResponseEntity.notFound().build() ResponseEntity.notFound().build()
}
override suspend fun apiV2FiltersStatusesIdGet(id: String): ResponseEntity<FilterStatus> { override suspend fun apiV2FiltersStatusesIdGet(id: String): ResponseEntity<FilterStatus> =
return ResponseEntity.notFound().build() ResponseEntity.notFound().build()
} }
}

View File

@ -17,23 +17,19 @@
package dev.usbharu.hideout.mastodon.interfaces.api package dev.usbharu.hideout.mastodon.interfaces.api
import dev.usbharu.hideout.mastodon.interfaces.api.generated.InstanceApi import dev.usbharu.hideout.mastodon.interfaces.api.generated.InstanceApi
import dev.usbharu.hideout.mastodon.interfaces.api.generated.model.* import dev.usbharu.hideout.mastodon.interfaces.api.generated.model.ExtendedDescription
import kotlinx.coroutines.flow.Flow import dev.usbharu.hideout.mastodon.interfaces.api.generated.model.Instance
import dev.usbharu.hideout.mastodon.interfaces.api.generated.model.V1Instance
import org.springframework.http.ResponseEntity import org.springframework.http.ResponseEntity
import org.springframework.stereotype.Controller import org.springframework.stereotype.Controller
@Controller @Controller
class SpringInstanceApi : InstanceApi { class SpringInstanceApi : InstanceApi {
override suspend fun apiV1InstanceExtendedDescriptionGet(): ResponseEntity<ExtendedDescription> { override suspend fun apiV1InstanceExtendedDescriptionGet(): ResponseEntity<ExtendedDescription> =
return super.apiV1InstanceExtendedDescriptionGet() super.apiV1InstanceExtendedDescriptionGet()
}
override suspend fun apiV1InstanceGet(): ResponseEntity<V1Instance> { override suspend fun apiV1InstanceGet(): ResponseEntity<V1Instance> = super.apiV1InstanceGet()
return super.apiV1InstanceGet()
}
override suspend fun apiV2InstanceGet(): ResponseEntity<Instance> { override suspend fun apiV2InstanceGet(): ResponseEntity<Instance> = super.apiV2InstanceGet()
return super.apiV2InstanceGet() }
}
}

View File

@ -52,25 +52,26 @@ class SpringMediaApi(
file.originalFilename ?: file.name, file.originalFilename ?: file.name,
null, null,
description description
), principalContextHolder.getPrincipal() ),
principalContextHolder.getPrincipal()
) )
return ResponseEntity.ok( return ResponseEntity.ok(
MediaAttachment( MediaAttachment(
media.id.toString(), id = media.id.toString(),
when (media.type) { type = when (media.type) {
Image -> MediaAttachment.Type.image Image -> MediaAttachment.Type.image
Video -> MediaAttachment.Type.video Video -> MediaAttachment.Type.video
Audio -> MediaAttachment.Type.audio Audio -> MediaAttachment.Type.audio
Unknown -> MediaAttachment.Type.unknown Unknown -> MediaAttachment.Type.unknown
}, },
media.url.toString(), url = media.url.toString(),
media.thumbprintURI?.toString(), previewUrl = media.thumbprintURI?.toString(),
media.remoteURL?.toString(), remoteUrl = media.remoteURL?.toString(),
media.description, description = media.description,
media.blurHash, blurhash = media.blurHash,
media.url.toASCIIString() textUrl = media.url.toASCIIString()
) )
) )
} }
} }

View File

@ -18,21 +18,16 @@ package dev.usbharu.hideout.mastodon.interfaces.api
import dev.usbharu.hideout.mastodon.interfaces.api.generated.NotificationsApi import dev.usbharu.hideout.mastodon.interfaces.api.generated.NotificationsApi
import dev.usbharu.hideout.mastodon.interfaces.api.generated.model.Notification import dev.usbharu.hideout.mastodon.interfaces.api.generated.model.Notification
import kotlinx.coroutines.flow.Flow
import org.springframework.http.ResponseEntity import org.springframework.http.ResponseEntity
import org.springframework.stereotype.Controller import org.springframework.stereotype.Controller
@Controller @Controller
class SpringNotificationApi : NotificationsApi { class SpringNotificationApi : NotificationsApi {
override suspend fun apiV1NotificationsClearPost(): ResponseEntity<Any> { override suspend fun apiV1NotificationsClearPost(): ResponseEntity<Any> = super.apiV1NotificationsClearPost()
return super.apiV1NotificationsClearPost()
}
override suspend fun apiV1NotificationsIdDismissPost(id: String): ResponseEntity<Any> { override suspend fun apiV1NotificationsIdDismissPost(id: String): ResponseEntity<Any> =
return super.apiV1NotificationsIdDismissPost(id) super.apiV1NotificationsIdDismissPost(id)
}
override suspend fun apiV1NotificationsIdGet(id: String): ResponseEntity<Notification> { override suspend fun apiV1NotificationsIdGet(id: String): ResponseEntity<Notification> =
return super.apiV1NotificationsIdGet(id) super.apiV1NotificationsIdGet(id)
} }
}

View File

@ -34,25 +34,22 @@ class SpringStatusApi(
private val getStatusApplicationService: GetStatusApplicationService, private val getStatusApplicationService: GetStatusApplicationService,
private val principalContextHolder: SpringSecurityOauth2PrincipalContextHolder private val principalContextHolder: SpringSecurityOauth2PrincipalContextHolder
) : StatusApi { ) : StatusApi {
override suspend fun apiV1StatusesIdEmojiReactionsEmojiDelete(id: String, emoji: String): ResponseEntity<Status> { override suspend fun apiV1StatusesIdEmojiReactionsEmojiDelete(id: String, emoji: String): ResponseEntity<Status> =
return super.apiV1StatusesIdEmojiReactionsEmojiDelete(id, emoji) super.apiV1StatusesIdEmojiReactionsEmojiDelete(id, emoji)
}
override suspend fun apiV1StatusesIdEmojiReactionsEmojiPut(id: String, emoji: String): ResponseEntity<Status> { override suspend fun apiV1StatusesIdEmojiReactionsEmojiPut(id: String, emoji: String): ResponseEntity<Status> =
return super.apiV1StatusesIdEmojiReactionsEmojiPut(id, emoji) super.apiV1StatusesIdEmojiReactionsEmojiPut(id, emoji)
}
override suspend fun apiV1StatusesIdGet(id: String): ResponseEntity<Status> { override suspend fun apiV1StatusesIdGet(id: String): ResponseEntity<Status> {
return ResponseEntity.ok( return ResponseEntity.ok(
getStatusApplicationService.execute( getStatusApplicationService.execute(
GetStatus(id), principalContextHolder.getPrincipal() GetStatus(id),
principalContextHolder.getPrincipal()
) )
) )
} }
override suspend fun apiV1StatusesPost(statusesRequest: dev.usbharu.hideout.mastodon.interfaces.api.StatusesRequest): ResponseEntity<Status> { override suspend fun apiV1StatusesPost(statusesRequest: StatusesRequest): ResponseEntity<Status> {
val principal = principalContextHolder.getPrincipal() val principal = principalContextHolder.getPrincipal()
val execute = registerLocalPostApplicationService.execute( val execute = registerLocalPostApplicationService.execute(
RegisterLocalPost( RegisterLocalPost(
@ -69,14 +66,14 @@ class SpringStatusApi(
replyId = statusesRequest.in_reply_to_id?.toLong(), replyId = statusesRequest.in_reply_to_id?.toLong(),
sensitive = statusesRequest.sensitive == true, sensitive = statusesRequest.sensitive == true,
mediaIds = statusesRequest.media_ids.map { it.toLong() } mediaIds = statusesRequest.media_ids.map { it.toLong() }
), principal ),
principal
) )
val status = val status =
getStatusApplicationService.execute(GetStatus(execute.toString()), principal) getStatusApplicationService.execute(GetStatus(execute.toString()), principal)
return ResponseEntity.ok( return ResponseEntity.ok(
status status
) )
} }
} }

View File

@ -20,4 +20,4 @@ import dev.usbharu.hideout.mastodon.interfaces.api.generated.TimelineApi
import org.springframework.stereotype.Controller import org.springframework.stereotype.Controller
@Controller @Controller
class SpringTimelineApi : TimelineApi class SpringTimelineApi : TimelineApi

View File

@ -66,8 +66,8 @@ class StatusesRequest {
override fun toString(): String { override fun toString(): String {
return "StatusesRequest(status=$status, mediaIds=$media_ids, poll=$poll, inReplyToId=$in_reply_to_id, " + return "StatusesRequest(status=$status, mediaIds=$media_ids, poll=$poll, inReplyToId=$in_reply_to_id, " +
"sensitive=$sensitive, spoilerText=$spoiler_text, visibility=$visibility, language=$language," + "sensitive=$sensitive, spoilerText=$spoiler_text, visibility=$visibility, language=$language," +
" scheduledAt=$scheduled_at)" " scheduledAt=$scheduled_at)"
} }
@Suppress("EnumNaming", "EnumEntryNameCase") @Suppress("EnumNaming", "EnumEntryNameCase")
@ -97,4 +97,4 @@ fun StatusesRequest.Visibility?.toStatusVisibility(): Status.Visibility {
direct -> Status.Visibility.direct direct -> Status.Visibility.direct
null -> Status.Visibility.public null -> Status.Visibility.public
} }
} }

View File

@ -21,4 +21,4 @@ import dev.usbharu.hideout.mastodon.interfaces.api.generated.model.Account
interface AccountQueryService { interface AccountQueryService {
suspend fun findById(accountId: Long): Account? suspend fun findById(accountId: Long): Account?
suspend fun findByIds(accountIds: List<Long>): List<Account> suspend fun findByIds(accountIds: List<Long>): List<Account>
} }

View File

@ -43,4 +43,4 @@ data class StatusQuery(
val repostId: Long?, val repostId: Long?,
val mediaIds: List<Long>, val mediaIds: List<Long>,
val emojiIds: List<Long>, val emojiIds: List<Long>,
) )