mirror of https://github.com/usbharu/Hideout.git
Compare commits
7 Commits
873982d4e7
...
e8050699ee
| Author | SHA1 | Date |
|---|---|---|
|
|
e8050699ee | |
|
|
bd18985894 | |
|
|
6c3088bc28 | |
|
|
a83eb02258 | |
|
|
1435dbadc7 | |
|
|
18410cfdee | |
|
|
a373c0d880 |
|
|
@ -1,6 +1,6 @@
|
|||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||
import org.openapitools.generator.gradle.plugin.tasks.GenerateTask
|
||||
import kotlin.math.min
|
||||
import kotlin.math.max
|
||||
|
||||
val ktor_version: String by project
|
||||
val kotlin_version: String by project
|
||||
|
|
@ -29,7 +29,7 @@ version = "0.0.1"
|
|||
tasks.withType<Test> {
|
||||
useJUnitPlatform()
|
||||
val cpus = Runtime.getRuntime().availableProcessors()
|
||||
maxParallelForks = min(1, cpus - 1)
|
||||
maxParallelForks = max(1, cpus - 1)
|
||||
setForkEvery(4)
|
||||
}
|
||||
|
||||
|
|
@ -68,9 +68,6 @@ tasks.create<GenerateTask>("openApiGenerateMastodonCompatibleApi", GenerateTask:
|
|||
"dev.usbharu.hideout.domain.model.mastodon.StatusesRequest"
|
||||
)
|
||||
templateDir.set("$rootDir/templates")
|
||||
globalProperties.put("debugModels", "true")
|
||||
globalProperties.put("debugOpenAPI", "true")
|
||||
globalProperties.put("debugOperations", "true")
|
||||
}
|
||||
|
||||
repositories {
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ class JsonOrFormModelMethodProcessor(
|
|||
webRequest: NativeWebRequest,
|
||||
binderFactory: WebDataBinderFactory?
|
||||
): Any? {
|
||||
|
||||
val contentType = webRequest.getHeader("Content-Type").orEmpty()
|
||||
logger.trace("ContentType is {}", contentType)
|
||||
if (contentType.contains(isJsonRegex)) {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ class MvcConfigurer(private val jsonOrFormModelMethodProcessor: JsonOrFormModelM
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
class JsonOrFormModelMethodProcessorConfig {
|
||||
@Bean
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import org.springframework.context.annotation.Configuration
|
|||
import org.springframework.web.filter.CommonsRequestLoggingFilter
|
||||
import java.net.URL
|
||||
|
||||
|
||||
@Configuration
|
||||
class SpringConfig {
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ class Document : Object {
|
|||
this.url = url
|
||||
}
|
||||
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other !is Document) return false
|
||||
|
|
@ -43,6 +42,4 @@ class Document : Object {
|
|||
override fun toString(): String {
|
||||
return "Document(mediaType=$mediaType, url=$url) ${super.toString()}"
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@ open class Note : Object {
|
|||
this.attachment = attachment
|
||||
}
|
||||
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other !is Note) return false
|
||||
|
|
@ -74,6 +73,4 @@ open class Note : Object {
|
|||
override fun toString(): String {
|
||||
return "Note(attributedTo=$attributedTo, attachment=$attachment, content=$content, published=$published, to=$to, cc=$cc, sensitive=$sensitive, inReplyTo=$inReplyTo) ${super.toString()}"
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,31 +1,38 @@
|
|||
package dev.usbharu.hideout.domain.model.mastodon
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import dev.usbharu.hideout.domain.mastodon.model.generated.StatusesRequest
|
||||
import dev.usbharu.hideout.domain.mastodon.model.generated.StatusesRequestPoll
|
||||
|
||||
class StatusesRequest {
|
||||
@JsonProperty("status")
|
||||
var status: String? = null
|
||||
|
||||
@JsonProperty("media_ids")
|
||||
var media_ids: List<String> = emptyList()
|
||||
|
||||
@JsonProperty("poll")
|
||||
var poll: StatusesRequestPoll? = null
|
||||
|
||||
@JsonProperty("in_reply_to_id")
|
||||
var in_reply_to_id: String? = null
|
||||
|
||||
@JsonProperty("sensitive")
|
||||
var sensitive: Boolean? = null
|
||||
|
||||
@JsonProperty("spoiler_text")
|
||||
var spoiler_text: String? = null
|
||||
|
||||
@JsonProperty("visibility")
|
||||
var visibility: StatusesRequest.Visibility? = null
|
||||
var visibility: Visibility? = null
|
||||
|
||||
@JsonProperty("language")
|
||||
var language: String? = null
|
||||
|
||||
@JsonProperty("scheduled_at")
|
||||
var scheduled_at: String? = null
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other !is dev.usbharu.hideout.domain.model.mastodon.StatusesRequest) return false
|
||||
if (other !is StatusesRequest) return false
|
||||
|
||||
if (status != other.status) return false
|
||||
if (media_ids != other.media_ids) return false
|
||||
|
|
@ -40,7 +47,6 @@ class StatusesRequest {
|
|||
return true
|
||||
}
|
||||
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = status?.hashCode() ?: 0
|
||||
result = 31 * result + media_ids.hashCode()
|
||||
|
|
@ -58,5 +64,10 @@ class StatusesRequest {
|
|||
return "StatusesRequest(status=$status, mediaIds=$media_ids, poll=$poll, inReplyToId=$in_reply_to_id, sensitive=$sensitive, spoilerText=$spoiler_text, visibility=$visibility, language=$language, scheduledAt=$scheduled_at)"
|
||||
}
|
||||
|
||||
|
||||
enum class Visibility {
|
||||
`public`,
|
||||
unlisted,
|
||||
private,
|
||||
direct;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@ class StatusQueryServiceImpl : StatusQueryService {
|
|||
return resolveReplyAndRepost(pairs)
|
||||
}
|
||||
|
||||
|
||||
private fun resolveReplyAndRepost(pairs: List<Pair<Status, Long?>>): List<Status> {
|
||||
val statuses = pairs.map { it.first }
|
||||
return pairs
|
||||
|
|
@ -56,25 +55,27 @@ class StatusQueryServiceImpl : StatusQueryService {
|
|||
.groupBy { it[Posts.id] }
|
||||
.map { it.value }
|
||||
.map {
|
||||
toStatus(it.first()).copy(mediaAttachments = it.map {
|
||||
it.toMedia().let {
|
||||
MediaAttachment(
|
||||
it.id.toString(),
|
||||
when (it.type) {
|
||||
FileType.Image -> MediaAttachment.Type.image
|
||||
FileType.Video -> MediaAttachment.Type.video
|
||||
FileType.Audio -> MediaAttachment.Type.audio
|
||||
FileType.Unknown -> MediaAttachment.Type.unknown
|
||||
},
|
||||
it.url,
|
||||
it.thumbnailUrl,
|
||||
it.remoteUrl,
|
||||
"",
|
||||
it.blurHash,
|
||||
it.url
|
||||
)
|
||||
toStatus(it.first()).copy(
|
||||
mediaAttachments = it.map {
|
||||
it.toMedia().let {
|
||||
MediaAttachment(
|
||||
it.id.toString(),
|
||||
when (it.type) {
|
||||
FileType.Image -> MediaAttachment.Type.image
|
||||
FileType.Video -> MediaAttachment.Type.video
|
||||
FileType.Audio -> MediaAttachment.Type.audio
|
||||
FileType.Unknown -> MediaAttachment.Type.unknown
|
||||
},
|
||||
it.url,
|
||||
it.thumbnailUrl,
|
||||
it.remoteUrl,
|
||||
"",
|
||||
it.blurHash,
|
||||
it.url
|
||||
)
|
||||
}
|
||||
}
|
||||
}) to it.first()[Posts.repostId]
|
||||
) to it.first()[Posts.repostId]
|
||||
}
|
||||
return resolveReplyAndRepost(pairs)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -90,7 +90,6 @@ object PostsMedia : Table() {
|
|||
override val primaryKey = PrimaryKey(postId, mediaId)
|
||||
}
|
||||
|
||||
|
||||
fun ResultRow.toPost(): Post {
|
||||
return Post.of(
|
||||
id = this[Posts.id],
|
||||
|
|
|
|||
|
|
@ -80,7 +80,9 @@ class APNoteServiceImpl(
|
|||
val actor = props[DeliverPostJob.actor]
|
||||
val postEntity = objectMapper.readValue<Post>(props[DeliverPostJob.post])
|
||||
val mediaList =
|
||||
objectMapper.readValue<List<dev.usbharu.hideout.domain.model.hideout.entity.Media>>(props[DeliverPostJob.media])
|
||||
objectMapper.readValue<List<dev.usbharu.hideout.domain.model.hideout.entity.Media>>(
|
||||
props[DeliverPostJob.media]
|
||||
)
|
||||
val note = Note(
|
||||
name = "Note",
|
||||
id = postEntity.url,
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@ package dev.usbharu.hideout.service.api.mastodon
|
|||
|
||||
import dev.usbharu.hideout.domain.mastodon.model.generated.MediaAttachment
|
||||
import dev.usbharu.hideout.domain.mastodon.model.generated.Status
|
||||
import dev.usbharu.hideout.domain.mastodon.model.generated.StatusesRequest
|
||||
import dev.usbharu.hideout.domain.model.hideout.dto.FileType
|
||||
import dev.usbharu.hideout.domain.model.hideout.dto.PostCreateDto
|
||||
import dev.usbharu.hideout.domain.model.hideout.entity.Visibility
|
||||
import dev.usbharu.hideout.domain.model.mastodon.StatusesRequest
|
||||
import dev.usbharu.hideout.exception.FailedToGetResourcesException
|
||||
import dev.usbharu.hideout.query.PostQueryService
|
||||
import dev.usbharu.hideout.query.UserQueryService
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import dev.usbharu.hideout.domain.model.hideout.entity.User
|
|||
import dev.usbharu.hideout.domain.model.hideout.entity.Visibility
|
||||
import dev.usbharu.hideout.domain.model.job.DeliverPostJob
|
||||
import dev.usbharu.hideout.query.FollowerQueryService
|
||||
import dev.usbharu.hideout.query.MediaQueryService
|
||||
import dev.usbharu.hideout.query.UserQueryService
|
||||
import dev.usbharu.hideout.service.job.JobQueueParentService
|
||||
import io.ktor.client.*
|
||||
|
|
@ -19,6 +20,7 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
|
|||
import kotlinx.coroutines.test.runTest
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.mockito.Mockito.anyLong
|
||||
import org.mockito.Mockito.eq
|
||||
import org.mockito.kotlin.*
|
||||
import utils.JsonObjectMapper
|
||||
|
|
@ -29,118 +31,131 @@ import kotlin.test.assertEquals
|
|||
|
||||
class APNoteServiceImplTest {
|
||||
@Test
|
||||
fun `createPost 新しい投稿`() = runTest {
|
||||
val followers = listOf(
|
||||
User.of(
|
||||
2L,
|
||||
"follower",
|
||||
"follower.example.com",
|
||||
"followerUser",
|
||||
"test follower user",
|
||||
"https://follower.example.com/inbox",
|
||||
"https://follower.example.com/outbox",
|
||||
"https://follower.example.com",
|
||||
"https://follower.example.com",
|
||||
publicKey = "",
|
||||
createdAt = Instant.now()
|
||||
),
|
||||
User.of(
|
||||
3L,
|
||||
"follower2",
|
||||
"follower2.example.com",
|
||||
"follower2User",
|
||||
"test follower2 user",
|
||||
"https://follower2.example.com/inbox",
|
||||
"https://follower2.example.com/outbox",
|
||||
"https://follower2.example.com",
|
||||
"https://follower2.example.com",
|
||||
publicKey = "",
|
||||
createdAt = Instant.now()
|
||||
fun `createPost 新しい投稿`() {
|
||||
val mediaQueryService = mock<MediaQueryService> {
|
||||
onBlocking { findByPostId(anyLong()) } doReturn emptyList()
|
||||
}
|
||||
runTest {
|
||||
val followers = listOf(
|
||||
User.of(
|
||||
2L,
|
||||
"follower",
|
||||
"follower.example.com",
|
||||
"followerUser",
|
||||
"test follower user",
|
||||
"https://follower.example.com/inbox",
|
||||
"https://follower.example.com/outbox",
|
||||
"https://follower.example.com",
|
||||
"https://follower.example.com",
|
||||
publicKey = "",
|
||||
createdAt = Instant.now()
|
||||
),
|
||||
User.of(
|
||||
3L,
|
||||
"follower2",
|
||||
"follower2.example.com",
|
||||
"follower2User",
|
||||
"test follower2 user",
|
||||
"https://follower2.example.com/inbox",
|
||||
"https://follower2.example.com/outbox",
|
||||
"https://follower2.example.com",
|
||||
"https://follower2.example.com",
|
||||
publicKey = "",
|
||||
createdAt = Instant.now()
|
||||
)
|
||||
)
|
||||
)
|
||||
val userQueryService = mock<UserQueryService> {
|
||||
onBlocking { findById(eq(1L)) } doReturn User.of(
|
||||
val userQueryService = mock<UserQueryService> {
|
||||
onBlocking { findById(eq(1L)) } doReturn User.of(
|
||||
1L,
|
||||
"test",
|
||||
"example.com",
|
||||
"testUser",
|
||||
"test user",
|
||||
"a",
|
||||
"https://example.com/inbox",
|
||||
"https://example.com/outbox",
|
||||
"https://example.com",
|
||||
publicKey = "",
|
||||
privateKey = "a",
|
||||
createdAt = Instant.now()
|
||||
)
|
||||
}
|
||||
val followerQueryService = mock<FollowerQueryService> {
|
||||
onBlocking { findFollowersById(eq(1L)) } doReturn followers
|
||||
}
|
||||
val jobQueueParentService = mock<JobQueueParentService>()
|
||||
val activityPubNoteService =
|
||||
APNoteServiceImpl(
|
||||
httpClient = mock(),
|
||||
jobQueueParentService = jobQueueParentService,
|
||||
postRepository = mock(),
|
||||
apUserService = mock(),
|
||||
userQueryService = userQueryService,
|
||||
followerQueryService = followerQueryService,
|
||||
postQueryService = mock(),
|
||||
objectMapper = objectMapper,
|
||||
applicationConfig = testApplicationConfig,
|
||||
postService = mock(),
|
||||
mediaQueryService = mediaQueryService
|
||||
)
|
||||
val postEntity = Post.of(
|
||||
1L,
|
||||
"test",
|
||||
"example.com",
|
||||
"testUser",
|
||||
"test user",
|
||||
"a",
|
||||
"https://example.com/inbox",
|
||||
"https://example.com/outbox",
|
||||
"https://example.com",
|
||||
publicKey = "",
|
||||
privateKey = "a",
|
||||
createdAt = Instant.now()
|
||||
1L,
|
||||
null,
|
||||
"test text",
|
||||
1L,
|
||||
Visibility.PUBLIC,
|
||||
"https://example.com"
|
||||
)
|
||||
activityPubNoteService.createNote(postEntity)
|
||||
verify(jobQueueParentService, times(2)).schedule(eq(DeliverPostJob), any())
|
||||
}
|
||||
val followerQueryService = mock<FollowerQueryService> {
|
||||
onBlocking { findFollowersById(eq(1L)) } doReturn followers
|
||||
}
|
||||
val jobQueueParentService = mock<JobQueueParentService>()
|
||||
val activityPubNoteService =
|
||||
APNoteServiceImpl(
|
||||
httpClient = mock(),
|
||||
jobQueueParentService = jobQueueParentService,
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `createPostJob 新しい投稿のJob`() {
|
||||
runTest {
|
||||
val mediaQueryService = mock<MediaQueryService> {
|
||||
onBlocking { findByPostId(anyLong()) } doReturn emptyList()
|
||||
}
|
||||
Config.configData = ConfigData(objectMapper = JsonObjectMapper.objectMapper)
|
||||
val httpClient = HttpClient(
|
||||
MockEngine { httpRequestData ->
|
||||
assertEquals("https://follower.example.com/inbox", httpRequestData.url.toString())
|
||||
respondOk()
|
||||
}
|
||||
)
|
||||
val activityPubNoteService = APNoteServiceImpl(
|
||||
httpClient = httpClient,
|
||||
jobQueueParentService = mock(),
|
||||
postRepository = mock(),
|
||||
apUserService = mock(),
|
||||
userQueryService = userQueryService,
|
||||
followerQueryService = followerQueryService,
|
||||
userQueryService = mock(),
|
||||
followerQueryService = mock(),
|
||||
postQueryService = mock(),
|
||||
objectMapper = objectMapper,
|
||||
applicationConfig = testApplicationConfig,
|
||||
postService = mock(),
|
||||
mediaQueryService = mediaQueryService
|
||||
)
|
||||
val postEntity = Post.of(
|
||||
1L,
|
||||
1L,
|
||||
null,
|
||||
"test text",
|
||||
1L,
|
||||
Visibility.PUBLIC,
|
||||
"https://example.com"
|
||||
)
|
||||
activityPubNoteService.createNote(postEntity)
|
||||
verify(jobQueueParentService, times(2)).schedule(eq(DeliverPostJob), any())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `createPostJob 新しい投稿のJob`() = runTest {
|
||||
Config.configData = ConfigData(objectMapper = JsonObjectMapper.objectMapper)
|
||||
val httpClient = HttpClient(
|
||||
MockEngine { httpRequestData ->
|
||||
assertEquals("https://follower.example.com/inbox", httpRequestData.url.toString())
|
||||
respondOk()
|
||||
}
|
||||
)
|
||||
val activityPubNoteService = APNoteServiceImpl(
|
||||
httpClient = httpClient,
|
||||
jobQueueParentService = mock(),
|
||||
postRepository = mock(),
|
||||
apUserService = mock(),
|
||||
userQueryService = mock(),
|
||||
followerQueryService = mock(),
|
||||
postQueryService = mock(),
|
||||
objectMapper = objectMapper,
|
||||
applicationConfig = testApplicationConfig,
|
||||
postService = mock(),
|
||||
)
|
||||
activityPubNoteService.createNoteJob(
|
||||
JobProps(
|
||||
data = mapOf<String, Any>(
|
||||
DeliverPostJob.actor.name to "https://follower.example.com",
|
||||
DeliverPostJob.post.name to """{
|
||||
"id": 1,
|
||||
"userId": 1,
|
||||
"text": "test text",
|
||||
"createdAt": 132525324,
|
||||
"visibility": 0,
|
||||
"url": "https://example.com"
|
||||
}""",
|
||||
DeliverPostJob.inbox.name to "https://follower.example.com/inbox"
|
||||
),
|
||||
json = Json
|
||||
activityPubNoteService.createNoteJob(
|
||||
JobProps(
|
||||
data = mapOf<String, Any>(
|
||||
DeliverPostJob.actor.name to "https://follower.example.com",
|
||||
DeliverPostJob.post.name to """{
|
||||
"id": 1,
|
||||
"userId": 1,
|
||||
"text": "test text",
|
||||
"createdAt": 132525324,
|
||||
"visibility": 0,
|
||||
"url": "https://example.com"
|
||||
}""",
|
||||
DeliverPostJob.inbox.name to "https://follower.example.com/inbox",
|
||||
DeliverPostJob.media.name to "[]"
|
||||
),
|
||||
json = Json
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue