This commit is contained in:
usbharu 2024-05-27 21:59:06 +09:00
parent 40d4e70b25
commit ee8c8d4e14
63 changed files with 2080 additions and 33 deletions

View File

@ -0,0 +1,41 @@
/*
* 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.event.actor
import dev.usbharu.hideout.core.domain.model.actor.Actor2
import dev.usbharu.hideout.core.domain.model.shared.domainevent.DomainEvent
import dev.usbharu.hideout.core.domain.model.shared.domainevent.DomainEventBody
class ActorDomainEventFactory(private val actor: Actor2) {
fun createEvent(actorEvent: ActorEvent): DomainEvent {
return DomainEvent.create(
actorEvent.eventName,
ActorEventBody(actor)
)
}
}
class ActorEventBody(actor: Actor2) : DomainEventBody(
mapOf(
"actor" to actor
)
)
enum class ActorEvent(val eventName: String) {
update("ActorUpdate"),
delete("ActorDelete"),
}

View File

@ -0,0 +1,47 @@
/*
* 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.event.actorinstancerelationship
import dev.usbharu.hideout.core.domain.model.actorinstancerelationship.ActorInstanceRelationship
import dev.usbharu.hideout.core.domain.model.shared.domainevent.DomainEvent
import dev.usbharu.hideout.core.domain.model.shared.domainevent.DomainEventBody
class ActorInstanceRelationshipDomainEventFactory(private val actorInstanceRelationship: ActorInstanceRelationship) {
fun createEvent(actorInstanceRelationshipEvent: ActorInstanceRelationshipEvent): DomainEvent {
return DomainEvent.create(
actorInstanceRelationshipEvent.eventName,
ActorInstanceRelationshipEventBody(actorInstanceRelationship)
)
}
}
class ActorInstanceRelationshipEventBody(actorInstanceRelationship: ActorInstanceRelationship) :
DomainEventBody(
mapOf(
"actorId" to actorInstanceRelationship.actorId,
"instanceId" to actorInstanceRelationship.instanceId,
"muting" to actorInstanceRelationship.isMuting(),
"blocking" to actorInstanceRelationship.isBlocking(),
"doNotSendPrivate" to actorInstanceRelationship.isDoNotSendPrivate(),
)
)
enum class ActorInstanceRelationshipEvent(val eventName: String) {
block("ActorInstanceBlock"),
mute("ActorInstanceMute"),
unmute("ActorInstanceUnmute"),
}

View File

@ -0,0 +1,36 @@
/*
* 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.event.instance
import dev.usbharu.hideout.core.domain.model.instance.Instance
import dev.usbharu.hideout.core.domain.model.shared.domainevent.DomainEvent
import dev.usbharu.hideout.core.domain.model.shared.domainevent.DomainEventBody
class InstanceEventFactory(private val instance: Instance) {
fun createEvent(event: InstanceEvent): DomainEvent {
return DomainEvent.create(
event.eventName,
InstanceEventBody(instance)
)
}
}
class InstanceEventBody(instance: Instance) : DomainEventBody(mapOf("instance" to instance))
enum class InstanceEvent(val eventName: String) {
update("InstanceUpdate")
}

View File

@ -0,0 +1,39 @@
/*
* 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.event.post
import dev.usbharu.hideout.core.domain.model.post.Post2
import dev.usbharu.hideout.core.domain.model.shared.domainevent.DomainEvent
import dev.usbharu.hideout.core.domain.model.shared.domainevent.DomainEventBody
class PostDomainEventFactory(private val post: Post2) {
fun createEvent(postEvent: PostEvent): DomainEvent {
return DomainEvent.create(
postEvent.eventName,
PostEventBody(post)
)
}
}
class PostEventBody(post: Post2) : DomainEventBody(mapOf("post" to post))
enum class PostEvent(val eventName: String) {
delete("PostDelete"),
update("PostUpdate"),
create("PostCreate"),
checkUpdate("PostCheckUpdate"),
}

View File

@ -0,0 +1,121 @@
/*
* 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
import dev.usbharu.hideout.core.domain.event.actor.ActorDomainEventFactory
import dev.usbharu.hideout.core.domain.event.actor.ActorEvent.delete
import dev.usbharu.hideout.core.domain.event.actor.ActorEvent.update
import dev.usbharu.hideout.core.domain.model.instance.InstanceId
import dev.usbharu.hideout.core.domain.model.shared.Domain
import dev.usbharu.hideout.core.domain.model.shared.domainevent.DomainEventStorable
import java.net.URI
import java.time.Instant
class Actor2 private constructor(
val id: ActorId,
val name: ActorName,
val domain: Domain,
screenName: ActorScreenName,
description: ActorDescription,
val inbox: URI,
val outbox: URI,
val url: URI,
val publicKey: ActorPublicKey,
val privateKey: ActorPrivateKey? = null,
val createdAt: Instant,
val keyId: ActorKeyId,
val followersEndpoint: URI,
val followingEndpoint: URI,
val instance: InstanceId,
var locked: Boolean,
var followersCount: ActorRelationshipCount?,
var followingCount: ActorRelationshipCount?,
var postsCount: ActorPostsCount,
var lastPostDate: Instant? = null,
var suspend: Boolean,
) : DomainEventStorable() {
val emojis
get() = screenName.emojis
var description = description
set(value) {
addDomainEvent(ActorDomainEventFactory(this).createEvent(update))
field = value
}
var screenName = screenName
set(value) {
addDomainEvent(ActorDomainEventFactory(this).createEvent(update))
field = value
}
fun delete() {
addDomainEvent(ActorDomainEventFactory(this).createEvent(delete))
}
abstract class Actor2Factory {
protected suspend fun create(
id: ActorId,
name: ActorName,
domain: Domain,
screenName: ActorScreenName,
description: ActorDescription,
inbox: URI,
outbox: URI,
url: URI,
publicKey: ActorPublicKey,
privateKey: ActorPrivateKey? = null,
createdAt: Instant,
keyId: ActorKeyId,
followersEndpoint: URI,
followingEndpoint: URI,
instance: InstanceId,
locked: Boolean,
followersCount: ActorRelationshipCount,
followingCount: ActorRelationshipCount,
postsCount: ActorPostsCount,
lastPostDate: Instant? = null,
suspend: Boolean,
): Actor2 {
return Actor2(
id = id,
name = name,
domain = domain,
screenName = screenName,
description = description,
inbox = inbox,
outbox = outbox,
url = url,
publicKey = publicKey,
privateKey = privateKey,
createdAt = createdAt,
keyId = keyId,
followersEndpoint = followersEndpoint,
followingEndpoint = followingEndpoint,
instance = instance,
locked = locked,
followersCount = followersCount,
followingCount = followingCount,
postsCount = postsCount,
lastPostDate = lastPostDate,
suspend = suspend
)
}
}
}

View File

@ -0,0 +1,23 @@
/*
* 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
interface Actor2Repository {
suspend fun save(actor: Actor2): Actor2
suspend fun deleteById(actor: ActorId)
suspend fun findById(id: ActorId): Actor2?
}

View File

@ -0,0 +1,27 @@
/*
* 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
import dev.usbharu.hideout.core.domain.model.emoji.EmojiId
class ActorDescription private constructor(private val description: String, private val emojis: List<EmojiId>) {
abstract class ActorDescriptionFactory {
protected suspend fun create(description: String, emojis: List<EmojiId>): ActorDescription =
ActorDescription(description, emojis)
}
}

View File

@ -0,0 +1,24 @@
/*
* 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
@JvmInline
value class ActorId(val id: Long) {
companion object {
val ghost = ActorId(0L)
}
}

View File

@ -0,0 +1,20 @@
/*
* 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
@JvmInline
value class ActorKeyId(private val keyId: String)

View File

@ -0,0 +1,20 @@
/*
* 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
@JvmInline
value class ActorName(val name: String)

View File

@ -0,0 +1,27 @@
/*
* 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
@JvmInline
value class ActorPostsCount(private val postsCount: Long) {
init {
require(0 <= this.postsCount) { "Posts count must be greater than 0" }
}
operator fun inc() = ActorPostsCount(postsCount + 1)
operator fun dec() = ActorPostsCount(postsCount - 1)
}

View File

@ -0,0 +1,20 @@
/*
* 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
@JvmInline
value class ActorPrivateKey(private val privateKey: String)

View File

@ -0,0 +1,20 @@
/*
* 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
@JvmInline
value class ActorPublicKey(private val publicKey: String)

View File

@ -0,0 +1,27 @@
/*
* 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
@JvmInline
value class ActorRelationshipCount(private val followersCount: Int) {
init {
require(0 <= followersCount) { "Followers count must be > 0" }
}
operator fun inc(): ActorRelationshipCount = ActorRelationshipCount(followersCount + 1)
operator fun dec(): ActorRelationshipCount = ActorRelationshipCount(followersCount - 1)
}

View File

@ -0,0 +1,28 @@
/*
* 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
import dev.usbharu.hideout.core.domain.model.emoji.EmojiId
class ActorScreenName private constructor(val screenName: String, val emojis: List<EmojiId>) {
abstract class ActorScreenNameFactory {
protected suspend fun create(screenName: String, emojis: List<EmojiId>): ActorScreenName =
ActorScreenName(screenName, emojis)
}
}

View File

@ -0,0 +1,88 @@
/*
* 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.actorinstancerelationship
import dev.usbharu.hideout.core.domain.event.actorinstancerelationship.ActorInstanceRelationshipDomainEventFactory
import dev.usbharu.hideout.core.domain.event.actorinstancerelationship.ActorInstanceRelationshipEvent.*
import dev.usbharu.hideout.core.domain.model.actor.ActorId
import dev.usbharu.hideout.core.domain.model.instance.InstanceId
import dev.usbharu.hideout.core.domain.model.shared.domainevent.DomainEventStorable
data class ActorInstanceRelationship(
val actorId: ActorId,
val instanceId: InstanceId,
private var blocking: Boolean = false,
private var muting: Boolean = false,
private var doNotSendPrivate: Boolean = false,
) : DomainEventStorable() {
fun block(): ActorInstanceRelationship {
addDomainEvent(ActorInstanceRelationshipDomainEventFactory(this).createEvent(block))
blocking = true
return this
}
fun unblock(): ActorInstanceRelationship {
blocking = false
return this
}
fun mute(): ActorInstanceRelationship {
addDomainEvent(ActorInstanceRelationshipDomainEventFactory(this).createEvent(mute))
muting = true
return this
}
fun unmute(): ActorInstanceRelationship {
addDomainEvent(ActorInstanceRelationshipDomainEventFactory(this).createEvent(unmute))
muting = false
return this
}
fun doNotSendPrivate(): ActorInstanceRelationship {
doNotSendPrivate = true
return this
}
fun doSendPrivate(): ActorInstanceRelationship {
doNotSendPrivate = false
return this
}
fun isBlocking() = blocking
fun isMuting() = muting
fun isDoNotSendPrivate() = doNotSendPrivate
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as ActorInstanceRelationship
if (actorId != other.actorId) return false
if (instanceId != other.instanceId) return false
return true
}
override fun hashCode(): Int {
var result = actorId.hashCode()
result = 31 * result + instanceId.hashCode()
return result
}
}

View File

@ -16,13 +16,17 @@
package dev.usbharu.hideout.core.domain.model.deletedActor
import dev.usbharu.hideout.core.domain.model.actor.ActorName
import dev.usbharu.hideout.core.domain.model.actor.ActorPublicKey
import dev.usbharu.hideout.core.domain.model.shared.Domain
import java.net.URI
import java.time.Instant
data class DeletedActor(
val id: Long,
val name: String,
val domain: String,
val apiId: String,
val publicKey: String,
val id: DeletedActorId,
val name: ActorName,
val domain: Domain,
val apId: URI,
val publicKey: ActorPublicKey,
val deletedAt: Instant,
)

View File

@ -0,0 +1,20 @@
/*
* 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.deletedActor
@JvmInline
value class DeletedActorId(val id: Long)

View File

@ -22,4 +22,5 @@ interface CustomEmojiRepository {
suspend fun findById(id: Long): CustomEmoji?
suspend fun delete(customEmoji: CustomEmoji)
suspend fun findByNameAndDomain(name: String, domain: String): CustomEmoji?
suspend fun findByNamesAndDomain(names: List<String>, domain: String): List<CustomEmoji>
}

View File

@ -0,0 +1,20 @@
/*
* 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.emoji
@JvmInline
value class EmojiId(private val emojiId: Long)

View File

@ -16,19 +16,46 @@
package dev.usbharu.hideout.core.domain.model.instance
import dev.usbharu.hideout.core.domain.event.instance.InstanceEvent
import dev.usbharu.hideout.core.domain.event.instance.InstanceEventFactory
import dev.usbharu.hideout.core.domain.model.shared.domainevent.DomainEventStorable
import java.net.URI
import java.time.Instant
data class Instance(
val id: Long,
val name: String,
val description: String,
val url: String,
val iconUrl: String,
val sharedInbox: String?,
val software: String,
val version: String,
val isBlocked: Boolean,
val isMuted: Boolean,
val moderationNote: String,
val createdAt: Instant
)
class Instance(
val id: InstanceId,
var name: InstanceName,
var description: InstanceDescription,
val url: URI,
iconUrl: URI,
var sharedInbox: URI?,
var software: InstanceSoftware,
var version: InstanceVersion,
var isBlocked: Boolean,
var isMuted: Boolean,
var moderationNote: InstanceModerationNote,
val createdAt: Instant,
) : DomainEventStorable() {
var iconUrl = iconUrl
set(value) {
addDomainEvent(InstanceEventFactory(this).createEvent(InstanceEvent.update))
field = value
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as Instance
return id == other.id
}
override fun hashCode(): Int {
return id.hashCode()
}
}

View File

@ -0,0 +1,20 @@
/*
* 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.instance
@JvmInline
value class InstanceDescription(val description: String)

View File

@ -0,0 +1,20 @@
/*
* 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.instance
@JvmInline
value class InstanceId(private val instanceId: Long)

View File

@ -0,0 +1,20 @@
/*
* 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.instance
@JvmInline
value class InstanceModerationNote(val note: String)

View File

@ -0,0 +1,20 @@
/*
* 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.instance
@JvmInline
value class InstanceName(val name: String)

View File

@ -16,10 +16,12 @@
package dev.usbharu.hideout.core.domain.model.instance
import java.net.URI
interface InstanceRepository {
suspend fun generateId(): Long
suspend fun generateId(): InstanceId
suspend fun save(instance: Instance): Instance
suspend fun findById(id: Long): Instance?
suspend fun findById(id: InstanceId): Instance?
suspend fun delete(instance: Instance)
suspend fun findByUrl(url: String): Instance?
suspend fun findByUrl(url: URI): Instance?
}

View File

@ -0,0 +1,20 @@
/*
* 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.instance
@JvmInline
value class InstanceSoftware(val software: String)

View File

@ -0,0 +1,20 @@
/*
* 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.instance
@JvmInline
value class InstanceVersion(val version: String)

View File

@ -0,0 +1,20 @@
/*
* 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.media
@JvmInline
value class MediaId(val id: Long)

View File

@ -0,0 +1,229 @@
/*
* 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.post
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.ActorId
import dev.usbharu.hideout.core.domain.model.media.MediaId
import dev.usbharu.hideout.core.domain.model.shared.domainevent.DomainEventStorable
import java.net.URI
import java.time.Instant
class Post2 private constructor(
val id: PostId,
actorId: ActorId,
overview: PostOverview? = null,
content: PostContent,
val createdAt: Instant,
visibility: Visibility,
val url: URI,
val repostId: PostId?,
val replyId: PostId?,
sensitive: Boolean,
val apId: URI,
deleted: Boolean,
mediaIds: List<MediaId>,
visibleActors: List<ActorId> = emptyList(),
hide: Boolean = false,
moveTo: PostId? = null,
) : DomainEventStorable() {
var actorId = actorId
private set
get() {
if (deleted) {
return ActorId.ghost
}
return field
}
var visibility = visibility
set(value) {
require(value != Visibility.DIRECT)
require(field.ordinal >= value.ordinal)
require(deleted.not())
if (field != value) {
addDomainEvent(PostDomainEventFactory(this).createEvent(PostEvent.update))
}
field = value
}
var visibleActors = visibleActors
set(value) {
require(deleted.not())
if (visibility == Visibility.DIRECT) {
addDomainEvent(PostDomainEventFactory(this).createEvent(PostEvent.update))
field = field.plus(value).distinct()
}
}
var content = content
get() {
if (hide) {
return PostContent.empty
}
return field
}
set(value) {
require(deleted.not())
if (field != value) {
addDomainEvent(PostDomainEventFactory(this).createEvent(PostEvent.update))
}
field = value
}
var overview = overview
get() {
if (hide) {
return null
}
return field
}
set(value) {
require(deleted.not())
if (field != value) {
addDomainEvent(PostDomainEventFactory(this).createEvent(PostEvent.update))
}
field = value
}
var sensitive = sensitive
set(value) {
require(deleted.not())
if (field != value) {
addDomainEvent(PostDomainEventFactory(this).createEvent(PostEvent.update))
}
field = value
}
val text
get() = content.text
val emojiIds
get() = content.emojiIds
var mediaIds = mediaIds
get() {
if (hide) {
return emptyList()
}
return field
}
private set
fun addMediaIds(mediaIds: List<MediaId>) {
require(deleted.not())
addDomainEvent(PostDomainEventFactory(this).createEvent(PostEvent.update))
this.mediaIds = this.mediaIds.plus(mediaIds).distinct()
}
var deleted = deleted
private set
fun delete() {
if (deleted.not()) {
addDomainEvent(PostDomainEventFactory(this).createEvent(PostEvent.delete))
content = PostContent.empty
overview = null
mediaIds = emptyList()
}
deleted = true
}
fun checkUpdate() {
addDomainEvent(PostDomainEventFactory(this).createEvent(PostEvent.checkUpdate))
}
fun restore(content: PostContent, overview: PostOverview?, mediaIds: List<MediaId>) {
deleted = false
this.content = content
this.overview = overview
this.mediaIds = mediaIds
}
var hide = hide
private set
fun hide() {
hide = true
}
fun show() {
hide = false
}
var moveTo = moveTo
private set
fun moveTo(moveTo: PostId) {
require(this.moveTo == null)
this.moveTo = moveTo
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as Post2
return id == other.id
}
override fun hashCode(): Int {
return id.hashCode()
}
abstract class PostFactory {
protected fun create(
id: PostId,
actorId: ActorId,
overview: PostOverview? = null,
content: PostContent,
createdAt: Instant,
visibility: Visibility,
url: URI,
repostId: PostId?,
replyId: PostId?,
sensitive: Boolean,
apId: URI,
deleted: Boolean,
mediaIds: List<MediaId>,
hide: Boolean,
): Post2 {
return Post2(
id = id,
actorId = actorId,
overview = overview,
content = content,
createdAt = createdAt,
visibility = visibility,
url = url,
repostId = repostId,
replyId = replyId,
sensitive = sensitive,
apId = apId,
deleted = deleted,
mediaIds = mediaIds,
hide = hide
).apply { addDomainEvent(PostDomainEventFactory(this).createEvent(PostEvent.create)) }
}
}
}

View File

@ -0,0 +1,23 @@
/*
* 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.post
interface Post2Repository {
suspend fun save(post: Post2): Post2
suspend fun findById(id: PostId): Post2?
suspend fun deleteById(id: PostId)
}

View File

@ -0,0 +1,34 @@
/*
* 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.post
import dev.usbharu.hideout.core.domain.model.emoji.EmojiId
class PostContent private constructor(val text: String, val content: String, val emojiIds: List<EmojiId>) {
companion object {
val empty = PostContent("", "", emptyList())
}
abstract class PostContentFactory {
protected suspend fun create(text: String, content: String, emojiIds: List<EmojiId>): PostContent {
return PostContent(
text, content, emojiIds
)
}
}
}

View File

@ -0,0 +1,20 @@
/*
* 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.post
@JvmInline
value class PostId(val id: Long)

View File

@ -0,0 +1,20 @@
/*
* 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.post
@JvmInline
value class PostOverview(val overview: String)

View File

@ -0,0 +1,20 @@
/*
* 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.shared
@JvmInline
value class Domain(val domain: String)

View File

@ -0,0 +1,37 @@
/*
* 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.shared.domainevent
import java.time.Instant
import java.util.*
data class DomainEvent(
private val id: String,
private val name: String,
private val occurredOn: Instant,
private val body: DomainEventBody,
) {
companion object {
fun create(name: String, body: DomainEventBody): DomainEvent {
return DomainEvent(UUID.randomUUID().toString(), name, Instant.now(), body)
}
fun reconstruct(id: String, name: String, occurredOn: Instant, body: DomainEventBody): DomainEvent {
return DomainEvent(id, name, occurredOn, body)
}
}
}

View File

@ -0,0 +1,23 @@
/*
* 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.shared.domainevent
abstract class DomainEventBody(val map: Map<String, Any>) {
fun toMap(): Map<String, Any> {
return map
}
}

View File

@ -0,0 +1,29 @@
/*
* 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.shared.domainevent
abstract class DomainEventStorable {
private val domainEvents: MutableList<DomainEvent> = mutableListOf()
protected fun addDomainEvent(domainEvent: DomainEvent) {
domainEvents.add(domainEvent)
}
fun clearDomainEvents() = domainEvents.clear()
fun getDomainEvents(): List<DomainEvent> = domainEvents.toList()
}

View File

@ -16,8 +16,33 @@
package dev.usbharu.hideout.core.domain.model.userdetails
data class UserDetail(
val actorId: Long,
val password: String,
val autoAcceptFolloweeFollowRequest: Boolean
)
import dev.usbharu.hideout.core.domain.model.actor.ActorId
class UserDetail(
val actorId: ActorId,
var password: UserDetailHashedPassword,
var autoAcceptFolloweeFollowRequest: Boolean,
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as UserDetail
return actorId == other.actorId
}
override fun hashCode(): Int {
return actorId.hashCode()
}
companion object {
fun create(
actorId: ActorId,
password: UserDetailHashedPassword,
autoAcceptFolloweeFollowRequest: Boolean = false,
): UserDetail {
return UserDetail(actorId, password, autoAcceptFolloweeFollowRequest)
}
}
}

View File

@ -0,0 +1,20 @@
/*
* 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.userdetails
@JvmInline
value class UserDetailHashedPassword(val password: String)

View File

@ -0,0 +1,30 @@
/*
* 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.service.actor
import dev.usbharu.hideout.application.config.ApplicationConfig
import dev.usbharu.hideout.core.domain.model.actor.Actor
import org.springframework.stereotype.Service
interface IRemoteActorCheckDomainService {
fun isRemoteActor(actor: Actor): Boolean
}
@Service
class RemoteActorCheckDomainService(private val applicationConfig: ApplicationConfig) : IRemoteActorCheckDomainService {
override fun isRemoteActor(actor: Actor): Boolean = actor.domain == applicationConfig.url.host
}

View File

@ -0,0 +1,25 @@
/*
* 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.service.actor.local
import dev.usbharu.hideout.core.domain.model.actor.ActorPrivateKey
import dev.usbharu.hideout.core.domain.model.actor.ActorPublicKey
interface LocalActorDomainService {
suspend fun usernameAlreadyUse(name: String): Boolean
suspend fun generateKeyPair(): Pair<ActorPublicKey, ActorPrivateKey>
}

View File

@ -0,0 +1,21 @@
/*
* 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.service.actorinstancerelationship
interface ActorInstanceRelationshipDomainService {
suspend fun block()
}

View File

@ -0,0 +1,21 @@
/*
* 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.service.userdetail
interface PasswordEncoder {
suspend fun encode(input: String): String
}

View File

@ -0,0 +1,25 @@
/*
* 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.service.userdetail
import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailHashedPassword
import org.springframework.stereotype.Service
@Service
class UserDetailDomainService(private val passwordEncoder: PasswordEncoder) {
suspend fun hashPassword(password: String) = UserDetailHashedPassword(passwordEncoder.encode(password))
}

View File

@ -39,7 +39,7 @@ class DeletedActorRepositoryImpl : DeletedActorRepository, AbstractRepository()
it[id] = deletedActor.id
it[name] = deletedActor.name
it[domain] = deletedActor.domain
it[apId] = deletedActor.apiId
it[apId] = deletedActor.apId
it[publicKey] = deletedActor.publicKey
it[deletedAt] = deletedActor.deletedAt
}
@ -47,7 +47,7 @@ class DeletedActorRepositoryImpl : DeletedActorRepository, AbstractRepository()
DeletedActors.update({ DeletedActors.id eq deletedActor.id }) {
it[name] = deletedActor.name
it[domain] = deletedActor.domain
it[apId] = deletedActor.apiId
it[apId] = deletedActor.apId
it[publicKey] = deletedActor.publicKey
it[deletedAt] = deletedActor.deletedAt
}
@ -85,7 +85,7 @@ private fun deletedActor(singleOr: ResultRow): DeletedActor {
id = singleOr[DeletedActors.id],
name = singleOr[DeletedActors.name],
domain = singleOr[DeletedActors.domain],
apiId = singleOr[DeletedActors.publicKey],
apId = singleOr[DeletedActors.publicKey],
publicKey = singleOr[DeletedActors.apId],
deletedAt = singleOr[DeletedActors.deletedAt]
)

View File

@ -0,0 +1,66 @@
/*
* 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.infrastructure.factory
import dev.usbharu.hideout.application.config.ApplicationConfig
import dev.usbharu.hideout.application.service.id.IdGenerateService
import dev.usbharu.hideout.core.domain.model.actor.*
import dev.usbharu.hideout.core.domain.model.instance.InstanceId
import dev.usbharu.hideout.core.domain.model.shared.Domain
import org.springframework.stereotype.Component
import java.net.URI
import java.time.Instant
@Component
class Actor2FactoryImpl(
private val idGenerateService: IdGenerateService,
private val actorScreenNameFactory: ActorScreenNameFactoryImpl,
private val actorDescriptionFactory: ActorDescriptionFactoryImpl,
private val applicationConfig: ApplicationConfig,
) : Actor2.Actor2Factory() {
suspend fun createLocal(
name: String,
keyPair: Pair<ActorPublicKey, ActorPrivateKey>,
instanceId: InstanceId,
): Actor2 {
val actorName = ActorName(name)
val userUrl = "${applicationConfig.url}/users/${actorName.name}"
return super.create(
id = ActorId(idGenerateService.generateId()),
name = actorName,
domain = Domain(applicationConfig.url.host),
screenName = actorScreenNameFactory.create(name),
description = actorDescriptionFactory.create(""),
inbox = URI.create("$userUrl/inbox"),
outbox = URI.create("$userUrl/outbox"),
url = applicationConfig.url.toURI(),
publicKey = keyPair.first,
privateKey = keyPair.second,
createdAt = Instant.now(),
keyId = ActorKeyId("$userUrl#main-key"),
followersEndpoint = URI.create("$userUrl/followers"),
followingEndpoint = URI.create("$userUrl/following"),
instance = instanceId,
locked = false,
followersCount = ActorRelationshipCount(0),
followingCount = ActorRelationshipCount(0),
postsCount = ActorPostsCount(0),
lastPostDate = null,
suspend = false
)
}
}

View File

@ -0,0 +1,41 @@
/*
* 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.infrastructure.factory
import dev.usbharu.hideout.application.config.ApplicationConfig
import dev.usbharu.hideout.core.domain.model.actor.ActorDescription
import dev.usbharu.hideout.core.domain.model.emoji.CustomEmojiRepository
import dev.usbharu.hideout.core.domain.model.emoji.EmojiId
import org.springframework.stereotype.Component
@Component
class ActorDescriptionFactoryImpl(
private val applicationConfig: ApplicationConfig,
private val emojiRepository: CustomEmojiRepository,
) : ActorDescription.ActorDescriptionFactory() {
val regex = Regex(":(w+):")
suspend fun create(description: String): ActorDescription {
val findAll = regex.findAll(description)
val emojis =
emojiRepository.findByNamesAndDomain(
findAll.map { it.groupValues[1] }.toList(),
applicationConfig.url.host
)
return create(description, emojis.map { EmojiId(it.id) })
}
}

View File

@ -0,0 +1,45 @@
/*
* 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.infrastructure.factory
import dev.usbharu.hideout.application.config.ApplicationConfig
import dev.usbharu.hideout.core.domain.model.actor.ActorScreenName
import dev.usbharu.hideout.core.domain.model.emoji.CustomEmojiRepository
import dev.usbharu.hideout.core.domain.model.emoji.EmojiId
import org.springframework.stereotype.Component
@Component
class ActorScreenNameFactoryImpl(
private val applicationConfig: ApplicationConfig,
private val emojiRepository: CustomEmojiRepository,
) : ActorScreenName.ActorScreenNameFactory() {
val regex = Regex(":(w+):")
suspend fun create(content: String): ActorScreenName {
val findAll = regex.findAll(content)
val emojis =
emojiRepository.findByNamesAndDomain(
findAll.map { it.groupValues[1] }.toList(),
applicationConfig.url.host
)
return create(content, emojis.map { EmojiId(it.id) })
}
}

View File

@ -0,0 +1,35 @@
/*
* 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.infrastructure.factory
import dev.usbharu.hideout.core.domain.model.post.PostContent
import dev.usbharu.hideout.core.service.post.PostContentFormatter
import org.springframework.stereotype.Component
@Component
class PostContentFactoryImpl(
private val postContentFormatter: PostContentFormatter,
) : PostContent.PostContentFactory() {
suspend fun create(content: String): PostContent {
val format = postContentFormatter.format(content)
return super.create(
format.content,
format.html,
emptyList()
)
}
}

View File

@ -0,0 +1,67 @@
/*
* 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.infrastructure.factory
import dev.usbharu.hideout.application.config.ApplicationConfig
import dev.usbharu.hideout.application.service.id.IdGenerateService
import dev.usbharu.hideout.core.domain.model.actor.ActorId
import dev.usbharu.hideout.core.domain.model.actor.ActorName
import dev.usbharu.hideout.core.domain.model.media.MediaId
import dev.usbharu.hideout.core.domain.model.post.Post2
import dev.usbharu.hideout.core.domain.model.post.PostId
import dev.usbharu.hideout.core.domain.model.post.PostOverview
import dev.usbharu.hideout.core.domain.model.post.Visibility
import org.springframework.stereotype.Component
import java.net.URI
import java.time.Instant
@Component
class PostFactoryImpl(
private val idGenerateService: IdGenerateService,
private val postContentFactoryImpl: PostContentFactoryImpl,
private val applicationConfig: ApplicationConfig,
) : Post2.PostFactory() {
suspend fun createLocal(
actorId: ActorId,
actorName: ActorName,
overview: PostOverview,
content: String,
visibility: Visibility,
repostId: PostId?,
replyId: PostId?,
sensitive: Boolean,
mediaIds: List<MediaId>,
): Post2 {
val id = idGenerateService.generateId()
val url = URI.create(applicationConfig.url.toString() + "/users/" + actorName + "/posts/" + id)
return super.create(
PostId(id),
actorId,
overview,
postContentFactoryImpl.create(content),
Instant.now(),
visibility,
url,
repostId,
replyId,
sensitive,
url,
false,
mediaIds
)
}
}

View File

@ -159,7 +159,7 @@ class UserServiceImpl(
id = actor.id,
name = actor.name,
domain = actor.domain,
apiId = actor.url,
apId = actor.url,
publicKey = actor.publicKey,
deletedAt = Instant.now()
)
@ -179,7 +179,7 @@ class UserServiceImpl(
deletedActorRepository.delete(deletedActor)
owlProducer.publishTask(UpdateActorTask(deletedActor.id, deletedActor.apiId))
owlProducer.publishTask(UpdateActorTask(deletedActor.id, deletedActor.apId))
}
override suspend fun deleteLocalUser(userId: Long) {
@ -189,7 +189,7 @@ class UserServiceImpl(
id = actor.id,
name = actor.name,
domain = actor.domain,
apiId = actor.url,
apId = actor.url,
publicKey = actor.publicKey,
deletedAt = Instant.now()
)

View File

@ -0,0 +1,25 @@
/*
* 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.usecase.actor
import dev.usbharu.hideout.core.domain.model.actor.ActorId
class DeleteLocalActorApplicationService {
suspend fun delete(actorId: ActorId, executor: ActorId) {
}
}

View File

@ -0,0 +1,25 @@
/*
* 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.usecase.actor
import dev.usbharu.hideout.core.domain.model.actor.ActorId
class MigrationLocalActorApplicationService {
suspend fun migration(from: ActorId, to: ActorId, executor: ActorId) {
TODO()
}
}

View File

@ -0,0 +1,22 @@
/*
* 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.usecase.actor
data class RegisterLocalActor(
val name: String,
val password: String,
)

View File

@ -0,0 +1,65 @@
/*
* 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.usecase.actor
import dev.usbharu.hideout.application.config.ApplicationConfig
import dev.usbharu.hideout.application.external.Transaction
import dev.usbharu.hideout.core.domain.model.actor.Actor2Repository
import dev.usbharu.hideout.core.domain.model.instance.InstanceRepository
import dev.usbharu.hideout.core.domain.model.userdetails.UserDetail
import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailRepository
import dev.usbharu.hideout.core.domain.service.actor.local.LocalActorDomainService
import dev.usbharu.hideout.core.domain.service.userdetail.UserDetailDomainService
import dev.usbharu.hideout.core.infrastructure.factory.Actor2FactoryImpl
import org.springframework.stereotype.Service
@Service
class RegisterLocalActorApplicationService(
private val transaction: Transaction,
private val actorDomainService: LocalActorDomainService,
private val actor2Repository: Actor2Repository,
private val actor2FactoryImpl: Actor2FactoryImpl,
private val instanceRepository: InstanceRepository,
private val applicationConfig: ApplicationConfig,
private val userDetailDomainService: UserDetailDomainService,
private val userDetailRepository: UserDetailRepository,
) {
suspend fun register(registerLocalActor: RegisterLocalActor) {
transaction.transaction {
if (actorDomainService.usernameAlreadyUse(registerLocalActor.name)) {
//todo 適切な例外を考える
throw Exception("Username already exists")
}
val instance = instanceRepository.findByUrl(applicationConfig.url.toURI())!!
val actor = actor2FactoryImpl.createLocal(
registerLocalActor.name,
actorDomainService.generateKeyPair(),
instance.id
)
actor2Repository.save(actor)
val userDetail = UserDetail.create(
actor.id,
userDetailDomainService.hashPassword(registerLocalActor.password),
)
userDetailRepository.save(userDetail)
}
}
}

View File

@ -0,0 +1,28 @@
/*
* 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.usecase.actor
import dev.usbharu.hideout.core.domain.model.actor.Actor2Repository
import dev.usbharu.hideout.core.domain.model.actor.ActorId
class SuspendLocalActorApplicationService(private val actor2Repository: Actor2Repository) {
suspend fun suspend(actorId: Long, executor: ActorId) {
val findById = actor2Repository.findById(ActorId(actorId))!!
findById.suspend = true
}
}

View File

@ -0,0 +1,23 @@
/*
* 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.usecase.actor
import dev.usbharu.hideout.core.domain.model.actor.ActorId
interface UnsuspendLocalActorApplicationService {
suspend fun unsuspend(actorId: ActorId, executor: ActorId)
}

View File

@ -0,0 +1,30 @@
/*
* 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.usecase.post
import dev.usbharu.hideout.core.domain.model.post.Post2Repository
import dev.usbharu.hideout.core.domain.model.post.PostId
import org.springframework.stereotype.Service
@Service
class DeleteLocalPostApplicationService(private val postRepository: Post2Repository) {
suspend fun delete(postId: Long) {
val findById = postRepository.findById(PostId(postId))!!
findById.delete()
postRepository.save(findById)
}
}

View File

@ -0,0 +1,30 @@
/*
* 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.usecase.post
import dev.usbharu.hideout.core.domain.model.post.Visibility
data class RegisterLocalPost(
val actorId: Long,
val content: String,
val overview: String,
val visibility: Visibility,
val repostId: Long?,
val replyId: Long?,
val sensitive: Boolean,
val mediaIds: List<Long>,
)

View File

@ -0,0 +1,51 @@
/*
* 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.usecase.post
import dev.usbharu.hideout.core.domain.model.actor.Actor2Repository
import dev.usbharu.hideout.core.domain.model.actor.ActorId
import dev.usbharu.hideout.core.domain.model.media.MediaId
import dev.usbharu.hideout.core.domain.model.post.Post2Repository
import dev.usbharu.hideout.core.domain.model.post.PostId
import dev.usbharu.hideout.core.domain.model.post.PostOverview
import dev.usbharu.hideout.core.infrastructure.factory.PostFactoryImpl
import org.springframework.stereotype.Service
@Service
class RegisterLocalPostApplicationService(
private val postFactory: PostFactoryImpl,
private val actor2Repository: Actor2Repository,
private val postRepository: Post2Repository,
) {
suspend fun register(registerLocalPost: RegisterLocalPost) {
val actorId = ActorId(registerLocalPost.actorId)
val post = postFactory.createLocal(
actorId,
actor2Repository.findById(actorId)!!.name,
PostOverview(registerLocalPost.overview),
registerLocalPost.content,
registerLocalPost.visibility,
registerLocalPost.repostId?.let { PostId(it) },
registerLocalPost.replyId?.let { PostId(it) },
registerLocalPost.sensitive,
registerLocalPost.mediaIds.map { MediaId(it) }
)
postRepository.save(post)
}
}

View File

@ -0,0 +1,25 @@
/*
* 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.usecase.post
data class UpdateLocalNote(
val postId: Long,
val overview: String?,
val content: String,
val sensitive: Boolean,
val mediaIds: List<Long>,
)

View File

@ -0,0 +1,45 @@
/*
* 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.usecase.post
import dev.usbharu.hideout.application.external.Transaction
import dev.usbharu.hideout.core.domain.model.media.MediaId
import dev.usbharu.hideout.core.domain.model.post.Post2Repository
import dev.usbharu.hideout.core.domain.model.post.PostId
import dev.usbharu.hideout.core.domain.model.post.PostOverview
import dev.usbharu.hideout.core.infrastructure.factory.PostContentFactoryImpl
import org.springframework.stereotype.Service
@Service
class UpdateLocalNoteApplicationService(
private val transaction: Transaction,
private val postRepository: Post2Repository,
private val postContentFactoryImpl: PostContentFactoryImpl,
) {
suspend fun update(updateLocalNote: UpdateLocalNote) {
transaction.transaction {
val post = postRepository.findById(PostId(updateLocalNote.postId))!!
post.content = postContentFactoryImpl.create(updateLocalNote.content)
post.overview = updateLocalNote.overview?.let { PostOverview(it) }
post.mediaIds = updateLocalNote.mediaIds.map { MediaId(it) }
post.sensitive = updateLocalNote.sensitive
postRepository.save(post)
}
}
}