mirror of https://github.com/usbharu/Hideout.git
commit
9a12c10f3a
|
@ -0,0 +1,146 @@
|
||||||
|
package mastodon.account
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.type.TypeReference
|
||||||
|
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
||||||
|
import dev.usbharu.hideout.SpringApplication
|
||||||
|
import dev.usbharu.hideout.domain.mastodon.model.generated.Notification
|
||||||
|
import dev.usbharu.hideout.domain.mastodon.model.generated.Status
|
||||||
|
import org.assertj.core.api.Assertions
|
||||||
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
|
import org.flywaydb.core.Flyway
|
||||||
|
import org.junit.jupiter.api.AfterAll
|
||||||
|
import org.junit.jupiter.api.BeforeEach
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
|
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest
|
||||||
|
import org.springframework.security.core.authority.SimpleGrantedAuthority
|
||||||
|
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors
|
||||||
|
import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers
|
||||||
|
import org.springframework.test.context.jdbc.Sql
|
||||||
|
import org.springframework.test.web.servlet.MockMvc
|
||||||
|
import org.springframework.test.web.servlet.get
|
||||||
|
import org.springframework.test.web.servlet.setup.DefaultMockMvcBuilder
|
||||||
|
import org.springframework.test.web.servlet.setup.MockMvcBuilders
|
||||||
|
import org.springframework.transaction.annotation.Transactional
|
||||||
|
import org.springframework.web.context.WebApplicationContext
|
||||||
|
|
||||||
|
@SpringBootTest(classes = [SpringApplication::class])
|
||||||
|
@AutoConfigureMockMvc
|
||||||
|
@Transactional
|
||||||
|
@Sql("/sql/test-user.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_CLASS)
|
||||||
|
@Sql("/sql/test-user2.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_CLASS)
|
||||||
|
@Sql("/sql/accounts/test-accounts-statuses.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_CLASS)
|
||||||
|
class AccountApiPaginationTest {
|
||||||
|
@Autowired
|
||||||
|
private lateinit var context: WebApplicationContext
|
||||||
|
|
||||||
|
private lateinit var mockMvc: MockMvc
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `apiV1AccountsIdStatusesGet 投稿を取得できる`() {
|
||||||
|
val content = mockMvc
|
||||||
|
.get("/api/v1/accounts/1/statuses"){
|
||||||
|
with(
|
||||||
|
SecurityMockMvcRequestPostProcessors.jwt()
|
||||||
|
.jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read"))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.asyncDispatch()
|
||||||
|
.andExpect { status { isOk() } }
|
||||||
|
.andExpect { header { string("Link","<https://example.com/api/v1/accounts/1/statuses?min_id=100>; rel=\"next\", <https://example.com/api/v1/accounts/1/statuses?max_id=81>; rel=\"prev\"") } }
|
||||||
|
.andReturn()
|
||||||
|
.response
|
||||||
|
.contentAsString
|
||||||
|
|
||||||
|
val value = jacksonObjectMapper().readValue(content, object : TypeReference<List<Status>>() {})
|
||||||
|
|
||||||
|
assertThat(value.first().id).isEqualTo("100")
|
||||||
|
assertThat(value.last().id).isEqualTo("81")
|
||||||
|
assertThat(value).size().isEqualTo(20)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `apiV1AccountsIdStatusesGet 結果が0件のときはLinkヘッダーがない`() {
|
||||||
|
val content = mockMvc
|
||||||
|
.get("/api/v1/accounts/1/statuses?min_id=100"){
|
||||||
|
with(
|
||||||
|
SecurityMockMvcRequestPostProcessors.jwt()
|
||||||
|
.jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read"))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.asyncDispatch()
|
||||||
|
.andExpect { status { isOk() } }
|
||||||
|
.andExpect { header { doesNotExist("Link") } }
|
||||||
|
.andReturn()
|
||||||
|
.response
|
||||||
|
.contentAsString
|
||||||
|
|
||||||
|
val value = jacksonObjectMapper().readValue(content, object : TypeReference<List<Status>>() {})
|
||||||
|
|
||||||
|
|
||||||
|
assertThat(value).isEmpty()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `apiV1AccountsIdStatusesGet maxIdを指定して取得`() {
|
||||||
|
val content = mockMvc
|
||||||
|
.get("/api/v1/accounts/1/statuses?max_id=100"){
|
||||||
|
with(
|
||||||
|
SecurityMockMvcRequestPostProcessors.jwt()
|
||||||
|
.jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read"))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.asyncDispatch()
|
||||||
|
.andExpect { status { isOk() } }
|
||||||
|
.andExpect { header { string("Link","<https://example.com/api/v1/accounts/1/statuses?min_id=99>; rel=\"next\", <https://example.com/api/v1/accounts/1/statuses?max_id=80>; rel=\"prev\"") } }
|
||||||
|
.andReturn()
|
||||||
|
.response
|
||||||
|
.contentAsString
|
||||||
|
|
||||||
|
val value = jacksonObjectMapper().readValue(content, object : TypeReference<List<Status>>() {})
|
||||||
|
|
||||||
|
assertThat(value.first().id).isEqualTo("99")
|
||||||
|
assertThat(value.last().id).isEqualTo("80")
|
||||||
|
assertThat(value).size().isEqualTo(20)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `apiV1AccountsIdStatusesGet minIdを指定して取得`() {
|
||||||
|
val content = mockMvc
|
||||||
|
.get("/api/v1/accounts/1/statuses?min_id=1"){
|
||||||
|
with(
|
||||||
|
SecurityMockMvcRequestPostProcessors.jwt()
|
||||||
|
.jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read"))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.asyncDispatch()
|
||||||
|
.andExpect { status { isOk() } }
|
||||||
|
.andExpect { header { string("Link","<https://example.com/api/v1/accounts/1/statuses?min_id=21>; rel=\"next\", <https://example.com/api/v1/accounts/1/statuses?max_id=2>; rel=\"prev\"") } }
|
||||||
|
.andReturn()
|
||||||
|
.response
|
||||||
|
.contentAsString
|
||||||
|
|
||||||
|
val value = jacksonObjectMapper().readValue(content, object : TypeReference<List<Status>>() {})
|
||||||
|
|
||||||
|
assertThat(value.first().id).isEqualTo("21")
|
||||||
|
assertThat(value.last().id).isEqualTo("2")
|
||||||
|
assertThat(value).size().isEqualTo(20)
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
fun setUp() {
|
||||||
|
mockMvc = MockMvcBuilders.webAppContextSetup(context)
|
||||||
|
.apply<DefaultMockMvcBuilder>(SecurityMockMvcConfigurers.springSecurity())
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@JvmStatic
|
||||||
|
@AfterAll
|
||||||
|
fun dropDatabase(@Autowired flyway: Flyway) {
|
||||||
|
flyway.clean()
|
||||||
|
flyway.migrate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,164 @@
|
||||||
|
package mastodon.notifications
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.type.TypeReference
|
||||||
|
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
||||||
|
import dev.usbharu.hideout.SpringApplication
|
||||||
|
import dev.usbharu.hideout.domain.mastodon.model.generated.Notification
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
|
import org.flywaydb.core.Flyway
|
||||||
|
import org.junit.jupiter.api.AfterAll
|
||||||
|
import org.junit.jupiter.api.BeforeEach
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
|
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest
|
||||||
|
import org.springframework.security.core.authority.SimpleGrantedAuthority
|
||||||
|
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors
|
||||||
|
import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers
|
||||||
|
import org.springframework.test.context.jdbc.Sql
|
||||||
|
import org.springframework.test.web.servlet.MockMvc
|
||||||
|
import org.springframework.test.web.servlet.get
|
||||||
|
import org.springframework.test.web.servlet.setup.DefaultMockMvcBuilder
|
||||||
|
import org.springframework.test.web.servlet.setup.MockMvcBuilders
|
||||||
|
import org.springframework.transaction.annotation.Transactional
|
||||||
|
import org.springframework.web.context.WebApplicationContext
|
||||||
|
|
||||||
|
@SpringBootTest(classes = [SpringApplication::class], properties = ["hideout.use-mongodb=false"])
|
||||||
|
@AutoConfigureMockMvc
|
||||||
|
@Transactional
|
||||||
|
@Sql("/sql/test-user.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_CLASS)
|
||||||
|
@Sql("/sql/test-user2.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_CLASS)
|
||||||
|
@Sql("/sql/notification/test-notifications.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_CLASS)
|
||||||
|
@Sql("/sql/notification/test-mastodon_notifications.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_CLASS)
|
||||||
|
class ExposedNotificationsApiPaginationTest {
|
||||||
|
@Autowired
|
||||||
|
private lateinit var context: WebApplicationContext
|
||||||
|
|
||||||
|
private lateinit var mockMvc: MockMvc
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `通知を取得できる`() = runTest {
|
||||||
|
val content = mockMvc
|
||||||
|
.get("/api/v1/notifications") {
|
||||||
|
with(
|
||||||
|
SecurityMockMvcRequestPostProcessors.jwt()
|
||||||
|
.jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read"))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.asyncDispatch()
|
||||||
|
.andExpect {
|
||||||
|
header {
|
||||||
|
string(
|
||||||
|
"Link",
|
||||||
|
"<https://example.com/api/v1/notifications?min_id=65>; rel=\"next\", <https://example.com/api/v1/notifications?max_id=26>; rel=\"prev\""
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.andReturn()
|
||||||
|
.response
|
||||||
|
.contentAsString
|
||||||
|
|
||||||
|
val value = jacksonObjectMapper().readValue(content, object : TypeReference<List<Notification>>() {})
|
||||||
|
|
||||||
|
assertThat(value.first().id).isEqualTo("65")
|
||||||
|
assertThat(value.last().id).isEqualTo("26")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun maxIdを指定して通知を取得できる() = runTest {
|
||||||
|
val content = mockMvc
|
||||||
|
.get("/api/v1/notifications?max_id=26") {
|
||||||
|
with(
|
||||||
|
SecurityMockMvcRequestPostProcessors.jwt()
|
||||||
|
.jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read"))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.asyncDispatch()
|
||||||
|
.andExpect {
|
||||||
|
header {
|
||||||
|
string(
|
||||||
|
"Link",
|
||||||
|
"<https://example.com/api/v1/notifications?min_id=25>; rel=\"next\", <https://example.com/api/v1/notifications?max_id=1>; rel=\"prev\""
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.andReturn()
|
||||||
|
.response
|
||||||
|
.contentAsString
|
||||||
|
|
||||||
|
val value = jacksonObjectMapper().readValue(content, object : TypeReference<List<Notification>>() {})
|
||||||
|
|
||||||
|
assertThat(value.first().id).isEqualTo("25")
|
||||||
|
assertThat(value.last().id).isEqualTo("1")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun minIdを指定して通知を取得できる() = runTest {
|
||||||
|
val content = mockMvc
|
||||||
|
.get("/api/v1/notifications?min_id=25") {
|
||||||
|
with(
|
||||||
|
SecurityMockMvcRequestPostProcessors.jwt()
|
||||||
|
.jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read"))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.asyncDispatch()
|
||||||
|
.andExpect {
|
||||||
|
header {
|
||||||
|
string(
|
||||||
|
"Link",
|
||||||
|
"<https://example.com/api/v1/notifications?min_id=65>; rel=\"next\", <https://example.com/api/v1/notifications?max_id=26>; rel=\"prev\""
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.andReturn()
|
||||||
|
.response
|
||||||
|
.contentAsString
|
||||||
|
|
||||||
|
val value = jacksonObjectMapper().readValue(content, object : TypeReference<List<Notification>>() {})
|
||||||
|
|
||||||
|
assertThat(value.first().id).isEqualTo("65")
|
||||||
|
assertThat(value.last().id).isEqualTo("26")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun 結果が0件のときはページネーションのヘッダーがない() = runTest {
|
||||||
|
val content = mockMvc
|
||||||
|
.get("/api/v1/notifications?max_id=1") {
|
||||||
|
with(
|
||||||
|
SecurityMockMvcRequestPostProcessors.jwt()
|
||||||
|
.jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read"))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.asyncDispatch()
|
||||||
|
.andExpect {
|
||||||
|
header {
|
||||||
|
doesNotExist("Link")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.andReturn()
|
||||||
|
.response
|
||||||
|
.contentAsString
|
||||||
|
|
||||||
|
val value = jacksonObjectMapper().readValue(content, object : TypeReference<List<Notification>>() {})
|
||||||
|
|
||||||
|
assertThat(value).size().isZero()
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
fun setUp() {
|
||||||
|
mockMvc = MockMvcBuilders.webAppContextSetup(context)
|
||||||
|
.apply<DefaultMockMvcBuilder>(SecurityMockMvcConfigurers.springSecurity())
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@JvmStatic
|
||||||
|
@AfterAll
|
||||||
|
fun dropDatabase(@Autowired flyway: Flyway) {
|
||||||
|
flyway.clean()
|
||||||
|
flyway.migrate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,199 @@
|
||||||
|
package mastodon.notifications
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.type.TypeReference
|
||||||
|
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
||||||
|
import dev.usbharu.hideout.SpringApplication
|
||||||
|
import dev.usbharu.hideout.domain.mastodon.model.generated.Notification
|
||||||
|
import dev.usbharu.hideout.mastodon.domain.model.MastodonNotification
|
||||||
|
import dev.usbharu.hideout.mastodon.domain.model.NotificationType
|
||||||
|
import dev.usbharu.hideout.mastodon.infrastructure.mongorepository.MongoMastodonNotificationRepository
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
|
import org.assertj.core.api.Assertions
|
||||||
|
import org.flywaydb.core.Flyway
|
||||||
|
import org.junit.jupiter.api.AfterAll
|
||||||
|
import org.junit.jupiter.api.BeforeAll
|
||||||
|
import org.junit.jupiter.api.BeforeEach
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
|
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest
|
||||||
|
import org.springframework.data.mongodb.core.MongoTemplate
|
||||||
|
import org.springframework.security.core.authority.SimpleGrantedAuthority
|
||||||
|
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors
|
||||||
|
import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers
|
||||||
|
import org.springframework.test.context.jdbc.Sql
|
||||||
|
import org.springframework.test.web.servlet.MockMvc
|
||||||
|
import org.springframework.test.web.servlet.get
|
||||||
|
import org.springframework.test.web.servlet.setup.DefaultMockMvcBuilder
|
||||||
|
import org.springframework.test.web.servlet.setup.MockMvcBuilders
|
||||||
|
import org.springframework.transaction.annotation.Transactional
|
||||||
|
import org.springframework.web.context.WebApplicationContext
|
||||||
|
import java.time.Instant
|
||||||
|
|
||||||
|
@SpringBootTest(classes = [SpringApplication::class], properties = ["hideout.use-mongodb=true"])
|
||||||
|
@AutoConfigureMockMvc
|
||||||
|
@Transactional
|
||||||
|
@Sql("/sql/test-user.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_CLASS)
|
||||||
|
@Sql("/sql/test-user2.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_CLASS)
|
||||||
|
@Sql("/sql/notification/test-notifications.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_CLASS)
|
||||||
|
class MongodbNotificationsApiPaginationTest {
|
||||||
|
@Autowired
|
||||||
|
private lateinit var context: WebApplicationContext
|
||||||
|
|
||||||
|
private lateinit var mockMvc: MockMvc
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `通知を取得できる`() = runTest {
|
||||||
|
val content = mockMvc
|
||||||
|
.get("/api/v1/notifications") {
|
||||||
|
with(
|
||||||
|
SecurityMockMvcRequestPostProcessors.jwt()
|
||||||
|
.jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read"))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.asyncDispatch()
|
||||||
|
.andDo { print() }
|
||||||
|
.andExpect {
|
||||||
|
header {
|
||||||
|
string(
|
||||||
|
"Link",
|
||||||
|
"<https://example.com/api/v1/notifications?min_id=65>; rel=\"next\", <https://example.com/api/v1/notifications?max_id=26>; rel=\"prev\""
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.andReturn()
|
||||||
|
.response
|
||||||
|
.contentAsString
|
||||||
|
|
||||||
|
val value = jacksonObjectMapper().readValue(content, object : TypeReference<List<Notification>>() {})
|
||||||
|
|
||||||
|
Assertions.assertThat(value.first().id).isEqualTo("65")
|
||||||
|
Assertions.assertThat(value.last().id).isEqualTo("26")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun maxIdを指定して通知を取得できる() = runTest {
|
||||||
|
val content = mockMvc
|
||||||
|
.get("/api/v1/notifications?max_id=26") {
|
||||||
|
with(
|
||||||
|
SecurityMockMvcRequestPostProcessors.jwt()
|
||||||
|
.jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read"))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.asyncDispatch()
|
||||||
|
.andExpect {
|
||||||
|
header {
|
||||||
|
string(
|
||||||
|
"Link",
|
||||||
|
"<https://example.com/api/v1/notifications?min_id=25>; rel=\"next\", <https://example.com/api/v1/notifications?max_id=1>; rel=\"prev\""
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.andReturn()
|
||||||
|
.response
|
||||||
|
.contentAsString
|
||||||
|
|
||||||
|
val value = jacksonObjectMapper().readValue(content, object : TypeReference<List<Notification>>() {})
|
||||||
|
|
||||||
|
Assertions.assertThat(value.first().id).isEqualTo("25")
|
||||||
|
Assertions.assertThat(value.last().id).isEqualTo("1")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun minIdを指定して通知を取得できる() = runTest {
|
||||||
|
val content = mockMvc
|
||||||
|
.get("/api/v1/notifications?min_id=25") {
|
||||||
|
with(
|
||||||
|
SecurityMockMvcRequestPostProcessors.jwt()
|
||||||
|
.jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read"))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.asyncDispatch()
|
||||||
|
.andExpect {
|
||||||
|
header {
|
||||||
|
string(
|
||||||
|
"Link",
|
||||||
|
"<https://example.com/api/v1/notifications?min_id=65>; rel=\"next\", <https://example.com/api/v1/notifications?max_id=26>; rel=\"prev\""
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.andReturn()
|
||||||
|
.response
|
||||||
|
.contentAsString
|
||||||
|
|
||||||
|
val value = jacksonObjectMapper().readValue(content, object : TypeReference<List<Notification>>() {})
|
||||||
|
|
||||||
|
Assertions.assertThat(value.first().id).isEqualTo("65")
|
||||||
|
Assertions.assertThat(value.last().id).isEqualTo("26")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun 結果が0件のときはページネーションのヘッダーがない() = runTest {
|
||||||
|
val content = mockMvc
|
||||||
|
.get("/api/v1/notifications?max_id=1") {
|
||||||
|
with(
|
||||||
|
SecurityMockMvcRequestPostProcessors.jwt()
|
||||||
|
.jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read"))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.asyncDispatch()
|
||||||
|
.andExpect {
|
||||||
|
header {
|
||||||
|
doesNotExist("Link")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.andReturn()
|
||||||
|
.response
|
||||||
|
.contentAsString
|
||||||
|
|
||||||
|
val value = jacksonObjectMapper().readValue(content, object : TypeReference<List<Notification>>() {})
|
||||||
|
|
||||||
|
Assertions.assertThat(value).size().isZero()
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
fun setUp() {
|
||||||
|
mockMvc = MockMvcBuilders.webAppContextSetup(context)
|
||||||
|
.apply<DefaultMockMvcBuilder>(SecurityMockMvcConfigurers.springSecurity())
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@JvmStatic
|
||||||
|
@BeforeAll
|
||||||
|
fun setupMongodb(
|
||||||
|
@Autowired mongoMastodonNotificationRepository: MongoMastodonNotificationRepository
|
||||||
|
) {
|
||||||
|
|
||||||
|
mongoMastodonNotificationRepository.deleteAll()
|
||||||
|
|
||||||
|
val notifications = (1..65).map {
|
||||||
|
MastodonNotification(
|
||||||
|
it.toLong(),
|
||||||
|
1,
|
||||||
|
NotificationType.follow,
|
||||||
|
Instant.now(),
|
||||||
|
2,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
mongoMastodonNotificationRepository.saveAll(notifications)
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
@AfterAll
|
||||||
|
fun dropDatabase(
|
||||||
|
@Autowired flyway: Flyway,
|
||||||
|
@Autowired mongodbMastodonNotificationRepository: MongoMastodonNotificationRepository
|
||||||
|
) {
|
||||||
|
flyway.clean()
|
||||||
|
flyway.migrate()
|
||||||
|
|
||||||
|
mongodbMastodonNotificationRepository.deleteAll()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,7 +24,7 @@ spring:
|
||||||
auto-index-creation: true
|
auto-index-creation: true
|
||||||
host: localhost
|
host: localhost
|
||||||
port: 27017
|
port: 27017
|
||||||
database: hideout
|
database: hideout-integration-test
|
||||||
h2:
|
h2:
|
||||||
console:
|
console:
|
||||||
enabled: true
|
enabled: true
|
||||||
|
|
|
@ -0,0 +1,202 @@
|
||||||
|
insert into posts (id, actor_id, overview, content, text, created_at, visibility, url, repost_id, reply_id, sensitive,
|
||||||
|
ap_id, deleted)
|
||||||
|
VALUES (1, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/1',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/1', false),
|
||||||
|
(2, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/2',
|
||||||
|
null, 1, false, 'https://example.com/users/1/posts/2', false),
|
||||||
|
(3, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 2, 'https://example.com/users/1/posts/3',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/3', false),
|
||||||
|
(4, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/4',
|
||||||
|
null, 3, false, 'https://example.com/users/1/posts/4', false),
|
||||||
|
(5, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/5',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/5', false),
|
||||||
|
(6, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 2, 'https://example.com/users/1/posts/6',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/6', false),
|
||||||
|
(7, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/7',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/7', false),
|
||||||
|
(8, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/8',
|
||||||
|
null, 7, false, 'https://example.com/users/1/posts/8', false),
|
||||||
|
(9, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 2, 'https://example.com/users/1/posts/9',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/9', false),
|
||||||
|
(10, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/10',
|
||||||
|
null, 9, false, 'https://example.com/users/1/posts/10', false),
|
||||||
|
(11, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/11',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/11', false),
|
||||||
|
(12, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 2, 'https://example.com/users/1/posts/12',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/12', false),
|
||||||
|
(13, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/13',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/13', false),
|
||||||
|
(14, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/14',
|
||||||
|
null, 13, false, 'https://example.com/users/1/posts/14', false),
|
||||||
|
(15, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 2, 'https://example.com/users/1/posts/15',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/15', false),
|
||||||
|
(16, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/16',
|
||||||
|
null, 15, false, 'https://example.com/users/1/posts/16', false),
|
||||||
|
(17, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/17',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/17', false),
|
||||||
|
(18, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 2, 'https://example.com/users/1/posts/18',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/18', false),
|
||||||
|
(19, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/19',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/19', false),
|
||||||
|
(20, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/20',
|
||||||
|
null, 19, false, 'https://example.com/users/1/posts/20', false),
|
||||||
|
(21, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 2, 'https://example.com/users/1/posts/21',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/21', false),
|
||||||
|
(22, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/22',
|
||||||
|
null, 21, false, 'https://example.com/users/1/posts/22', false),
|
||||||
|
(23, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/23',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/23', false),
|
||||||
|
(24, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 2, 'https://example.com/users/1/posts/24',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/24', false),
|
||||||
|
(25, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/25',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/25', false),
|
||||||
|
(26, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/26',
|
||||||
|
null, 25, false, 'https://example.com/users/1/posts/26', false),
|
||||||
|
(27, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 2, 'https://example.com/users/1/posts/27',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/27', false),
|
||||||
|
(28, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/28',
|
||||||
|
null, 27, false, 'https://example.com/users/1/posts/28', false),
|
||||||
|
(29, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/29',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/29', false),
|
||||||
|
(30, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 2, 'https://example.com/users/1/posts/30',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/30', false),
|
||||||
|
(31, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/31',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/31', false),
|
||||||
|
(32, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/32',
|
||||||
|
null, 31, false, 'https://example.com/users/1/posts/32', false),
|
||||||
|
(33, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 2, 'https://example.com/users/1/posts/33',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/33', false),
|
||||||
|
(34, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/34',
|
||||||
|
null, 33, false, 'https://example.com/users/1/posts/34', false),
|
||||||
|
(35, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/35',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/35', false),
|
||||||
|
(36, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 2, 'https://example.com/users/1/posts/36',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/36', false),
|
||||||
|
(37, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/37',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/37', false),
|
||||||
|
(38, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/38',
|
||||||
|
null, 37, false, 'https://example.com/users/1/posts/38', false),
|
||||||
|
(39, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 2, 'https://example.com/users/1/posts/39',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/39', false),
|
||||||
|
(40, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/40',
|
||||||
|
null, 39, false, 'https://example.com/users/1/posts/40', false),
|
||||||
|
(41, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/41',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/41', false),
|
||||||
|
(42, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 2, 'https://example.com/users/1/posts/42',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/42', false),
|
||||||
|
(43, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/43',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/43', false),
|
||||||
|
(44, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/44',
|
||||||
|
null, 43, false, 'https://example.com/users/1/posts/44', false),
|
||||||
|
(45, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 2, 'https://example.com/users/1/posts/45',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/45', false),
|
||||||
|
(46, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/46',
|
||||||
|
null, 45, false, 'https://example.com/users/1/posts/46', false),
|
||||||
|
(47, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/47',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/47', false),
|
||||||
|
(48, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 2, 'https://example.com/users/1/posts/48',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/48', false),
|
||||||
|
(49, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/49',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/49', false),
|
||||||
|
(50, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/50',
|
||||||
|
null, 49, false, 'https://example.com/users/1/posts/50', false),
|
||||||
|
(51, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 2, 'https://example.com/users/1/posts/51',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/51', false),
|
||||||
|
(52, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/52',
|
||||||
|
null, 51, false, 'https://example.com/users/1/posts/52', false),
|
||||||
|
(53, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/53',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/53', false),
|
||||||
|
(54, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 2, 'https://example.com/users/1/posts/54',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/54', false),
|
||||||
|
(55, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/55',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/55', false),
|
||||||
|
(56, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/56',
|
||||||
|
null, 55, false, 'https://example.com/users/1/posts/56', false),
|
||||||
|
(57, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 2, 'https://example.com/users/1/posts/57',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/57', false),
|
||||||
|
(58, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/58',
|
||||||
|
null, 57, false, 'https://example.com/users/1/posts/58', false),
|
||||||
|
(59, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/59',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/59', false),
|
||||||
|
(60, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 2, 'https://example.com/users/1/posts/60',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/60', false),
|
||||||
|
(61, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/61',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/61', false),
|
||||||
|
(62, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/62',
|
||||||
|
null, 61, false, 'https://example.com/users/1/posts/62', false),
|
||||||
|
(63, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 2, 'https://example.com/users/1/posts/63',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/63', false),
|
||||||
|
(64, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/64',
|
||||||
|
null, 63, false, 'https://example.com/users/1/posts/64', false),
|
||||||
|
(65, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/65',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/65', false),
|
||||||
|
(66, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 2, 'https://example.com/users/1/posts/66',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/66', false),
|
||||||
|
(67, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/67',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/67', false),
|
||||||
|
(68, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/68',
|
||||||
|
null, 67, false, 'https://example.com/users/1/posts/68', false),
|
||||||
|
(69, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 2, 'https://example.com/users/1/posts/69',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/69', false),
|
||||||
|
(70, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/70',
|
||||||
|
null, 69, false, 'https://example.com/users/1/posts/70', false),
|
||||||
|
(71, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/71',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/71', false),
|
||||||
|
(72, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 2, 'https://example.com/users/1/posts/72',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/72', false),
|
||||||
|
(73, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/73',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/73', false),
|
||||||
|
(74, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/74',
|
||||||
|
null, 73, false, 'https://example.com/users/1/posts/74', false),
|
||||||
|
(75, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 2, 'https://example.com/users/1/posts/75',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/75', false),
|
||||||
|
(76, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/76',
|
||||||
|
null, 75, false, 'https://example.com/users/1/posts/76', false),
|
||||||
|
(77, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/77',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/77', false),
|
||||||
|
(78, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 2, 'https://example.com/users/1/posts/78',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/78', false),
|
||||||
|
(79, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/79',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/79', false),
|
||||||
|
(80, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/80',
|
||||||
|
null, 79, false, 'https://example.com/users/1/posts/80', false),
|
||||||
|
(81, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 2, 'https://example.com/users/1/posts/81',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/81', false),
|
||||||
|
(82, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/82',
|
||||||
|
null, 81, false, 'https://example.com/users/1/posts/82', false),
|
||||||
|
(83, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/83',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/83', false),
|
||||||
|
(84, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 2, 'https://example.com/users/1/posts/84',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/84', false),
|
||||||
|
(85, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/85',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/85', false),
|
||||||
|
(86, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/86',
|
||||||
|
null, 85, false, 'https://example.com/users/1/posts/86', false),
|
||||||
|
(87, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 2, 'https://example.com/users/1/posts/87',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/87', false),
|
||||||
|
(88, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/88',
|
||||||
|
null, 87, false, 'https://example.com/users/1/posts/88', false),
|
||||||
|
(89, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/89',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/89', false),
|
||||||
|
(90, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 2, 'https://example.com/users/1/posts/90',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/90', false),
|
||||||
|
(91, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/91',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/91', false),
|
||||||
|
(92, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/92',
|
||||||
|
null, 91, false, 'https://example.com/users/1/posts/92', false),
|
||||||
|
(93, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 2, 'https://example.com/users/1/posts/93',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/93', false),
|
||||||
|
(94, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/94',
|
||||||
|
null, 93, false, 'https://example.com/users/1/posts/94', false),
|
||||||
|
(95, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/95',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/95', false),
|
||||||
|
(96, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 2, 'https://example.com/users/1/posts/96',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/96', false),
|
||||||
|
(97, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/97',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/97', false),
|
||||||
|
(98, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/98',
|
||||||
|
null, 97, false, 'https://example.com/users/1/posts/98', false),
|
||||||
|
(99, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 2, 'https://example.com/users/1/posts/99',
|
||||||
|
null, null, false, 'https://example.com/users/1/posts/99', false),
|
||||||
|
(100, 1, null, '<p>this is test</p>', 'this is test', 1706684146436, 0, 'https://example.com/users/1/posts/100',
|
||||||
|
null, 99, false, 'https://example.com/users/1/posts/100', false);
|
|
@ -0,0 +1,66 @@
|
||||||
|
insert into mastodon_notifications (id, user_id, type, created_at, account_id, status_id, report_id, relationship_serverance_event_id)
|
||||||
|
values (1, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(2, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(3, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(4, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(5, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(6, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(7, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(8, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(9, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(10, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(11, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(12, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(13, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(14, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(15, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(16, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(17, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(18, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(19, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(20, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(21, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(22, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(23, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(24, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(25, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(26, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(27, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(28, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(29, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(30, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(31, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(32, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(33, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(34, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(35, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(36, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(37, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(38, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(39, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(40, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(41, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(42, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(43, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(44, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(45, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(46, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(47, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(48, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(49, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(50, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(51, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(52, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(53, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(54, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(55, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(56, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(57, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(58, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(59, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(60, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(61, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(62, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(63, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(64, 1, 'follow', current_timestamp, 2, null, null, null),
|
||||||
|
(65, 1, 'follow', current_timestamp, 2, null, null, null);
|
|
@ -0,0 +1,66 @@
|
||||||
|
insert into notifications(id, type, user_id, source_actor_id, post_id, text, reaction_id, created_at)
|
||||||
|
VALUES (1, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(2, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(3, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(4, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(5, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(6, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(7, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(8, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(9, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(10, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(11, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(12, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(13, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(14, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(15, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(16, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(17, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(18, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(19, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(20, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(21, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(22, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(23, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(24, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(25, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(26, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(27, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(28, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(29, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(30, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(31, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(32, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(33, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(34, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(35, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(36, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(37, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(38, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(39, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(40, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(41, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(42, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(43, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(44, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(45, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(46, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(47, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(48, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(49, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(50, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(51, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(52, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(53, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(54, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(55, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(56, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(57, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(58, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(59, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(60, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(61, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(62, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(63, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(64, 'follow', 1, 2, null, null, null, current_timestamp),
|
||||||
|
(65, 'follow', 1, 2, null, null, null, current_timestamp);
|
|
@ -0,0 +1,19 @@
|
||||||
|
package dev.usbharu.hideout.application.infrastructure.exposed
|
||||||
|
|
||||||
|
import org.jetbrains.exposed.sql.*
|
||||||
|
|
||||||
|
fun <S> Query.withPagination(page: Page, exp: ExpressionWithColumnType<S>): PaginationList<ResultRow, S> {
|
||||||
|
page.limit?.let { limit(it) }
|
||||||
|
val resultRows = if (page.minId != null) {
|
||||||
|
page.maxId?.let { andWhere { exp.less(it) } }
|
||||||
|
andWhere { exp.greater(page.minId!!) }
|
||||||
|
reversed()
|
||||||
|
} else {
|
||||||
|
page.maxId?.let { andWhere { exp.less(it) } }
|
||||||
|
page.sinceId?.let { andWhere { exp.greater(it) } }
|
||||||
|
orderBy(exp, SortOrder.DESC)
|
||||||
|
toList()
|
||||||
|
}
|
||||||
|
|
||||||
|
return PaginationList(resultRows, resultRows.firstOrNull()?.getOrNull(exp), resultRows.lastOrNull()?.getOrNull(exp))
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
package dev.usbharu.hideout.application.infrastructure.exposed
|
||||||
|
|
||||||
|
sealed class Page {
|
||||||
|
abstract val maxId: Long?
|
||||||
|
abstract val sinceId: Long?
|
||||||
|
abstract val minId: Long?
|
||||||
|
abstract val limit: Int?
|
||||||
|
|
||||||
|
data class PageByMaxId(
|
||||||
|
override val maxId: Long?,
|
||||||
|
override val sinceId: Long?,
|
||||||
|
override val limit: Int?
|
||||||
|
) : Page() {
|
||||||
|
override val minId: Long? = null
|
||||||
|
}
|
||||||
|
|
||||||
|
data class PageByMinId(
|
||||||
|
override val maxId: Long?,
|
||||||
|
override val minId: Long?,
|
||||||
|
override val limit: Int?
|
||||||
|
) : Page() {
|
||||||
|
override val sinceId: Long? = null
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun of(
|
||||||
|
maxId: Long? = null,
|
||||||
|
sinceId: Long? = null,
|
||||||
|
minId: Long? = null,
|
||||||
|
limit: Int? = null
|
||||||
|
): Page =
|
||||||
|
if (minId != null) {
|
||||||
|
PageByMinId(
|
||||||
|
maxId,
|
||||||
|
minId,
|
||||||
|
limit
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
PageByMaxId(
|
||||||
|
maxId,
|
||||||
|
sinceId,
|
||||||
|
limit
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
package dev.usbharu.hideout.application.infrastructure.exposed
|
||||||
|
|
||||||
|
class PaginationList<T, ID>(list: List<T>, val next: ID?, val prev: ID?) : List<T> by list
|
||||||
|
|
||||||
|
fun <T, ID> PaginationList<T, ID>.toHttpHeader(
|
||||||
|
nextBlock: (string: String) -> String,
|
||||||
|
prevBlock: (string: String) -> String
|
||||||
|
): String? {
|
||||||
|
val mutableListOf = mutableListOf<String>()
|
||||||
|
if (next != null) {
|
||||||
|
mutableListOf.add("<${nextBlock(this.next.toString())}>; rel=\"next\"")
|
||||||
|
}
|
||||||
|
if (prev != null) {
|
||||||
|
mutableListOf.add("<${prevBlock(this.prev.toString())}>; rel=\"prev\"")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mutableListOf.isEmpty()) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return mutableListOf.joinToString(", ")
|
||||||
|
}
|
|
@ -1,5 +1,8 @@
|
||||||
package dev.usbharu.hideout.core.domain.model.relationship
|
package dev.usbharu.hideout.core.domain.model.relationship
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.application.infrastructure.exposed.Page
|
||||||
|
import dev.usbharu.hideout.application.infrastructure.exposed.PaginationList
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [Relationship]の永続化
|
* [Relationship]の永続化
|
||||||
*
|
*
|
||||||
|
@ -33,22 +36,16 @@ interface RelationshipRepository {
|
||||||
|
|
||||||
suspend fun findByTargetIdAndFollowing(targetId: Long, following: Boolean): List<Relationship>
|
suspend fun findByTargetIdAndFollowing(targetId: Long, following: Boolean): List<Relationship>
|
||||||
|
|
||||||
@Suppress("LongParameterList", "FunctionMaxLength")
|
|
||||||
suspend fun findByTargetIdAndFollowRequestAndIgnoreFollowRequest(
|
suspend fun findByTargetIdAndFollowRequestAndIgnoreFollowRequest(
|
||||||
maxId: Long?,
|
|
||||||
sinceId: Long?,
|
|
||||||
limit: Int,
|
|
||||||
targetId: Long,
|
targetId: Long,
|
||||||
followRequest: Boolean,
|
followRequest: Boolean,
|
||||||
ignoreFollowRequest: Boolean
|
ignoreFollowRequest: Boolean,
|
||||||
): List<Relationship>
|
page: Page.PageByMaxId
|
||||||
|
): PaginationList<Relationship, Long>
|
||||||
|
|
||||||
@Suppress("FunctionMaxLength")
|
suspend fun findByActorIdAndMuting(
|
||||||
suspend fun findByActorIdAntMutingAndMaxIdAndSinceId(
|
|
||||||
actorId: Long,
|
actorId: Long,
|
||||||
muting: Boolean,
|
muting: Boolean,
|
||||||
maxId: Long?,
|
page: Page.PageByMaxId
|
||||||
sinceId: Long?,
|
): PaginationList<Relationship, Long>
|
||||||
limit: Int
|
|
||||||
): List<Relationship>
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
package dev.usbharu.hideout.core.domain.model.relationship
|
package dev.usbharu.hideout.core.domain.model.relationship
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.application.infrastructure.exposed.Page
|
||||||
|
import dev.usbharu.hideout.application.infrastructure.exposed.PaginationList
|
||||||
|
import dev.usbharu.hideout.application.infrastructure.exposed.withPagination
|
||||||
import dev.usbharu.hideout.core.infrastructure.exposedrepository.AbstractRepository
|
import dev.usbharu.hideout.core.infrastructure.exposedrepository.AbstractRepository
|
||||||
import dev.usbharu.hideout.core.infrastructure.exposedrepository.Actors
|
import dev.usbharu.hideout.core.infrastructure.exposedrepository.Actors
|
||||||
import org.jetbrains.exposed.dao.id.LongIdTable
|
import org.jetbrains.exposed.dao.id.LongIdTable
|
||||||
|
@ -74,49 +77,41 @@ class RelationshipRepositoryImpl : RelationshipRepository, AbstractRepository()
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun findByTargetIdAndFollowRequestAndIgnoreFollowRequest(
|
override suspend fun findByTargetIdAndFollowRequestAndIgnoreFollowRequest(
|
||||||
maxId: Long?,
|
|
||||||
sinceId: Long?,
|
|
||||||
limit: Int,
|
|
||||||
targetId: Long,
|
targetId: Long,
|
||||||
followRequest: Boolean,
|
followRequest: Boolean,
|
||||||
ignoreFollowRequest: Boolean
|
ignoreFollowRequest: Boolean,
|
||||||
): List<Relationship> = query {
|
page: Page.PageByMaxId
|
||||||
|
): PaginationList<Relationship, Long> = query {
|
||||||
val query = Relationships.select {
|
val query = Relationships.select {
|
||||||
Relationships.targetActorId.eq(targetId).and(Relationships.followRequest.eq(followRequest))
|
Relationships.targetActorId.eq(targetId).and(Relationships.followRequest.eq(followRequest))
|
||||||
.and(Relationships.ignoreFollowRequestFromTarget.eq(ignoreFollowRequest))
|
.and(Relationships.ignoreFollowRequestFromTarget.eq(ignoreFollowRequest))
|
||||||
}.limit(limit)
|
|
||||||
|
|
||||||
if (maxId != null) {
|
|
||||||
query.andWhere { Relationships.id lessEq maxId }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sinceId != null) {
|
val resultRowList = query.withPagination(page, Relationships.id)
|
||||||
query.andWhere { Relationships.id greaterEq sinceId }
|
|
||||||
|
return@query PaginationList(
|
||||||
|
resultRowList.map { it.toRelationships() },
|
||||||
|
resultRowList.next?.value,
|
||||||
|
resultRowList.prev?.value
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return@query query.map { it.toRelationships() }
|
override suspend fun findByActorIdAndMuting(
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun findByActorIdAntMutingAndMaxIdAndSinceId(
|
|
||||||
actorId: Long,
|
actorId: Long,
|
||||||
muting: Boolean,
|
muting: Boolean,
|
||||||
maxId: Long?,
|
page: Page.PageByMaxId
|
||||||
sinceId: Long?,
|
): PaginationList<Relationship, Long> = query {
|
||||||
limit: Int
|
|
||||||
): List<Relationship> = query {
|
|
||||||
val query = Relationships.select {
|
val query = Relationships.select {
|
||||||
Relationships.actorId.eq(actorId).and(Relationships.muting.eq(muting))
|
Relationships.actorId.eq(actorId).and(Relationships.muting.eq(muting))
|
||||||
}.limit(limit)
|
|
||||||
|
|
||||||
if (maxId != null) {
|
|
||||||
query.andWhere { Relationships.id lessEq maxId }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sinceId != null) {
|
val resultRowList = query.withPagination(page, Relationships.id)
|
||||||
query.andWhere { Relationships.id greaterEq sinceId }
|
|
||||||
}
|
|
||||||
|
|
||||||
return@query query.map { it.toRelationships() }
|
return@query PaginationList(
|
||||||
|
resultRowList.map { it.toRelationships() },
|
||||||
|
resultRowList.next?.value,
|
||||||
|
resultRowList.prev?.value
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
package dev.usbharu.hideout.core.service.timeline
|
package dev.usbharu.hideout.core.service.timeline
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.application.infrastructure.exposed.Page
|
||||||
|
import dev.usbharu.hideout.application.infrastructure.exposed.PaginationList
|
||||||
|
import dev.usbharu.hideout.application.infrastructure.exposed.withPagination
|
||||||
import dev.usbharu.hideout.core.infrastructure.exposedrepository.Timelines
|
import dev.usbharu.hideout.core.infrastructure.exposedrepository.Timelines
|
||||||
import dev.usbharu.hideout.domain.mastodon.model.generated.Status
|
import dev.usbharu.hideout.domain.mastodon.model.generated.Status
|
||||||
import dev.usbharu.hideout.mastodon.interfaces.api.status.StatusQuery
|
import dev.usbharu.hideout.mastodon.interfaces.api.status.StatusQuery
|
||||||
import dev.usbharu.hideout.mastodon.query.StatusQueryService
|
import dev.usbharu.hideout.mastodon.query.StatusQueryService
|
||||||
import org.jetbrains.exposed.sql.SortOrder
|
|
||||||
import org.jetbrains.exposed.sql.andWhere
|
import org.jetbrains.exposed.sql.andWhere
|
||||||
import org.jetbrains.exposed.sql.selectAll
|
import org.jetbrains.exposed.sql.selectAll
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
|
||||||
|
@ -13,15 +15,13 @@ import org.springframework.stereotype.Service
|
||||||
@Service
|
@Service
|
||||||
@ConditionalOnProperty("hideout.use-mongodb", havingValue = "false", matchIfMissing = true)
|
@ConditionalOnProperty("hideout.use-mongodb", havingValue = "false", matchIfMissing = true)
|
||||||
class ExposedGenerateTimelineService(private val statusQueryService: StatusQueryService) : GenerateTimelineService {
|
class ExposedGenerateTimelineService(private val statusQueryService: StatusQueryService) : GenerateTimelineService {
|
||||||
|
|
||||||
override suspend fun getTimeline(
|
override suspend fun getTimeline(
|
||||||
forUserId: Long?,
|
forUserId: Long?,
|
||||||
localOnly: Boolean,
|
localOnly: Boolean,
|
||||||
mediaOnly: Boolean,
|
mediaOnly: Boolean,
|
||||||
maxId: Long?,
|
page: Page
|
||||||
minId: Long?,
|
): PaginationList<Status, Long> {
|
||||||
sinceId: Long?,
|
|
||||||
limit: Int
|
|
||||||
): List<Status> {
|
|
||||||
val query = Timelines.selectAll()
|
val query = Timelines.selectAll()
|
||||||
|
|
||||||
if (forUserId != null) {
|
if (forUserId != null) {
|
||||||
|
@ -30,15 +30,7 @@ class ExposedGenerateTimelineService(private val statusQueryService: StatusQuery
|
||||||
if (localOnly) {
|
if (localOnly) {
|
||||||
query.andWhere { Timelines.isLocal eq true }
|
query.andWhere { Timelines.isLocal eq true }
|
||||||
}
|
}
|
||||||
if (maxId != null) {
|
val result = query.withPagination(page, Timelines.id)
|
||||||
query.andWhere { Timelines.id lessEq maxId }
|
|
||||||
}
|
|
||||||
if (minId != null) {
|
|
||||||
query.andWhere { Timelines.id greaterEq minId }
|
|
||||||
}
|
|
||||||
val result = query
|
|
||||||
.limit(limit)
|
|
||||||
.orderBy(Timelines.createdAt, SortOrder.DESC)
|
|
||||||
|
|
||||||
val statusQueries = result.map {
|
val statusQueries = result.map {
|
||||||
StatusQuery(
|
StatusQuery(
|
||||||
|
@ -50,6 +42,11 @@ class ExposedGenerateTimelineService(private val statusQueryService: StatusQuery
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return statusQueryService.findByPostIdsWithMediaIds(statusQueries)
|
val findByPostIdsWithMediaIds = statusQueryService.findByPostIdsWithMediaIds(statusQueries)
|
||||||
|
return PaginationList(
|
||||||
|
findByPostIdsWithMediaIds,
|
||||||
|
findByPostIdsWithMediaIds.lastOrNull()?.id?.toLongOrNull(),
|
||||||
|
findByPostIdsWithMediaIds.firstOrNull()?.id?.toLongOrNull()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
package dev.usbharu.hideout.core.service.timeline
|
package dev.usbharu.hideout.core.service.timeline
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.application.infrastructure.exposed.Page
|
||||||
|
import dev.usbharu.hideout.application.infrastructure.exposed.PaginationList
|
||||||
import dev.usbharu.hideout.domain.mastodon.model.generated.Status
|
import dev.usbharu.hideout.domain.mastodon.model.generated.Status
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@Suppress("LongParameterList")
|
@Suppress("LongParameterList")
|
||||||
interface GenerateTimelineService {
|
interface GenerateTimelineService {
|
||||||
|
|
||||||
suspend fun getTimeline(
|
suspend fun getTimeline(
|
||||||
forUserId: Long? = null,
|
forUserId: Long? = null,
|
||||||
localOnly: Boolean = false,
|
localOnly: Boolean = false,
|
||||||
mediaOnly: Boolean = false,
|
mediaOnly: Boolean = false,
|
||||||
maxId: Long? = null,
|
page: Page
|
||||||
minId: Long? = null,
|
): PaginationList<Status, Long>
|
||||||
sinceId: Long? = null,
|
|
||||||
limit: Int = 20
|
|
||||||
): List<Status>
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package dev.usbharu.hideout.core.service.timeline
|
package dev.usbharu.hideout.core.service.timeline
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.application.infrastructure.exposed.Page
|
||||||
|
import dev.usbharu.hideout.application.infrastructure.exposed.PaginationList
|
||||||
import dev.usbharu.hideout.core.domain.model.timeline.Timeline
|
import dev.usbharu.hideout.core.domain.model.timeline.Timeline
|
||||||
import dev.usbharu.hideout.domain.mastodon.model.generated.Status
|
import dev.usbharu.hideout.domain.mastodon.model.generated.Status
|
||||||
import dev.usbharu.hideout.mastodon.interfaces.api.status.StatusQuery
|
import dev.usbharu.hideout.mastodon.interfaces.api.status.StatusQuery
|
||||||
|
@ -18,15 +20,13 @@ class MongoGenerateTimelineService(
|
||||||
private val mongoTemplate: MongoTemplate
|
private val mongoTemplate: MongoTemplate
|
||||||
) :
|
) :
|
||||||
GenerateTimelineService {
|
GenerateTimelineService {
|
||||||
|
|
||||||
override suspend fun getTimeline(
|
override suspend fun getTimeline(
|
||||||
forUserId: Long?,
|
forUserId: Long?,
|
||||||
localOnly: Boolean,
|
localOnly: Boolean,
|
||||||
mediaOnly: Boolean,
|
mediaOnly: Boolean,
|
||||||
maxId: Long?,
|
page: Page
|
||||||
minId: Long?,
|
): PaginationList<Status, Long> {
|
||||||
sinceId: Long?,
|
|
||||||
limit: Int
|
|
||||||
): List<Status> {
|
|
||||||
val query = Query()
|
val query = Query()
|
||||||
|
|
||||||
if (forUserId != null) {
|
if (forUserId != null) {
|
||||||
|
@ -37,21 +37,23 @@ class MongoGenerateTimelineService(
|
||||||
val criteria = Criteria.where("isLocal").`is`(true)
|
val criteria = Criteria.where("isLocal").`is`(true)
|
||||||
query.addCriteria(criteria)
|
query.addCriteria(criteria)
|
||||||
}
|
}
|
||||||
if (maxId != null) {
|
|
||||||
val criteria = Criteria.where("postId").lt(maxId)
|
if (page.minId != null) {
|
||||||
query.addCriteria(criteria)
|
page.minId?.let { query.addCriteria(Criteria.where("id").gt(it)) }
|
||||||
}
|
page.maxId?.let { query.addCriteria(Criteria.where("id").lt(it)) }
|
||||||
if (minId != null) {
|
} else {
|
||||||
val criteria = Criteria.where("postId").gt(minId)
|
query.with(Sort.by(Sort.Direction.DESC, "createdAt"))
|
||||||
query.addCriteria(criteria)
|
page.sinceId?.let { query.addCriteria(Criteria.where("id").gt(it)) }
|
||||||
|
page.maxId?.let { query.addCriteria(Criteria.where("id").lt(it)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
query.limit(limit)
|
page.limit?.let { query.limit(it) }
|
||||||
|
|
||||||
query.with(Sort.by(Sort.Direction.DESC, "createdAt"))
|
query.with(Sort.by(Sort.Direction.DESC, "createdAt"))
|
||||||
|
|
||||||
val timelines = mongoTemplate.find(query, Timeline::class.java)
|
val timelines = mongoTemplate.find(query, Timeline::class.java)
|
||||||
|
|
||||||
return statusQueryService.findByPostIdsWithMediaIds(
|
val statuses = statusQueryService.findByPostIdsWithMediaIds(
|
||||||
timelines.map {
|
timelines.map {
|
||||||
StatusQuery(
|
StatusQuery(
|
||||||
it.postId,
|
it.postId,
|
||||||
|
@ -62,5 +64,10 @@ class MongoGenerateTimelineService(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
return PaginationList(
|
||||||
|
statuses,
|
||||||
|
statuses.lastOrNull()?.id?.toLongOrNull(),
|
||||||
|
statuses.firstOrNull()?.id?.toLongOrNull()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +1,19 @@
|
||||||
package dev.usbharu.hideout.mastodon.domain.model
|
package dev.usbharu.hideout.mastodon.domain.model
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.application.infrastructure.exposed.Page
|
||||||
|
import dev.usbharu.hideout.application.infrastructure.exposed.PaginationList
|
||||||
|
|
||||||
interface MastodonNotificationRepository {
|
interface MastodonNotificationRepository {
|
||||||
suspend fun save(mastodonNotification: MastodonNotification): MastodonNotification
|
suspend fun save(mastodonNotification: MastodonNotification): MastodonNotification
|
||||||
suspend fun deleteById(id: Long)
|
suspend fun deleteById(id: Long)
|
||||||
suspend fun findById(id: Long): MastodonNotification?
|
suspend fun findById(id: Long): MastodonNotification?
|
||||||
|
|
||||||
@Suppress("LongParameterList", "FunctionMaxLength")
|
suspend fun findByUserIdAndInTypesAndInSourceActorId(
|
||||||
suspend fun findByUserIdAndMaxIdAndMinIdAndSinceIdAndInTypesAndInSourceActorId(
|
|
||||||
loginUser: Long,
|
loginUser: Long,
|
||||||
maxId: Long?,
|
types: List<NotificationType>,
|
||||||
minId: Long?,
|
accountId: List<Long>,
|
||||||
sinceId: Long?,
|
page: Page
|
||||||
limit: Int,
|
): PaginationList<MastodonNotification, Long>
|
||||||
typesTmp: MutableList<NotificationType>,
|
|
||||||
accountId: List<Long>
|
|
||||||
): List<MastodonNotification>
|
|
||||||
|
|
||||||
suspend fun deleteByUserId(userId: Long)
|
suspend fun deleteByUserId(userId: Long)
|
||||||
suspend fun deleteByUserIdAndId(userId: Long, id: Long)
|
suspend fun deleteByUserIdAndId(userId: Long, id: Long)
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
package dev.usbharu.hideout.mastodon.infrastructure.exposedquery
|
package dev.usbharu.hideout.mastodon.infrastructure.exposedquery
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.application.infrastructure.exposed.Page
|
||||||
|
import dev.usbharu.hideout.application.infrastructure.exposed.PaginationList
|
||||||
|
import dev.usbharu.hideout.application.infrastructure.exposed.withPagination
|
||||||
import dev.usbharu.hideout.core.domain.model.emoji.CustomEmoji
|
import dev.usbharu.hideout.core.domain.model.emoji.CustomEmoji
|
||||||
import dev.usbharu.hideout.core.domain.model.media.toMediaAttachments
|
import dev.usbharu.hideout.core.domain.model.media.toMediaAttachments
|
||||||
import dev.usbharu.hideout.core.infrastructure.exposedrepository.*
|
import dev.usbharu.hideout.core.infrastructure.exposedrepository.*
|
||||||
|
@ -54,32 +57,20 @@ class StatusQueryServiceImpl : StatusQueryService {
|
||||||
|
|
||||||
override suspend fun accountsStatus(
|
override suspend fun accountsStatus(
|
||||||
accountId: Long,
|
accountId: Long,
|
||||||
maxId: Long?,
|
|
||||||
sinceId: Long?,
|
|
||||||
minId: Long?,
|
|
||||||
limit: Int,
|
|
||||||
onlyMedia: Boolean,
|
onlyMedia: Boolean,
|
||||||
excludeReplies: Boolean,
|
excludeReplies: Boolean,
|
||||||
excludeReblogs: Boolean,
|
excludeReblogs: Boolean,
|
||||||
pinned: Boolean,
|
pinned: Boolean,
|
||||||
tagged: String?,
|
tagged: String?,
|
||||||
includeFollowers: Boolean
|
includeFollowers: Boolean,
|
||||||
): List<Status> {
|
page: Page
|
||||||
|
): PaginationList<Status, Long> {
|
||||||
val query = Posts
|
val query = Posts
|
||||||
.leftJoin(PostsMedia)
|
.leftJoin(PostsMedia)
|
||||||
.leftJoin(Actors)
|
.leftJoin(Actors)
|
||||||
.leftJoin(Media)
|
.leftJoin(Media)
|
||||||
.select { Posts.actorId eq accountId }.limit(20)
|
.select { Posts.actorId eq accountId }
|
||||||
|
|
||||||
if (maxId != null) {
|
|
||||||
query.andWhere { Posts.id eq maxId }
|
|
||||||
}
|
|
||||||
if (sinceId != null) {
|
|
||||||
query.andWhere { Posts.id eq sinceId }
|
|
||||||
}
|
|
||||||
if (minId != null) {
|
|
||||||
query.andWhere { Posts.id eq minId }
|
|
||||||
}
|
|
||||||
if (onlyMedia) {
|
if (onlyMedia) {
|
||||||
query.andWhere { PostsMedia.mediaId.isNotNull() }
|
query.andWhere { PostsMedia.mediaId.isNotNull() }
|
||||||
}
|
}
|
||||||
|
@ -95,7 +86,9 @@ class StatusQueryServiceImpl : StatusQueryService {
|
||||||
query.andWhere { Posts.visibility inList listOf(public.ordinal, unlisted.ordinal) }
|
query.andWhere { Posts.visibility inList listOf(public.ordinal, unlisted.ordinal) }
|
||||||
}
|
}
|
||||||
|
|
||||||
val pairs = query.groupBy { it[Posts.id] }
|
val pairs = query
|
||||||
|
.withPagination(page, Posts.id)
|
||||||
|
.groupBy { it[Posts.id] }
|
||||||
.map { it.value }
|
.map { it.value }
|
||||||
.map {
|
.map {
|
||||||
toStatus(it.first()).copy(
|
toStatus(it.first()).copy(
|
||||||
|
@ -105,7 +98,12 @@ class StatusQueryServiceImpl : StatusQueryService {
|
||||||
) to it.first()[Posts.repostId]
|
) to it.first()[Posts.repostId]
|
||||||
}
|
}
|
||||||
|
|
||||||
return resolveReplyAndRepost(pairs)
|
val statuses = resolveReplyAndRepost(pairs)
|
||||||
|
return PaginationList(
|
||||||
|
statuses,
|
||||||
|
statuses.firstOrNull()?.id?.toLongOrNull(),
|
||||||
|
statuses.lastOrNull()?.id?.toLongOrNull()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun findByPostId(id: Long): Status {
|
override suspend fun findByPostId(id: Long): Status {
|
||||||
|
@ -139,7 +137,9 @@ class StatusQueryServiceImpl : StatusQueryService {
|
||||||
}
|
}
|
||||||
.map {
|
.map {
|
||||||
if (it.inReplyToId != null) {
|
if (it.inReplyToId != null) {
|
||||||
it.copy(inReplyToAccountId = statuses.find { (id) -> id == it.inReplyToId }?.id)
|
println("statuses trace: $statuses")
|
||||||
|
println("inReplyToId trace: ${it.inReplyToId}")
|
||||||
|
it.copy(inReplyToAccountId = statuses.find { (id) -> id == it.inReplyToId }?.account?.id)
|
||||||
} else {
|
} else {
|
||||||
it
|
it
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
package dev.usbharu.hideout.mastodon.infrastructure.exposedrepository
|
package dev.usbharu.hideout.mastodon.infrastructure.exposedrepository
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.application.infrastructure.exposed.Page
|
||||||
|
import dev.usbharu.hideout.application.infrastructure.exposed.PaginationList
|
||||||
|
import dev.usbharu.hideout.application.infrastructure.exposed.withPagination
|
||||||
import dev.usbharu.hideout.core.infrastructure.exposedrepository.AbstractRepository
|
import dev.usbharu.hideout.core.infrastructure.exposedrepository.AbstractRepository
|
||||||
import dev.usbharu.hideout.core.infrastructure.exposedrepository.Timelines
|
|
||||||
import dev.usbharu.hideout.mastodon.domain.model.MastodonNotification
|
import dev.usbharu.hideout.mastodon.domain.model.MastodonNotification
|
||||||
import dev.usbharu.hideout.mastodon.domain.model.MastodonNotificationRepository
|
import dev.usbharu.hideout.mastodon.domain.model.MastodonNotificationRepository
|
||||||
import dev.usbharu.hideout.mastodon.domain.model.NotificationType
|
import dev.usbharu.hideout.mastodon.domain.model.NotificationType
|
||||||
|
@ -59,33 +61,18 @@ class ExposedMastodonNotificationRepository : MastodonNotificationRepository, Ab
|
||||||
MastodonNotifications.select { MastodonNotifications.id eq id }.singleOrNull()?.toMastodonNotification()
|
MastodonNotifications.select { MastodonNotifications.id eq id }.singleOrNull()?.toMastodonNotification()
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun findByUserIdAndMaxIdAndMinIdAndSinceIdAndInTypesAndInSourceActorId(
|
override suspend fun findByUserIdAndInTypesAndInSourceActorId(
|
||||||
loginUser: Long,
|
loginUser: Long,
|
||||||
maxId: Long?,
|
types: List<NotificationType>,
|
||||||
minId: Long?,
|
accountId: List<Long>,
|
||||||
sinceId: Long?,
|
page: Page
|
||||||
limit: Int,
|
): PaginationList<MastodonNotification, Long> = query {
|
||||||
typesTmp: MutableList<NotificationType>,
|
|
||||||
accountId: List<Long>
|
|
||||||
): List<MastodonNotification> = query {
|
|
||||||
val query = MastodonNotifications.select {
|
val query = MastodonNotifications.select {
|
||||||
MastodonNotifications.userId eq loginUser
|
MastodonNotifications.userId eq loginUser
|
||||||
}
|
}
|
||||||
|
val result = query.withPagination(page, MastodonNotifications.id)
|
||||||
|
|
||||||
if (maxId != null) {
|
return@query PaginationList(result.map { it.toMastodonNotification() }, result.next, result.prev)
|
||||||
query.andWhere { MastodonNotifications.id lessEq maxId }
|
|
||||||
}
|
|
||||||
if (minId != null) {
|
|
||||||
query.andWhere { MastodonNotifications.id greaterEq minId }
|
|
||||||
}
|
|
||||||
if (sinceId != null) {
|
|
||||||
query.andWhere { MastodonNotifications.id greaterEq sinceId }
|
|
||||||
}
|
|
||||||
val result = query
|
|
||||||
.limit(limit)
|
|
||||||
.orderBy(Timelines.createdAt, SortOrder.DESC)
|
|
||||||
|
|
||||||
return@query result.map { it.toMastodonNotification() }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun deleteByUserId(userId: Long) {
|
override suspend fun deleteByUserId(userId: Long) {
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package dev.usbharu.hideout.mastodon.infrastructure.mongorepository
|
package dev.usbharu.hideout.mastodon.infrastructure.mongorepository
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.application.infrastructure.exposed.Page
|
||||||
|
import dev.usbharu.hideout.application.infrastructure.exposed.PaginationList
|
||||||
import dev.usbharu.hideout.mastodon.domain.model.MastodonNotification
|
import dev.usbharu.hideout.mastodon.domain.model.MastodonNotification
|
||||||
import dev.usbharu.hideout.mastodon.domain.model.MastodonNotificationRepository
|
import dev.usbharu.hideout.mastodon.domain.model.MastodonNotificationRepository
|
||||||
import dev.usbharu.hideout.mastodon.domain.model.NotificationType
|
import dev.usbharu.hideout.mastodon.domain.model.NotificationType
|
||||||
|
@ -26,35 +28,33 @@ class MongoMastodonNotificationRepositoryWrapper(
|
||||||
override suspend fun findById(id: Long): MastodonNotification? =
|
override suspend fun findById(id: Long): MastodonNotification? =
|
||||||
mongoMastodonNotificationRepository.findById(id).getOrNull()
|
mongoMastodonNotificationRepository.findById(id).getOrNull()
|
||||||
|
|
||||||
override suspend fun findByUserIdAndMaxIdAndMinIdAndSinceIdAndInTypesAndInSourceActorId(
|
override suspend fun findByUserIdAndInTypesAndInSourceActorId(
|
||||||
loginUser: Long,
|
loginUser: Long,
|
||||||
maxId: Long?,
|
types: List<NotificationType>,
|
||||||
minId: Long?,
|
accountId: List<Long>,
|
||||||
sinceId: Long?,
|
page: Page
|
||||||
limit: Int,
|
): PaginationList<MastodonNotification, Long> {
|
||||||
typesTmp: MutableList<NotificationType>,
|
|
||||||
accountId: List<Long>
|
|
||||||
): List<MastodonNotification> {
|
|
||||||
val query = Query()
|
val query = Query()
|
||||||
|
|
||||||
if (maxId != null) {
|
page.limit?.let { query.limit(it) }
|
||||||
val criteria = Criteria.where("id").lte(maxId)
|
|
||||||
query.addCriteria(criteria)
|
val mastodonNotifications = if (page.minId != null) {
|
||||||
|
query.with(Sort.by(Sort.Direction.ASC, "id"))
|
||||||
|
page.minId?.let { query.addCriteria(Criteria.where("id").gt(it)) }
|
||||||
|
page.maxId?.let { query.addCriteria(Criteria.where("id").lt(it)) }
|
||||||
|
mongoTemplate.find(query, MastodonNotification::class.java).reversed()
|
||||||
|
} else {
|
||||||
|
query.with(Sort.by(Sort.Direction.DESC, "id"))
|
||||||
|
page.sinceId?.let { query.addCriteria(Criteria.where("id").gt(it)) }
|
||||||
|
page.maxId?.let { query.addCriteria(Criteria.where("id").lt(it)) }
|
||||||
|
mongoTemplate.find(query, MastodonNotification::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (minId != null) {
|
return PaginationList(
|
||||||
val criteria = Criteria.where("id").gte(minId)
|
mastodonNotifications,
|
||||||
query.addCriteria(criteria)
|
mastodonNotifications.firstOrNull()?.id,
|
||||||
}
|
mastodonNotifications.lastOrNull()?.id
|
||||||
if (sinceId != null) {
|
)
|
||||||
val criteria = Criteria.where("id").gte(sinceId)
|
|
||||||
query.addCriteria(criteria)
|
|
||||||
}
|
|
||||||
|
|
||||||
query.limit(limit)
|
|
||||||
query.with(Sort.by(Sort.Direction.DESC, "createdAt"))
|
|
||||||
|
|
||||||
return mongoTemplate.find(query, MastodonNotification::class.java)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun deleteByUserId(userId: Long) {
|
override suspend fun deleteByUserId(userId: Long) {
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
package dev.usbharu.hideout.mastodon.interfaces.api.account
|
package dev.usbharu.hideout.mastodon.interfaces.api.account
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.application.config.ApplicationConfig
|
||||||
import dev.usbharu.hideout.application.external.Transaction
|
import dev.usbharu.hideout.application.external.Transaction
|
||||||
|
import dev.usbharu.hideout.application.infrastructure.exposed.Page
|
||||||
|
import dev.usbharu.hideout.application.infrastructure.exposed.toHttpHeader
|
||||||
import dev.usbharu.hideout.controller.mastodon.generated.AccountApi
|
import dev.usbharu.hideout.controller.mastodon.generated.AccountApi
|
||||||
import dev.usbharu.hideout.core.infrastructure.springframework.security.LoginUserContextHolder
|
import dev.usbharu.hideout.core.infrastructure.springframework.security.LoginUserContextHolder
|
||||||
import dev.usbharu.hideout.core.service.user.UserCreateDto
|
import dev.usbharu.hideout.core.service.user.UserCreateDto
|
||||||
|
@ -19,7 +22,8 @@ import java.net.URI
|
||||||
class MastodonAccountApiController(
|
class MastodonAccountApiController(
|
||||||
private val accountApiService: AccountApiService,
|
private val accountApiService: AccountApiService,
|
||||||
private val transaction: Transaction,
|
private val transaction: Transaction,
|
||||||
private val loginUserContextHolder: LoginUserContextHolder
|
private val loginUserContextHolder: LoginUserContextHolder,
|
||||||
|
private val applicationConfig: ApplicationConfig
|
||||||
) : AccountApi {
|
) : AccountApi {
|
||||||
|
|
||||||
override suspend fun apiV1AccountsIdFollowPost(
|
override suspend fun apiV1AccountsIdFollowPost(
|
||||||
|
@ -68,20 +72,31 @@ class MastodonAccountApiController(
|
||||||
tagged: String?
|
tagged: String?
|
||||||
): ResponseEntity<Flow<Status>> = runBlocking {
|
): ResponseEntity<Flow<Status>> = runBlocking {
|
||||||
val userid = loginUserContextHolder.getLoginUserId()
|
val userid = loginUserContextHolder.getLoginUserId()
|
||||||
val statusFlow = accountApiService.accountsStatuses(
|
val statuses = accountApiService.accountsStatuses(
|
||||||
userid = id.toLong(),
|
userid = id.toLong(),
|
||||||
maxId = maxId?.toLongOrNull(),
|
|
||||||
sinceId = sinceId?.toLongOrNull(),
|
|
||||||
minId = minId?.toLongOrNull(),
|
|
||||||
limit = limit,
|
|
||||||
onlyMedia = onlyMedia,
|
onlyMedia = onlyMedia,
|
||||||
excludeReplies = excludeReplies,
|
excludeReplies = excludeReplies,
|
||||||
excludeReblogs = excludeReblogs,
|
excludeReblogs = excludeReblogs,
|
||||||
pinned = pinned,
|
pinned = pinned,
|
||||||
tagged = tagged,
|
tagged = tagged,
|
||||||
loginUser = userid
|
loginUser = userid,
|
||||||
).asFlow()
|
page = Page.of(
|
||||||
ResponseEntity.ok(statusFlow)
|
maxId?.toLongOrNull(),
|
||||||
|
sinceId?.toLongOrNull(),
|
||||||
|
minId?.toLongOrNull(),
|
||||||
|
limit.coerceIn(0, 80) ?: 40
|
||||||
|
)
|
||||||
|
)
|
||||||
|
val httpHeader = statuses.toHttpHeader(
|
||||||
|
{ "${applicationConfig.url}/api/v1/accounts/$id/statuses?min_id=$it" },
|
||||||
|
{ "${applicationConfig.url}/api/v1/accounts/$id/statuses?max_id=$it" },
|
||||||
|
)
|
||||||
|
|
||||||
|
if (httpHeader != null) {
|
||||||
|
return@runBlocking ResponseEntity.ok().header("Link", httpHeader).body(statuses.asFlow())
|
||||||
|
}
|
||||||
|
|
||||||
|
ResponseEntity.ok(statuses.asFlow())
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun apiV1AccountsRelationshipsGet(
|
override fun apiV1AccountsRelationshipsGet(
|
||||||
|
@ -128,8 +143,7 @@ class MastodonAccountApiController(
|
||||||
return ResponseEntity.ok(removeFromFollowers)
|
return ResponseEntity.ok(removeFromFollowers)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun apiV1AccountsUpdateCredentialsPatch(updateCredentials: UpdateCredentials?):
|
override suspend fun apiV1AccountsUpdateCredentialsPatch(updateCredentials: UpdateCredentials?): ResponseEntity<Account> {
|
||||||
ResponseEntity<Account> {
|
|
||||||
val userid = loginUserContextHolder.getLoginUserId()
|
val userid = loginUserContextHolder.getLoginUserId()
|
||||||
|
|
||||||
val removeFromFollowers = accountApiService.updateProfile(userid, updateCredentials)
|
val removeFromFollowers = accountApiService.updateProfile(userid, updateCredentials)
|
||||||
|
@ -157,10 +171,27 @@ class MastodonAccountApiController(
|
||||||
runBlocking {
|
runBlocking {
|
||||||
val userid = loginUserContextHolder.getLoginUserId()
|
val userid = loginUserContextHolder.getLoginUserId()
|
||||||
|
|
||||||
val accountFlow =
|
val followRequests = accountApiService.followRequests(
|
||||||
accountApiService.followRequests(userid, maxId?.toLong(), sinceId?.toLong(), limit ?: 20, false)
|
userid,
|
||||||
.asFlow()
|
false,
|
||||||
ResponseEntity.ok(accountFlow)
|
Page.PageByMaxId(
|
||||||
|
maxId?.toLongOrNull(),
|
||||||
|
sinceId?.toLongOrNull(),
|
||||||
|
limit?.coerceIn(0, 80) ?: 40
|
||||||
|
)
|
||||||
|
|
||||||
|
)
|
||||||
|
|
||||||
|
val httpHeader = followRequests.toHttpHeader(
|
||||||
|
{ "${applicationConfig.url}/api/v1/follow_requests?max_id=$it" },
|
||||||
|
{ "${applicationConfig.url}/api/v1/follow_requests?min_id=$it" },
|
||||||
|
)
|
||||||
|
|
||||||
|
if (httpHeader != null) {
|
||||||
|
return@runBlocking ResponseEntity.ok().header("Link", httpHeader).body(followRequests.asFlow())
|
||||||
|
}
|
||||||
|
|
||||||
|
ResponseEntity.ok(followRequests.asFlow())
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun apiV1AccountsIdMutePost(id: String): ResponseEntity<Relationship> {
|
override suspend fun apiV1AccountsIdMutePost(id: String): ResponseEntity<Relationship> {
|
||||||
|
@ -183,9 +214,21 @@ class MastodonAccountApiController(
|
||||||
runBlocking {
|
runBlocking {
|
||||||
val userid = loginUserContextHolder.getLoginUserId()
|
val userid = loginUserContextHolder.getLoginUserId()
|
||||||
|
|
||||||
val unmute =
|
val mutes =
|
||||||
accountApiService.mutesAccount(userid, maxId?.toLong(), sinceId?.toLong(), limit ?: 20).asFlow()
|
accountApiService.mutesAccount(
|
||||||
|
userid,
|
||||||
|
Page.PageByMaxId(maxId?.toLongOrNull(), sinceId?.toLongOrNull(), limit?.coerceIn(0, 80) ?: 40)
|
||||||
|
)
|
||||||
|
|
||||||
return@runBlocking ResponseEntity.ok(unmute)
|
val httpHeader = mutes.toHttpHeader(
|
||||||
|
{ "${applicationConfig.url}/api/v1/mutes?max_id=$it" },
|
||||||
|
{ "${applicationConfig.url}/api/v1/mutes?since_id=$it" },
|
||||||
|
)
|
||||||
|
|
||||||
|
if (httpHeader != null) {
|
||||||
|
return@runBlocking ResponseEntity.ok().header("Link", httpHeader).body(mutes.asFlow())
|
||||||
|
}
|
||||||
|
|
||||||
|
return@runBlocking ResponseEntity.ok(mutes.asFlow())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
package dev.usbharu.hideout.mastodon.interfaces.api.notification
|
package dev.usbharu.hideout.mastodon.interfaces.api.notification
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.application.config.ApplicationConfig
|
||||||
|
import dev.usbharu.hideout.application.infrastructure.exposed.Page
|
||||||
|
import dev.usbharu.hideout.application.infrastructure.exposed.toHttpHeader
|
||||||
import dev.usbharu.hideout.controller.mastodon.generated.NotificationsApi
|
import dev.usbharu.hideout.controller.mastodon.generated.NotificationsApi
|
||||||
import dev.usbharu.hideout.core.infrastructure.springframework.security.LoginUserContextHolder
|
import dev.usbharu.hideout.core.infrastructure.springframework.security.LoginUserContextHolder
|
||||||
import dev.usbharu.hideout.domain.mastodon.model.generated.Notification
|
import dev.usbharu.hideout.domain.mastodon.model.generated.Notification
|
||||||
|
@ -14,7 +17,8 @@ import org.springframework.stereotype.Controller
|
||||||
@Controller
|
@Controller
|
||||||
class MastodonNotificationApiController(
|
class MastodonNotificationApiController(
|
||||||
private val loginUserContextHolder: LoginUserContextHolder,
|
private val loginUserContextHolder: LoginUserContextHolder,
|
||||||
private val notificationApiService: NotificationApiService
|
private val notificationApiService: NotificationApiService,
|
||||||
|
private val applicationConfig: ApplicationConfig
|
||||||
) : NotificationsApi {
|
) : NotificationsApi {
|
||||||
override suspend fun apiV1NotificationsClearPost(): ResponseEntity<Any> {
|
override suspend fun apiV1NotificationsClearPost(): ResponseEntity<Any> {
|
||||||
notificationApiService.clearAll(loginUserContextHolder.getLoginUserId())
|
notificationApiService.clearAll(loginUserContextHolder.getLoginUserId())
|
||||||
|
@ -30,17 +34,27 @@ class MastodonNotificationApiController(
|
||||||
excludeTypes: List<String>?,
|
excludeTypes: List<String>?,
|
||||||
accountId: List<String>?
|
accountId: List<String>?
|
||||||
): ResponseEntity<Flow<Notification>> = runBlocking {
|
): ResponseEntity<Flow<Notification>> = runBlocking {
|
||||||
val notificationFlow = notificationApiService.notifications(
|
val notifications = notificationApiService.notifications(
|
||||||
loginUser = loginUserContextHolder.getLoginUserId(),
|
loginUser = loginUserContextHolder.getLoginUserId(),
|
||||||
maxId = maxId?.toLong(),
|
|
||||||
minId = minId?.toLong(),
|
|
||||||
sinceId = sinceId?.toLong(),
|
|
||||||
limit = limit ?: 20,
|
|
||||||
types = types.orEmpty().mapNotNull { NotificationType.parse(it) },
|
types = types.orEmpty().mapNotNull { NotificationType.parse(it) },
|
||||||
excludeTypes = excludeTypes.orEmpty().mapNotNull { NotificationType.parse(it) },
|
excludeTypes = excludeTypes.orEmpty().mapNotNull { NotificationType.parse(it) },
|
||||||
accountId = accountId.orEmpty().mapNotNull { it.toLongOrNull() }
|
accountId = accountId.orEmpty().mapNotNull { it.toLongOrNull() },
|
||||||
).asFlow()
|
page = Page.of(
|
||||||
ResponseEntity.ok(notificationFlow)
|
maxId?.toLongOrNull(),
|
||||||
|
sinceId?.toLongOrNull(),
|
||||||
|
minId?.toLongOrNull(),
|
||||||
|
limit?.coerceIn(0, 80) ?: 40
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
val httpHeader = notifications.toHttpHeader(
|
||||||
|
{ "${applicationConfig.url}/api/v1/notifications?min_id=$it" },
|
||||||
|
{ "${applicationConfig.url}/api/v1/notifications?max_id=$it" }
|
||||||
|
) ?: return@runBlocking ResponseEntity.ok(
|
||||||
|
notifications.asFlow()
|
||||||
|
)
|
||||||
|
|
||||||
|
ResponseEntity.ok().header("Link", httpHeader).body(notifications.asFlow())
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun apiV1NotificationsIdDismissPost(id: String): ResponseEntity<Any> {
|
override suspend fun apiV1NotificationsIdDismissPost(id: String): ResponseEntity<Any> {
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
package dev.usbharu.hideout.mastodon.interfaces.api.timeline
|
package dev.usbharu.hideout.mastodon.interfaces.api.timeline
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.application.config.ApplicationConfig
|
||||||
|
import dev.usbharu.hideout.application.infrastructure.exposed.Page
|
||||||
|
import dev.usbharu.hideout.application.infrastructure.exposed.toHttpHeader
|
||||||
import dev.usbharu.hideout.controller.mastodon.generated.TimelineApi
|
import dev.usbharu.hideout.controller.mastodon.generated.TimelineApi
|
||||||
import dev.usbharu.hideout.core.infrastructure.springframework.security.LoginUserContextHolder
|
import dev.usbharu.hideout.core.infrastructure.springframework.security.LoginUserContextHolder
|
||||||
import dev.usbharu.hideout.domain.mastodon.model.generated.Status
|
import dev.usbharu.hideout.domain.mastodon.model.generated.Status
|
||||||
|
@ -14,7 +17,8 @@ import org.springframework.stereotype.Controller
|
||||||
@Controller
|
@Controller
|
||||||
class MastodonTimelineApiController(
|
class MastodonTimelineApiController(
|
||||||
private val timelineApiService: TimelineApiService,
|
private val timelineApiService: TimelineApiService,
|
||||||
private val loginUserContextHolder: LoginUserContextHolder
|
private val loginUserContextHolder: LoginUserContextHolder,
|
||||||
|
private val applicationConfig: ApplicationConfig,
|
||||||
) : TimelineApi {
|
) : TimelineApi {
|
||||||
override fun apiV1TimelinesHomeGet(
|
override fun apiV1TimelinesHomeGet(
|
||||||
maxId: String?,
|
maxId: String?,
|
||||||
|
@ -24,12 +28,22 @@ class MastodonTimelineApiController(
|
||||||
): ResponseEntity<Flow<Status>> = runBlocking {
|
): ResponseEntity<Flow<Status>> = runBlocking {
|
||||||
val homeTimeline = timelineApiService.homeTimeline(
|
val homeTimeline = timelineApiService.homeTimeline(
|
||||||
userId = loginUserContextHolder.getLoginUserId(),
|
userId = loginUserContextHolder.getLoginUserId(),
|
||||||
|
page = Page.of(
|
||||||
maxId = maxId?.toLongOrNull(),
|
maxId = maxId?.toLongOrNull(),
|
||||||
minId = minId?.toLongOrNull(),
|
minId = minId?.toLongOrNull(),
|
||||||
sinceId = sinceId?.toLongOrNull(),
|
sinceId = sinceId?.toLongOrNull(),
|
||||||
limit = limit ?: 20
|
limit = limit?.coerceIn(0, 80) ?: 40
|
||||||
)
|
)
|
||||||
ResponseEntity(homeTimeline.asFlow(), HttpStatus.OK)
|
)
|
||||||
|
|
||||||
|
val httpHeader = homeTimeline.toHttpHeader(
|
||||||
|
{ "${applicationConfig.url}/api/v1/home?max_id=$it" },
|
||||||
|
{ "${applicationConfig.url}/api/v1/home?min_id=$it" }
|
||||||
|
) ?: return@runBlocking ResponseEntity(
|
||||||
|
homeTimeline.asFlow(),
|
||||||
|
HttpStatus.OK
|
||||||
|
)
|
||||||
|
ResponseEntity.ok().header("Link", httpHeader).body(homeTimeline.asFlow())
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun apiV1TimelinesPublicGet(
|
override fun apiV1TimelinesPublicGet(
|
||||||
|
@ -45,11 +59,21 @@ class MastodonTimelineApiController(
|
||||||
localOnly = local ?: false,
|
localOnly = local ?: false,
|
||||||
remoteOnly = remote ?: false,
|
remoteOnly = remote ?: false,
|
||||||
mediaOnly = onlyMedia ?: false,
|
mediaOnly = onlyMedia ?: false,
|
||||||
|
page = Page.of(
|
||||||
maxId = maxId?.toLongOrNull(),
|
maxId = maxId?.toLongOrNull(),
|
||||||
minId = minId?.toLongOrNull(),
|
minId = minId?.toLongOrNull(),
|
||||||
sinceId = sinceId?.toLongOrNull(),
|
sinceId = sinceId?.toLongOrNull(),
|
||||||
limit = limit ?: 20
|
limit = limit?.coerceIn(0, 80) ?: 40
|
||||||
)
|
)
|
||||||
ResponseEntity(publicTimeline.asFlow(), HttpStatus.OK)
|
)
|
||||||
|
|
||||||
|
val httpHeader = publicTimeline.toHttpHeader(
|
||||||
|
{ "${applicationConfig.url}/api/v1/public?max_id=$it" },
|
||||||
|
{ "${applicationConfig.url}/api/v1/public?min_id=$it" }
|
||||||
|
) ?: return@runBlocking ResponseEntity(
|
||||||
|
publicTimeline.asFlow(),
|
||||||
|
HttpStatus.OK
|
||||||
|
)
|
||||||
|
ResponseEntity.ok().header("Link", httpHeader).body(publicTimeline.asFlow())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package dev.usbharu.hideout.mastodon.query
|
package dev.usbharu.hideout.mastodon.query
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.application.infrastructure.exposed.Page
|
||||||
|
import dev.usbharu.hideout.application.infrastructure.exposed.PaginationList
|
||||||
import dev.usbharu.hideout.domain.mastodon.model.generated.Status
|
import dev.usbharu.hideout.domain.mastodon.model.generated.Status
|
||||||
import dev.usbharu.hideout.mastodon.interfaces.api.status.StatusQuery
|
import dev.usbharu.hideout.mastodon.interfaces.api.status.StatusQuery
|
||||||
|
|
||||||
|
@ -7,35 +9,17 @@ interface StatusQueryService {
|
||||||
suspend fun findByPostIds(ids: List<Long>): List<Status>
|
suspend fun findByPostIds(ids: List<Long>): List<Status>
|
||||||
suspend fun findByPostIdsWithMediaIds(statusQueries: List<StatusQuery>): List<Status>
|
suspend fun findByPostIdsWithMediaIds(statusQueries: List<StatusQuery>): List<Status>
|
||||||
|
|
||||||
/**
|
|
||||||
* アカウントの投稿一覧を取得します
|
|
||||||
*
|
|
||||||
* @param accountId 対象アカウントのid
|
|
||||||
* @param maxId 投稿の最大id
|
|
||||||
* @param sinceId 投稿の最小id
|
|
||||||
* @param minId 不明
|
|
||||||
* @param limit 投稿の最大件数
|
|
||||||
* @param onlyMedia メディア付き投稿のみ
|
|
||||||
* @param excludeReplies 返信を除外
|
|
||||||
* @param excludeReblogs リブログを除外
|
|
||||||
* @param pinned ピン止め投稿のみ
|
|
||||||
* @param tagged タグ付き?
|
|
||||||
* @param includeFollowers フォロワー限定投稿を含める
|
|
||||||
*/
|
|
||||||
@Suppress("LongParameterList")
|
@Suppress("LongParameterList")
|
||||||
suspend fun accountsStatus(
|
suspend fun accountsStatus(
|
||||||
accountId: Long,
|
accountId: Long,
|
||||||
maxId: Long? = null,
|
|
||||||
sinceId: Long? = null,
|
|
||||||
minId: Long? = null,
|
|
||||||
limit: Int,
|
|
||||||
onlyMedia: Boolean = false,
|
onlyMedia: Boolean = false,
|
||||||
excludeReplies: Boolean = false,
|
excludeReplies: Boolean = false,
|
||||||
excludeReblogs: Boolean = false,
|
excludeReblogs: Boolean = false,
|
||||||
pinned: Boolean = false,
|
pinned: Boolean = false,
|
||||||
tagged: String? = null,
|
tagged: String?,
|
||||||
includeFollowers: Boolean = false
|
includeFollowers: Boolean = false,
|
||||||
): List<Status>
|
page: Page
|
||||||
|
): PaginationList<Status, Long>
|
||||||
|
|
||||||
suspend fun findByPostId(id: Long): Status
|
suspend fun findByPostId(id: Long): Status
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package dev.usbharu.hideout.mastodon.service.account
|
package dev.usbharu.hideout.mastodon.service.account
|
||||||
|
|
||||||
import dev.usbharu.hideout.application.external.Transaction
|
import dev.usbharu.hideout.application.external.Transaction
|
||||||
|
import dev.usbharu.hideout.application.infrastructure.exposed.Page
|
||||||
|
import dev.usbharu.hideout.application.infrastructure.exposed.PaginationList
|
||||||
import dev.usbharu.hideout.core.domain.model.relationship.RelationshipRepository
|
import dev.usbharu.hideout.core.domain.model.relationship.RelationshipRepository
|
||||||
import dev.usbharu.hideout.core.service.media.MediaService
|
import dev.usbharu.hideout.core.service.media.MediaService
|
||||||
import dev.usbharu.hideout.core.service.relationship.RelationshipService
|
import dev.usbharu.hideout.core.service.relationship.RelationshipService
|
||||||
|
@ -17,20 +19,18 @@ import kotlin.math.min
|
||||||
@Service
|
@Service
|
||||||
@Suppress("TooManyFunctions")
|
@Suppress("TooManyFunctions")
|
||||||
interface AccountApiService {
|
interface AccountApiService {
|
||||||
@Suppress("LongParameterList")
|
|
||||||
|
@Suppress("ongParameterList")
|
||||||
suspend fun accountsStatuses(
|
suspend fun accountsStatuses(
|
||||||
userid: Long,
|
userid: Long,
|
||||||
maxId: Long?,
|
|
||||||
sinceId: Long?,
|
|
||||||
minId: Long?,
|
|
||||||
limit: Int,
|
|
||||||
onlyMedia: Boolean,
|
onlyMedia: Boolean,
|
||||||
excludeReplies: Boolean,
|
excludeReplies: Boolean,
|
||||||
excludeReblogs: Boolean,
|
excludeReblogs: Boolean,
|
||||||
pinned: Boolean,
|
pinned: Boolean,
|
||||||
tagged: String?,
|
tagged: String?,
|
||||||
loginUser: Long?
|
loginUser: Long?,
|
||||||
): List<Status>
|
page: Page
|
||||||
|
): PaginationList<Status, Long>
|
||||||
|
|
||||||
suspend fun verifyCredentials(userid: Long): CredentialAccount
|
suspend fun verifyCredentials(userid: Long): CredentialAccount
|
||||||
suspend fun registerAccount(userCreateDto: UserCreateDto): Unit
|
suspend fun registerAccount(userCreateDto: UserCreateDto): Unit
|
||||||
|
@ -50,19 +50,18 @@ interface AccountApiService {
|
||||||
suspend fun unfollow(userid: Long, target: Long): Relationship
|
suspend fun unfollow(userid: Long, target: Long): Relationship
|
||||||
suspend fun removeFromFollowers(userid: Long, target: Long): Relationship
|
suspend fun removeFromFollowers(userid: Long, target: Long): Relationship
|
||||||
suspend fun updateProfile(userid: Long, updateCredentials: UpdateCredentials?): Account
|
suspend fun updateProfile(userid: Long, updateCredentials: UpdateCredentials?): Account
|
||||||
|
|
||||||
suspend fun followRequests(
|
suspend fun followRequests(
|
||||||
loginUser: Long,
|
loginUser: Long,
|
||||||
maxId: Long?,
|
withIgnore: Boolean,
|
||||||
sinceId: Long?,
|
pageByMaxId: Page.PageByMaxId
|
||||||
limit: Int = 20,
|
): PaginationList<Account, Long>
|
||||||
withIgnore: Boolean
|
|
||||||
): List<Account>
|
|
||||||
|
|
||||||
suspend fun acceptFollowRequest(loginUser: Long, target: Long): Relationship
|
suspend fun acceptFollowRequest(loginUser: Long, target: Long): Relationship
|
||||||
suspend fun rejectFollowRequest(loginUser: Long, target: Long): Relationship
|
suspend fun rejectFollowRequest(loginUser: Long, target: Long): Relationship
|
||||||
suspend fun mute(userid: Long, target: Long): Relationship
|
suspend fun mute(userid: Long, target: Long): Relationship
|
||||||
suspend fun unmute(userid: Long, target: Long): Relationship
|
suspend fun unmute(userid: Long, target: Long): Relationship
|
||||||
suspend fun mutesAccount(userid: Long, maxId: Long?, sinceId: Long?, limit: Int): List<Account>
|
suspend fun mutesAccount(userid: Long, pageByMaxId: Page.PageByMaxId): PaginationList<Account, Long>
|
||||||
}
|
}
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
|
@ -76,21 +75,21 @@ class AccountApiServiceImpl(
|
||||||
private val mediaService: MediaService
|
private val mediaService: MediaService
|
||||||
) :
|
) :
|
||||||
AccountApiService {
|
AccountApiService {
|
||||||
|
|
||||||
override suspend fun accountsStatuses(
|
override suspend fun accountsStatuses(
|
||||||
userid: Long,
|
userid: Long,
|
||||||
maxId: Long?,
|
|
||||||
sinceId: Long?,
|
|
||||||
minId: Long?,
|
|
||||||
limit: Int,
|
|
||||||
onlyMedia: Boolean,
|
onlyMedia: Boolean,
|
||||||
excludeReplies: Boolean,
|
excludeReplies: Boolean,
|
||||||
excludeReblogs: Boolean,
|
excludeReblogs: Boolean,
|
||||||
pinned: Boolean,
|
pinned: Boolean,
|
||||||
tagged: String?,
|
tagged: String?,
|
||||||
loginUser: Long?
|
loginUser: Long?,
|
||||||
): List<Status> {
|
page: Page
|
||||||
|
): PaginationList<Status, Long> {
|
||||||
val canViewFollowers = if (loginUser == null) {
|
val canViewFollowers = if (loginUser == null) {
|
||||||
false
|
false
|
||||||
|
} else if (loginUser == userid) {
|
||||||
|
true
|
||||||
} else {
|
} else {
|
||||||
transaction.transaction {
|
transaction.transaction {
|
||||||
isFollowing(loginUser, userid)
|
isFollowing(loginUser, userid)
|
||||||
|
@ -100,16 +99,13 @@ class AccountApiServiceImpl(
|
||||||
return transaction.transaction {
|
return transaction.transaction {
|
||||||
statusQueryService.accountsStatus(
|
statusQueryService.accountsStatus(
|
||||||
accountId = userid,
|
accountId = userid,
|
||||||
maxId = maxId,
|
|
||||||
sinceId = sinceId,
|
|
||||||
minId = minId,
|
|
||||||
limit = limit,
|
|
||||||
onlyMedia = onlyMedia,
|
onlyMedia = onlyMedia,
|
||||||
excludeReplies = excludeReplies,
|
excludeReplies = excludeReplies,
|
||||||
excludeReblogs = excludeReblogs,
|
excludeReblogs = excludeReblogs,
|
||||||
pinned = pinned,
|
pinned = pinned,
|
||||||
tagged = tagged,
|
tagged = tagged,
|
||||||
includeFollowers = canViewFollowers
|
includeFollowers = canViewFollowers,
|
||||||
|
page = page
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -217,23 +213,19 @@ class AccountApiServiceImpl(
|
||||||
|
|
||||||
override suspend fun followRequests(
|
override suspend fun followRequests(
|
||||||
loginUser: Long,
|
loginUser: Long,
|
||||||
maxId: Long?,
|
withIgnore: Boolean,
|
||||||
sinceId: Long?,
|
pageByMaxId: Page.PageByMaxId
|
||||||
limit: Int,
|
): PaginationList<Account, Long> = transaction.transaction {
|
||||||
withIgnore: Boolean
|
val request =
|
||||||
): List<Account> = transaction.transaction {
|
relationshipRepository.findByTargetIdAndFollowRequestAndIgnoreFollowRequest(
|
||||||
val actorIdList = relationshipRepository
|
loginUser,
|
||||||
.findByTargetIdAndFollowRequestAndIgnoreFollowRequest(
|
true,
|
||||||
maxId = maxId,
|
withIgnore,
|
||||||
sinceId = sinceId,
|
pageByMaxId
|
||||||
limit = limit,
|
|
||||||
targetId = loginUser,
|
|
||||||
followRequest = true,
|
|
||||||
ignoreFollowRequest = withIgnore
|
|
||||||
)
|
)
|
||||||
.map { it.actorId }
|
val actorIds = request.map { it.actorId }
|
||||||
|
|
||||||
return@transaction accountService.findByIds(actorIdList)
|
return@transaction PaginationList(accountService.findByIds(actorIds), request.next, request.prev)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun acceptFollowRequest(loginUser: Long, target: Long): Relationship = transaction.transaction {
|
override suspend fun acceptFollowRequest(loginUser: Long, target: Long): Relationship = transaction.transaction {
|
||||||
|
@ -260,11 +252,14 @@ class AccountApiServiceImpl(
|
||||||
return@transaction fetchRelationship(userid, target)
|
return@transaction fetchRelationship(userid, target)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun mutesAccount(userid: Long, maxId: Long?, sinceId: Long?, limit: Int): List<Account> {
|
override suspend fun mutesAccount(userid: Long, pageByMaxId: Page.PageByMaxId): PaginationList<Account, Long> {
|
||||||
val mutedAccounts =
|
val mutedAccounts = relationshipRepository.findByActorIdAndMuting(userid, true, pageByMaxId)
|
||||||
relationshipRepository.findByActorIdAntMutingAndMaxIdAndSinceId(userid, true, maxId, sinceId, limit)
|
|
||||||
|
|
||||||
return accountService.findByIds(mutedAccounts.map { it.targetActorId })
|
return PaginationList(
|
||||||
|
accountService.findByIds(mutedAccounts.map { it.targetActorId }),
|
||||||
|
mutedAccounts.next,
|
||||||
|
mutedAccounts.prev
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun from(account: Account): CredentialAccount {
|
private fun from(account: Account): CredentialAccount {
|
||||||
|
|
|
@ -1,20 +1,19 @@
|
||||||
package dev.usbharu.hideout.mastodon.service.notification
|
package dev.usbharu.hideout.mastodon.service.notification
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.application.infrastructure.exposed.Page
|
||||||
|
import dev.usbharu.hideout.application.infrastructure.exposed.PaginationList
|
||||||
import dev.usbharu.hideout.domain.mastodon.model.generated.Notification
|
import dev.usbharu.hideout.domain.mastodon.model.generated.Notification
|
||||||
import dev.usbharu.hideout.mastodon.domain.model.NotificationType
|
import dev.usbharu.hideout.mastodon.domain.model.NotificationType
|
||||||
|
|
||||||
interface NotificationApiService {
|
interface NotificationApiService {
|
||||||
@Suppress("LongParameterList")
|
|
||||||
suspend fun notifications(
|
suspend fun notifications(
|
||||||
loginUser: Long,
|
loginUser: Long,
|
||||||
maxId: Long?,
|
|
||||||
minId: Long?,
|
|
||||||
sinceId: Long?,
|
|
||||||
limit: Int,
|
|
||||||
types: List<NotificationType>,
|
types: List<NotificationType>,
|
||||||
excludeTypes: List<NotificationType>,
|
excludeTypes: List<NotificationType>,
|
||||||
accountId: List<Long>
|
accountId: List<Long>,
|
||||||
): List<Notification>
|
page: Page
|
||||||
|
): PaginationList<Notification, Long>
|
||||||
|
|
||||||
suspend fun fingById(loginUser: Long, notificationId: Long): Notification?
|
suspend fun fingById(loginUser: Long, notificationId: Long): Notification?
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package dev.usbharu.hideout.mastodon.service.notification
|
package dev.usbharu.hideout.mastodon.service.notification
|
||||||
|
|
||||||
import dev.usbharu.hideout.application.external.Transaction
|
import dev.usbharu.hideout.application.external.Transaction
|
||||||
|
import dev.usbharu.hideout.application.infrastructure.exposed.Page
|
||||||
|
import dev.usbharu.hideout.application.infrastructure.exposed.PaginationList
|
||||||
import dev.usbharu.hideout.domain.mastodon.model.generated.Notification
|
import dev.usbharu.hideout.domain.mastodon.model.generated.Notification
|
||||||
import dev.usbharu.hideout.mastodon.domain.model.MastodonNotificationRepository
|
import dev.usbharu.hideout.mastodon.domain.model.MastodonNotificationRepository
|
||||||
import dev.usbharu.hideout.mastodon.domain.model.NotificationType
|
import dev.usbharu.hideout.mastodon.domain.model.NotificationType
|
||||||
|
@ -17,30 +19,25 @@ class NotificationApiServiceImpl(
|
||||||
private val statusQueryService: StatusQueryService
|
private val statusQueryService: StatusQueryService
|
||||||
) :
|
) :
|
||||||
NotificationApiService {
|
NotificationApiService {
|
||||||
|
|
||||||
override suspend fun notifications(
|
override suspend fun notifications(
|
||||||
loginUser: Long,
|
loginUser: Long,
|
||||||
maxId: Long?,
|
|
||||||
minId: Long?,
|
|
||||||
sinceId: Long?,
|
|
||||||
limit: Int,
|
|
||||||
types: List<NotificationType>,
|
types: List<NotificationType>,
|
||||||
excludeTypes: List<NotificationType>,
|
excludeTypes: List<NotificationType>,
|
||||||
accountId: List<Long>
|
accountId: List<Long>,
|
||||||
): List<Notification> = transaction.transaction {
|
page: Page
|
||||||
|
): PaginationList<Notification, Long> = transaction.transaction {
|
||||||
val typesTmp = mutableListOf<NotificationType>()
|
val typesTmp = mutableListOf<NotificationType>()
|
||||||
|
|
||||||
typesTmp.addAll(types)
|
typesTmp.addAll(types)
|
||||||
typesTmp.removeAll(excludeTypes)
|
typesTmp.removeAll(excludeTypes)
|
||||||
|
|
||||||
val mastodonNotifications =
|
val mastodonNotifications =
|
||||||
mastodonNotificationRepository.findByUserIdAndMaxIdAndMinIdAndSinceIdAndInTypesAndInSourceActorId(
|
mastodonNotificationRepository.findByUserIdAndInTypesAndInSourceActorId(
|
||||||
loginUser,
|
loginUser,
|
||||||
maxId,
|
|
||||||
minId,
|
|
||||||
sinceId,
|
|
||||||
limit,
|
|
||||||
typesTmp,
|
typesTmp,
|
||||||
accountId
|
accountId,
|
||||||
|
page
|
||||||
)
|
)
|
||||||
|
|
||||||
val accounts = accountService.findByIds(
|
val accounts = accountService.findByIds(
|
||||||
|
@ -52,7 +49,7 @@ class NotificationApiServiceImpl(
|
||||||
val statuses = statusQueryService.findByPostIds(mastodonNotifications.mapNotNull { it.statusId })
|
val statuses = statusQueryService.findByPostIds(mastodonNotifications.mapNotNull { it.statusId })
|
||||||
.associateBy { it.id.toLong() }
|
.associateBy { it.id.toLong() }
|
||||||
|
|
||||||
mastodonNotifications.map {
|
val notifications = mastodonNotifications.map {
|
||||||
Notification(
|
Notification(
|
||||||
id = it.id.toString(),
|
id = it.id.toString(),
|
||||||
type = convertNotificationType(it.type),
|
type = convertNotificationType(it.type),
|
||||||
|
@ -63,6 +60,8 @@ class NotificationApiServiceImpl(
|
||||||
relationshipSeveranceEvent = null
|
relationshipSeveranceEvent = null
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return@transaction PaginationList(notifications, mastodonNotifications.next, mastodonNotifications.prev)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun fingById(loginUser: Long, notificationId: Long): Notification? {
|
override suspend fun fingById(loginUser: Long, notificationId: Long): Notification? {
|
||||||
|
|
|
@ -1,29 +1,26 @@
|
||||||
package dev.usbharu.hideout.mastodon.service.timeline
|
package dev.usbharu.hideout.mastodon.service.timeline
|
||||||
|
|
||||||
import dev.usbharu.hideout.application.external.Transaction
|
import dev.usbharu.hideout.application.external.Transaction
|
||||||
|
import dev.usbharu.hideout.application.infrastructure.exposed.Page
|
||||||
|
import dev.usbharu.hideout.application.infrastructure.exposed.PaginationList
|
||||||
import dev.usbharu.hideout.core.service.timeline.GenerateTimelineService
|
import dev.usbharu.hideout.core.service.timeline.GenerateTimelineService
|
||||||
import dev.usbharu.hideout.domain.mastodon.model.generated.Status
|
import dev.usbharu.hideout.domain.mastodon.model.generated.Status
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
|
|
||||||
@Suppress("LongParameterList")
|
@Suppress("LongParameterList")
|
||||||
interface TimelineApiService {
|
interface TimelineApiService {
|
||||||
|
|
||||||
suspend fun publicTimeline(
|
suspend fun publicTimeline(
|
||||||
localOnly: Boolean = false,
|
localOnly: Boolean = false,
|
||||||
remoteOnly: Boolean = false,
|
remoteOnly: Boolean = false,
|
||||||
mediaOnly: Boolean = false,
|
mediaOnly: Boolean = false,
|
||||||
maxId: Long?,
|
page: Page
|
||||||
minId: Long?,
|
): PaginationList<Status, Long>
|
||||||
sinceId: Long?,
|
|
||||||
limit: Int = 20
|
|
||||||
): List<Status>
|
|
||||||
|
|
||||||
suspend fun homeTimeline(
|
suspend fun homeTimeline(
|
||||||
userId: Long,
|
userId: Long,
|
||||||
maxId: Long?,
|
page: Page
|
||||||
minId: Long?,
|
): PaginationList<Status, Long>
|
||||||
sinceId: Long?,
|
|
||||||
limit: Int = 20
|
|
||||||
): List<Status>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
|
@ -31,39 +28,18 @@ class TimelineApiServiceImpl(
|
||||||
private val generateTimelineService: GenerateTimelineService,
|
private val generateTimelineService: GenerateTimelineService,
|
||||||
private val transaction: Transaction
|
private val transaction: Transaction
|
||||||
) : TimelineApiService {
|
) : TimelineApiService {
|
||||||
|
|
||||||
override suspend fun publicTimeline(
|
override suspend fun publicTimeline(
|
||||||
localOnly: Boolean,
|
localOnly: Boolean,
|
||||||
remoteOnly: Boolean,
|
remoteOnly: Boolean,
|
||||||
mediaOnly: Boolean,
|
mediaOnly: Boolean,
|
||||||
maxId: Long?,
|
page: Page
|
||||||
minId: Long?,
|
): PaginationList<Status, Long> = transaction.transaction {
|
||||||
sinceId: Long?,
|
return@transaction generateTimelineService.getTimeline(forUserId = 0, localOnly, mediaOnly, page)
|
||||||
limit: Int
|
|
||||||
): List<Status> = transaction.transaction {
|
|
||||||
generateTimelineService.getTimeline(
|
|
||||||
forUserId = 0,
|
|
||||||
localOnly = localOnly,
|
|
||||||
mediaOnly = mediaOnly,
|
|
||||||
maxId = maxId,
|
|
||||||
minId = minId,
|
|
||||||
sinceId = sinceId,
|
|
||||||
limit = limit
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun homeTimeline(
|
override suspend fun homeTimeline(userId: Long, page: Page): PaginationList<Status, Long> =
|
||||||
userId: Long,
|
transaction.transaction {
|
||||||
maxId: Long?,
|
return@transaction generateTimelineService.getTimeline(forUserId = userId, page = page)
|
||||||
minId: Long?,
|
|
||||||
sinceId: Long?,
|
|
||||||
limit: Int
|
|
||||||
): List<Status> = transaction.transaction {
|
|
||||||
generateTimelineService.getTimeline(
|
|
||||||
forUserId = userId,
|
|
||||||
maxId = maxId,
|
|
||||||
minId = minId,
|
|
||||||
sinceId = sinceId,
|
|
||||||
limit = limit
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -573,6 +573,7 @@ paths:
|
||||||
required: false
|
required: false
|
||||||
schema:
|
schema:
|
||||||
type: integer
|
type: integer
|
||||||
|
nullable: true
|
||||||
default: 20
|
default: 20
|
||||||
- in: query
|
- in: query
|
||||||
name: only_media
|
name: only_media
|
||||||
|
@ -1051,7 +1052,6 @@ components:
|
||||||
- group
|
- group
|
||||||
- discoverable
|
- discoverable
|
||||||
- created_at
|
- created_at
|
||||||
- last_status_at
|
|
||||||
- statuses_count
|
- statuses_count
|
||||||
- followers_count
|
- followers_count
|
||||||
- followers_count
|
- followers_count
|
||||||
|
@ -1279,6 +1279,7 @@ components:
|
||||||
language:
|
language:
|
||||||
type: string
|
type: string
|
||||||
nullable: true
|
nullable: true
|
||||||
|
default: null
|
||||||
text:
|
text:
|
||||||
type: string
|
type: string
|
||||||
nullable: true
|
nullable: true
|
||||||
|
@ -1316,11 +1317,7 @@ components:
|
||||||
- favourites_count
|
- favourites_count
|
||||||
- replies_count
|
- replies_count
|
||||||
- url
|
- url
|
||||||
- in_reply_to_id
|
|
||||||
- in_reply_to_account_id
|
|
||||||
- language
|
|
||||||
- text
|
- text
|
||||||
- edited_at
|
|
||||||
|
|
||||||
MediaAttachment:
|
MediaAttachment:
|
||||||
type: object
|
type: object
|
||||||
|
|
|
@ -0,0 +1,137 @@
|
||||||
|
package dev.usbharu.hideout.application.infrastructure.exposed
|
||||||
|
|
||||||
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
|
import org.jetbrains.exposed.sql.*
|
||||||
|
import org.jetbrains.exposed.sql.transactions.transaction
|
||||||
|
import org.junit.jupiter.api.AfterEach
|
||||||
|
import org.junit.jupiter.api.BeforeAll
|
||||||
|
import org.junit.jupiter.api.BeforeEach
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
|
||||||
|
class ExposedPaginationExtensionKtTest {
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
fun setUp(): Unit = transaction {
|
||||||
|
val map = (1..100).map { it to it.toString() }
|
||||||
|
|
||||||
|
ExposePaginationTestTable.batchInsert(map){
|
||||||
|
this[ExposePaginationTestTable.id] = it.first.toLong()
|
||||||
|
this[ExposePaginationTestTable.name] = it.second
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
fun tearDown():Unit = transaction {
|
||||||
|
ExposePaginationTestTable.deleteAll()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun パラメーター無しでの取得(): Unit = transaction {
|
||||||
|
val pagination: PaginationList<ResultRow,Long> = ExposePaginationTestTable.selectAll().limit(20).withPagination(Page.of(), ExposePaginationTestTable.id)
|
||||||
|
|
||||||
|
assertThat(pagination.next).isEqualTo(100)
|
||||||
|
assertThat(pagination.prev).isEqualTo(81)
|
||||||
|
assertThat(pagination.first()[ExposePaginationTestTable.id]).isEqualTo(100)
|
||||||
|
assertThat(pagination.last()[ExposePaginationTestTable.id]).isEqualTo(81)
|
||||||
|
assertThat(pagination).size().isEqualTo(20)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun maxIdを指定して取得(): Unit = transaction {
|
||||||
|
val pagination: PaginationList<ResultRow,Long> = ExposePaginationTestTable.selectAll().limit(20).withPagination(Page.of(maxId = 100), ExposePaginationTestTable.id)
|
||||||
|
|
||||||
|
assertThat(pagination.next).isEqualTo(99)
|
||||||
|
assertThat(pagination.prev).isEqualTo(80)
|
||||||
|
assertThat(pagination.first()[ExposePaginationTestTable.id]).isEqualTo(99)
|
||||||
|
assertThat(pagination.last()[ExposePaginationTestTable.id]).isEqualTo(80)
|
||||||
|
assertThat(pagination).size().isEqualTo(20)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun sinceIdを指定して取得(): Unit = transaction {
|
||||||
|
val pagination: PaginationList<ResultRow,Long> = ExposePaginationTestTable.selectAll().limit(20).withPagination(Page.of(sinceId = 15), ExposePaginationTestTable.id)
|
||||||
|
|
||||||
|
assertThat(pagination.next).isEqualTo(100)
|
||||||
|
assertThat(pagination.prev).isEqualTo(81)
|
||||||
|
assertThat(pagination.first()[ExposePaginationTestTable.id]).isEqualTo(100)
|
||||||
|
assertThat(pagination.last()[ExposePaginationTestTable.id]).isEqualTo(81)
|
||||||
|
assertThat(pagination).size().isEqualTo(20)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun minIdを指定して取得():Unit = transaction {
|
||||||
|
val pagination: PaginationList<ResultRow,Long> = ExposePaginationTestTable.selectAll().limit(20).withPagination(Page.of(minId = 45), ExposePaginationTestTable.id)
|
||||||
|
|
||||||
|
assertThat(pagination.next).isEqualTo(65)
|
||||||
|
assertThat(pagination.prev).isEqualTo(46)
|
||||||
|
assertThat(pagination.first()[ExposePaginationTestTable.id]).isEqualTo(65)
|
||||||
|
assertThat(pagination.last()[ExposePaginationTestTable.id]).isEqualTo(46)
|
||||||
|
assertThat(pagination).size().isEqualTo(20)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun maxIdとsinceIdを指定して取得(): Unit = transaction {
|
||||||
|
val pagination: PaginationList<ResultRow,Long> = ExposePaginationTestTable.selectAll().limit(20).withPagination(Page.of(maxId = 45, sinceId = 34), ExposePaginationTestTable.id)
|
||||||
|
|
||||||
|
assertThat(pagination.next).isEqualTo(44)
|
||||||
|
assertThat(pagination.prev).isEqualTo(35)
|
||||||
|
assertThat(pagination.first()[ExposePaginationTestTable.id]).isEqualTo(44)
|
||||||
|
assertThat(pagination.last()[ExposePaginationTestTable.id]).isEqualTo(35)
|
||||||
|
assertThat(pagination).size().isEqualTo(10)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun maxIdとminIdを指定して取得():Unit = transaction {
|
||||||
|
val pagination: PaginationList<ResultRow,Long> = ExposePaginationTestTable.selectAll().limit(20).withPagination(Page.of(maxId = 54, minId = 45), ExposePaginationTestTable.id)
|
||||||
|
|
||||||
|
assertThat(pagination.next).isEqualTo(53)
|
||||||
|
assertThat(pagination.prev).isEqualTo(46)
|
||||||
|
assertThat(pagination.first()[ExposePaginationTestTable.id]).isEqualTo(53)
|
||||||
|
assertThat(pagination.last()[ExposePaginationTestTable.id]).isEqualTo(46)
|
||||||
|
assertThat(pagination).size().isEqualTo(8)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun limitを指定して取得():Unit = transaction {
|
||||||
|
val pagination: PaginationList<ResultRow,Long> = ExposePaginationTestTable.selectAll().withPagination(Page.of(limit = 30), ExposePaginationTestTable.id)
|
||||||
|
assertThat(pagination).size().isEqualTo(30)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun 結果が0件の場合はprevとnextがnullになる():Unit = transaction {
|
||||||
|
val pagination = ExposePaginationTestTable.select { ExposePaginationTestTable.id.isNull() }
|
||||||
|
.withPagination(Page.of(), ExposePaginationTestTable.id)
|
||||||
|
|
||||||
|
assertThat(pagination).isEmpty()
|
||||||
|
assertThat(pagination.next).isNull()
|
||||||
|
assertThat(pagination.prev).isNull()
|
||||||
|
}
|
||||||
|
|
||||||
|
object ExposePaginationTestTable : Table(){
|
||||||
|
val id = long("id")
|
||||||
|
val name = varchar("name",100)
|
||||||
|
|
||||||
|
override val primaryKey: PrimaryKey?
|
||||||
|
get() = PrimaryKey(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private lateinit var database: Database
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
@BeforeAll
|
||||||
|
fun beforeAll(): Unit {
|
||||||
|
database = Database.connect(
|
||||||
|
url = "jdbc:h2:mem:test;MODE=POSTGRESQL;DB_CLOSE_DELAY=-1;CASE_INSENSITIVE_IDENTIFIERS=true;TRACE_LEVEL_FILE=4;",
|
||||||
|
driver = "org.h2.Driver",
|
||||||
|
user = "sa",
|
||||||
|
password = ""
|
||||||
|
)
|
||||||
|
|
||||||
|
transaction(database) {
|
||||||
|
SchemaUtils.create(ExposePaginationTestTable)
|
||||||
|
SchemaUtils.createMissingTablesAndColumns(ExposePaginationTestTable)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
package dev.usbharu.hideout.application.infrastructure.exposed
|
||||||
|
|
||||||
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
|
import org.junit.jupiter.api.Assertions.*
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
|
||||||
|
class PageTest {
|
||||||
|
@Test
|
||||||
|
fun minIdが指定されているとsinceIdは無視される() {
|
||||||
|
val page = Page.of(1, 2, 3, 4)
|
||||||
|
|
||||||
|
assertThat(page.maxId).isEqualTo(1)
|
||||||
|
assertThat(page.sinceId).isNull()
|
||||||
|
assertThat(page.minId).isEqualTo(3)
|
||||||
|
assertThat(page.limit).isEqualTo(4)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun minIdがnullのときはsinceIdが使われる() {
|
||||||
|
val page = Page.of(1, 2, null, 4)
|
||||||
|
|
||||||
|
assertThat(page.maxId).isEqualTo(1)
|
||||||
|
assertThat(page.minId).isNull()
|
||||||
|
assertThat(page.sinceId).isEqualTo(2)
|
||||||
|
assertThat(page.limit).isEqualTo(4)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
package dev.usbharu.hideout.application.infrastructure.exposed
|
||||||
|
|
||||||
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
|
import org.junit.jupiter.api.Assertions.*
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
|
||||||
|
class PaginationListKtTest {
|
||||||
|
@Test
|
||||||
|
fun `toHttpHeader nextとprevがnullでない場合両方作成される`() {
|
||||||
|
val paginationList = PaginationList<String, Long>(emptyList(), 1, 2)
|
||||||
|
|
||||||
|
val httpHeader =
|
||||||
|
paginationList.toHttpHeader({ "https://example.com?max_id=$it" }, { "https://example.com?min_id=$it" })
|
||||||
|
|
||||||
|
assertThat(httpHeader).isEqualTo("<https://example.com?max_id=1>; rel=\"next\", <https://example.com?min_id=2>; rel=\"prev\"")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `toHttpHeader nextがnullなら片方だけ作成される`() {
|
||||||
|
val paginationList = PaginationList<String, Long>(emptyList(), 1,null)
|
||||||
|
|
||||||
|
val httpHeader =
|
||||||
|
paginationList.toHttpHeader({ "https://example.com?max_id=$it" }, { "https://example.com?min_id=$it" })
|
||||||
|
|
||||||
|
assertThat(httpHeader).isEqualTo("<https://example.com?max_id=1>; rel=\"next\"")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `toHttpHeader prevがnullなら片方だけ作成される`() {
|
||||||
|
val paginationList = PaginationList<String, Long>(emptyList(), null,2)
|
||||||
|
|
||||||
|
val httpHeader =
|
||||||
|
paginationList.toHttpHeader({ "https://example.com?max_id=$it" }, { "https://example.com?min_id=$it" })
|
||||||
|
|
||||||
|
assertThat(httpHeader).isEqualTo("<https://example.com?min_id=2>; rel=\"prev\"")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `toHttpHeader 両方nullならnullが返ってくる`() {
|
||||||
|
val paginationList = PaginationList<String, Long>(emptyList(), null, null)
|
||||||
|
|
||||||
|
|
||||||
|
val httpHeader =
|
||||||
|
paginationList.toHttpHeader({ "https://example.com?max_id=$it" }, { "https://example.com?min_id=$it" })
|
||||||
|
|
||||||
|
assertThat(httpHeader).isNull()
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
package dev.usbharu.hideout.mastodon.interfaces.api.account
|
package dev.usbharu.hideout.mastodon.interfaces.api.account
|
||||||
|
|
||||||
import dev.usbharu.hideout.application.config.ActivityPubConfig
|
import dev.usbharu.hideout.application.config.ActivityPubConfig
|
||||||
|
import dev.usbharu.hideout.application.config.ApplicationConfig
|
||||||
import dev.usbharu.hideout.core.infrastructure.springframework.security.OAuth2JwtLoginUserContextHolder
|
import dev.usbharu.hideout.core.infrastructure.springframework.security.OAuth2JwtLoginUserContextHolder
|
||||||
import dev.usbharu.hideout.domain.mastodon.model.generated.AccountSource
|
import dev.usbharu.hideout.domain.mastodon.model.generated.AccountSource
|
||||||
import dev.usbharu.hideout.domain.mastodon.model.generated.CredentialAccount
|
import dev.usbharu.hideout.domain.mastodon.model.generated.CredentialAccount
|
||||||
|
@ -26,6 +27,7 @@ import org.springframework.test.web.servlet.get
|
||||||
import org.springframework.test.web.servlet.post
|
import org.springframework.test.web.servlet.post
|
||||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders
|
import org.springframework.test.web.servlet.setup.MockMvcBuilders
|
||||||
import utils.TestTransaction
|
import utils.TestTransaction
|
||||||
|
import java.net.URL
|
||||||
|
|
||||||
@ExtendWith(MockitoExtension::class)
|
@ExtendWith(MockitoExtension::class)
|
||||||
class MastodonAccountApiControllerTest {
|
class MastodonAccountApiControllerTest {
|
||||||
|
@ -41,6 +43,9 @@ class MastodonAccountApiControllerTest {
|
||||||
@Mock
|
@Mock
|
||||||
private lateinit var accountApiService: AccountApiService
|
private lateinit var accountApiService: AccountApiService
|
||||||
|
|
||||||
|
@Spy
|
||||||
|
private val applicationConfig: ApplicationConfig = ApplicationConfig(URL("https://example.com"))
|
||||||
|
|
||||||
@InjectMocks
|
@InjectMocks
|
||||||
private lateinit var mastodonAccountApiController: MastodonAccountApiController
|
private lateinit var mastodonAccountApiController: MastodonAccountApiController
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package dev.usbharu.hideout.mastodon.interfaces.api.timeline
|
package dev.usbharu.hideout.mastodon.interfaces.api.timeline
|
||||||
|
|
||||||
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
||||||
|
import dev.usbharu.hideout.application.config.ApplicationConfig
|
||||||
|
import dev.usbharu.hideout.application.infrastructure.exposed.PaginationList
|
||||||
import dev.usbharu.hideout.core.infrastructure.springframework.security.OAuth2JwtLoginUserContextHolder
|
import dev.usbharu.hideout.core.infrastructure.springframework.security.OAuth2JwtLoginUserContextHolder
|
||||||
import dev.usbharu.hideout.domain.mastodon.model.generated.Account
|
import dev.usbharu.hideout.domain.mastodon.model.generated.Account
|
||||||
import dev.usbharu.hideout.domain.mastodon.model.generated.Status
|
import dev.usbharu.hideout.domain.mastodon.model.generated.Status
|
||||||
|
@ -21,6 +23,7 @@ import org.springframework.test.web.servlet.MockMvc
|
||||||
import org.springframework.test.web.servlet.get
|
import org.springframework.test.web.servlet.get
|
||||||
import org.springframework.test.web.servlet.post
|
import org.springframework.test.web.servlet.post
|
||||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders
|
import org.springframework.test.web.servlet.setup.MockMvcBuilders
|
||||||
|
import java.net.URL
|
||||||
|
|
||||||
@ExtendWith(MockitoExtension::class)
|
@ExtendWith(MockitoExtension::class)
|
||||||
class MastodonTimelineApiControllerTest {
|
class MastodonTimelineApiControllerTest {
|
||||||
|
@ -31,6 +34,9 @@ class MastodonTimelineApiControllerTest {
|
||||||
@Mock
|
@Mock
|
||||||
private lateinit var timelineApiService: TimelineApiService
|
private lateinit var timelineApiService: TimelineApiService
|
||||||
|
|
||||||
|
@Spy
|
||||||
|
private val applicationConfig: ApplicationConfig = ApplicationConfig(URL("https://example.com"))
|
||||||
|
|
||||||
@InjectMocks
|
@InjectMocks
|
||||||
private lateinit var mastodonTimelineApiController: MastodonTimelineApiController
|
private lateinit var mastodonTimelineApiController: MastodonTimelineApiController
|
||||||
|
|
||||||
|
@ -41,7 +47,8 @@ class MastodonTimelineApiControllerTest {
|
||||||
mockMvc = MockMvcBuilders.standaloneSetup(mastodonTimelineApiController).build()
|
mockMvc = MockMvcBuilders.standaloneSetup(mastodonTimelineApiController).build()
|
||||||
}
|
}
|
||||||
|
|
||||||
val statusList = listOf<Status>(
|
val statusList = PaginationList<Status, Long>(
|
||||||
|
listOf<Status>(
|
||||||
Status(
|
Status(
|
||||||
id = "",
|
id = "",
|
||||||
uri = "",
|
uri = "",
|
||||||
|
@ -142,6 +149,7 @@ class MastodonTimelineApiControllerTest {
|
||||||
editedAt = null
|
editedAt = null
|
||||||
|
|
||||||
)
|
)
|
||||||
|
), null, null
|
||||||
)
|
)
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -156,10 +164,7 @@ class MastodonTimelineApiControllerTest {
|
||||||
whenever(
|
whenever(
|
||||||
timelineApiService.homeTimeline(
|
timelineApiService.homeTimeline(
|
||||||
eq(1234),
|
eq(1234),
|
||||||
eq(123456),
|
any()
|
||||||
eq(54321),
|
|
||||||
eq(1234567),
|
|
||||||
eq(20)
|
|
||||||
)
|
)
|
||||||
).doReturn(statusList)
|
).doReturn(statusList)
|
||||||
|
|
||||||
|
@ -183,10 +188,7 @@ class MastodonTimelineApiControllerTest {
|
||||||
whenever(
|
whenever(
|
||||||
timelineApiService.homeTimeline(
|
timelineApiService.homeTimeline(
|
||||||
eq(1234),
|
eq(1234),
|
||||||
isNull(),
|
any()
|
||||||
isNull(),
|
|
||||||
isNull(),
|
|
||||||
eq(20)
|
|
||||||
)
|
)
|
||||||
).doReturn(statusList)
|
).doReturn(statusList)
|
||||||
|
|
||||||
|
@ -213,10 +215,7 @@ class MastodonTimelineApiControllerTest {
|
||||||
localOnly = eq(false),
|
localOnly = eq(false),
|
||||||
remoteOnly = eq(true),
|
remoteOnly = eq(true),
|
||||||
mediaOnly = eq(false),
|
mediaOnly = eq(false),
|
||||||
maxId = eq(1234),
|
any()
|
||||||
minId = eq(4321),
|
|
||||||
sinceId = eq(12345),
|
|
||||||
limit = eq(20)
|
|
||||||
)
|
)
|
||||||
).doAnswer {
|
).doAnswer {
|
||||||
println(it.arguments.joinToString())
|
println(it.arguments.joinToString())
|
||||||
|
@ -245,10 +244,7 @@ class MastodonTimelineApiControllerTest {
|
||||||
localOnly = eq(false),
|
localOnly = eq(false),
|
||||||
remoteOnly = eq(false),
|
remoteOnly = eq(false),
|
||||||
mediaOnly = eq(false),
|
mediaOnly = eq(false),
|
||||||
maxId = isNull(),
|
any()
|
||||||
minId = isNull(),
|
|
||||||
sinceId = isNull(),
|
|
||||||
limit = eq(20)
|
|
||||||
)
|
)
|
||||||
).doAnswer {
|
).doAnswer {
|
||||||
println(it.arguments.joinToString())
|
println(it.arguments.joinToString())
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package dev.usbharu.hideout.mastodon.service.account
|
package dev.usbharu.hideout.mastodon.service.account
|
||||||
|
|
||||||
import dev.usbharu.hideout.application.external.Transaction
|
import dev.usbharu.hideout.application.external.Transaction
|
||||||
|
import dev.usbharu.hideout.application.infrastructure.exposed.Page
|
||||||
|
import dev.usbharu.hideout.application.infrastructure.exposed.PaginationList
|
||||||
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.relationship.RelationshipRepository
|
import dev.usbharu.hideout.core.domain.model.relationship.RelationshipRepository
|
||||||
import dev.usbharu.hideout.core.query.FollowerQueryService
|
import dev.usbharu.hideout.core.query.FollowerQueryService
|
||||||
|
@ -55,7 +57,8 @@ class AccountApiServiceImplTest {
|
||||||
@InjectMocks
|
@InjectMocks
|
||||||
private lateinit var accountApiServiceImpl: AccountApiServiceImpl
|
private lateinit var accountApiServiceImpl: AccountApiServiceImpl
|
||||||
|
|
||||||
private val statusList = listOf(
|
private val statusList = PaginationList<Status, Long>(
|
||||||
|
listOf(
|
||||||
Status(
|
Status(
|
||||||
id = "",
|
id = "",
|
||||||
uri = "",
|
uri = "",
|
||||||
|
@ -105,6 +108,7 @@ class AccountApiServiceImplTest {
|
||||||
text = "Test",
|
text = "Test",
|
||||||
editedAt = null
|
editedAt = null
|
||||||
)
|
)
|
||||||
|
), null, null
|
||||||
)
|
)
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -114,16 +118,13 @@ class AccountApiServiceImplTest {
|
||||||
whenever(
|
whenever(
|
||||||
statusQueryService.accountsStatus(
|
statusQueryService.accountsStatus(
|
||||||
accountId = eq(userId),
|
accountId = eq(userId),
|
||||||
maxId = isNull(),
|
|
||||||
sinceId = isNull(),
|
|
||||||
minId = isNull(),
|
|
||||||
limit = eq(20),
|
|
||||||
onlyMedia = eq(false),
|
onlyMedia = eq(false),
|
||||||
excludeReplies = eq(false),
|
excludeReplies = eq(false),
|
||||||
excludeReblogs = eq(false),
|
excludeReblogs = eq(false),
|
||||||
pinned = eq(false),
|
pinned = eq(false),
|
||||||
tagged = isNull(),
|
tagged = isNull(),
|
||||||
includeFollowers = eq(false)
|
includeFollowers = eq(false),
|
||||||
|
page = any()
|
||||||
)
|
)
|
||||||
).doReturn(
|
).doReturn(
|
||||||
statusList
|
statusList
|
||||||
|
@ -132,16 +133,13 @@ class AccountApiServiceImplTest {
|
||||||
|
|
||||||
val accountsStatuses = accountApiServiceImpl.accountsStatuses(
|
val accountsStatuses = accountApiServiceImpl.accountsStatuses(
|
||||||
userid = userId,
|
userid = userId,
|
||||||
maxId = null,
|
|
||||||
sinceId = null,
|
|
||||||
minId = null,
|
|
||||||
limit = 20,
|
|
||||||
onlyMedia = false,
|
onlyMedia = false,
|
||||||
excludeReplies = false,
|
excludeReplies = false,
|
||||||
excludeReblogs = false,
|
excludeReblogs = false,
|
||||||
pinned = false,
|
pinned = false,
|
||||||
tagged = null,
|
tagged = null,
|
||||||
loginUser = null
|
loginUser = null,
|
||||||
|
Page.of()
|
||||||
)
|
)
|
||||||
|
|
||||||
assertThat(accountsStatuses).hasSize(1)
|
assertThat(accountsStatuses).hasSize(1)
|
||||||
|
@ -156,31 +154,25 @@ class AccountApiServiceImplTest {
|
||||||
whenever(
|
whenever(
|
||||||
statusQueryService.accountsStatus(
|
statusQueryService.accountsStatus(
|
||||||
accountId = eq(userId),
|
accountId = eq(userId),
|
||||||
maxId = isNull(),
|
|
||||||
sinceId = isNull(),
|
|
||||||
minId = isNull(),
|
|
||||||
limit = eq(20),
|
|
||||||
onlyMedia = eq(false),
|
onlyMedia = eq(false),
|
||||||
excludeReplies = eq(false),
|
excludeReplies = eq(false),
|
||||||
excludeReblogs = eq(false),
|
excludeReblogs = eq(false),
|
||||||
pinned = eq(false),
|
pinned = eq(false),
|
||||||
tagged = isNull(),
|
tagged = isNull(),
|
||||||
includeFollowers = eq(false)
|
includeFollowers = eq(false),
|
||||||
|
page = any()
|
||||||
)
|
)
|
||||||
).doReturn(statusList)
|
).doReturn(statusList)
|
||||||
|
|
||||||
val accountsStatuses = accountApiServiceImpl.accountsStatuses(
|
val accountsStatuses = accountApiServiceImpl.accountsStatuses(
|
||||||
userid = userId,
|
userid = userId,
|
||||||
maxId = null,
|
|
||||||
sinceId = null,
|
|
||||||
minId = null,
|
|
||||||
limit = 20,
|
|
||||||
onlyMedia = false,
|
onlyMedia = false,
|
||||||
excludeReplies = false,
|
excludeReplies = false,
|
||||||
excludeReblogs = false,
|
excludeReblogs = false,
|
||||||
pinned = false,
|
pinned = false,
|
||||||
tagged = null,
|
tagged = null,
|
||||||
loginUser = loginUser
|
loginUser = loginUser,
|
||||||
|
Page.of()
|
||||||
)
|
)
|
||||||
|
|
||||||
assertThat(accountsStatuses).hasSize(1)
|
assertThat(accountsStatuses).hasSize(1)
|
||||||
|
@ -193,16 +185,13 @@ class AccountApiServiceImplTest {
|
||||||
whenever(
|
whenever(
|
||||||
statusQueryService.accountsStatus(
|
statusQueryService.accountsStatus(
|
||||||
accountId = eq(userId),
|
accountId = eq(userId),
|
||||||
maxId = isNull(),
|
|
||||||
sinceId = isNull(),
|
|
||||||
minId = isNull(),
|
|
||||||
limit = eq(20),
|
|
||||||
onlyMedia = eq(false),
|
onlyMedia = eq(false),
|
||||||
excludeReplies = eq(false),
|
excludeReplies = eq(false),
|
||||||
excludeReblogs = eq(false),
|
excludeReblogs = eq(false),
|
||||||
pinned = eq(false),
|
pinned = eq(false),
|
||||||
tagged = isNull(),
|
tagged = isNull(),
|
||||||
includeFollowers = eq(true)
|
includeFollowers = eq(true),
|
||||||
|
page = any()
|
||||||
)
|
)
|
||||||
).doReturn(statusList)
|
).doReturn(statusList)
|
||||||
|
|
||||||
|
@ -221,16 +210,13 @@ class AccountApiServiceImplTest {
|
||||||
|
|
||||||
val accountsStatuses = accountApiServiceImpl.accountsStatuses(
|
val accountsStatuses = accountApiServiceImpl.accountsStatuses(
|
||||||
userid = userId,
|
userid = userId,
|
||||||
maxId = null,
|
|
||||||
sinceId = null,
|
|
||||||
minId = null,
|
|
||||||
limit = 20,
|
|
||||||
onlyMedia = false,
|
onlyMedia = false,
|
||||||
excludeReplies = false,
|
excludeReplies = false,
|
||||||
excludeReblogs = false,
|
excludeReblogs = false,
|
||||||
pinned = false,
|
pinned = false,
|
||||||
tagged = null,
|
tagged = null,
|
||||||
loginUser = loginUser
|
loginUser = loginUser,
|
||||||
|
Page.of()
|
||||||
)
|
)
|
||||||
|
|
||||||
assertThat(accountsStatuses).hasSize(1)
|
assertThat(accountsStatuses).hasSize(1)
|
||||||
|
|
Loading…
Reference in New Issue