mirror of
https://github.com/msfjarvis/compose-lobsters
synced 2025-08-14 15:17:05 +05:30
refactor: remove all Shiori code
Their API is Terrible, Horrible, No Good, Very Bad[1][2] 1: It's _fine_ but I want more 2: https://en.wikipedia.org/wiki/Alexander_and_the_Terrible,_Horrible,_No_Good,_Very_Bad_Day
This commit is contained in:
parent
1d5302f26c
commit
6084e5bb30
13 changed files with 0 additions and 391 deletions
|
@ -27,7 +27,6 @@ dependencies {
|
||||||
implementation(libs.jsoup)
|
implementation(libs.jsoup)
|
||||||
|
|
||||||
testImplementation(testFixtures(libs.eithernet))
|
testImplementation(testFixtures(libs.eithernet))
|
||||||
testImplementation(libs.testcontainers)
|
|
||||||
testImplementation(libs.kotlinx.coroutines.test)
|
testImplementation(libs.kotlinx.coroutines.test)
|
||||||
testImplementation(libs.kotlinx.serialization.json)
|
testImplementation(libs.kotlinx.serialization.json)
|
||||||
testImplementation(libs.retrofit.kotlinxSerializationConverter)
|
testImplementation(libs.retrofit.kotlinxSerializationConverter)
|
||||||
|
|
|
@ -1,53 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright © 2023 Harsh Shandilya.
|
|
||||||
* Use of this source code is governed by an MIT-style
|
|
||||||
* license that can be found in the LICENSE file or at
|
|
||||||
* https://opensource.org/licenses/MIT.
|
|
||||||
*/
|
|
||||||
package dev.msfjarvis.claw.api
|
|
||||||
|
|
||||||
import com.slack.eithernet.ApiResult
|
|
||||||
import dev.msfjarvis.claw.model.shiori.AuthRequest
|
|
||||||
import dev.msfjarvis.claw.model.shiori.AuthResponse
|
|
||||||
import dev.msfjarvis.claw.model.shiori.Bookmark
|
|
||||||
import dev.msfjarvis.claw.model.shiori.BookmarkRequest
|
|
||||||
import dev.msfjarvis.claw.model.shiori.BookmarksResponse
|
|
||||||
import dev.msfjarvis.claw.model.shiori.EditedBookmark
|
|
||||||
import retrofit2.http.Body
|
|
||||||
import retrofit2.http.GET
|
|
||||||
import retrofit2.http.HTTP
|
|
||||||
import retrofit2.http.Header
|
|
||||||
import retrofit2.http.POST
|
|
||||||
import retrofit2.http.PUT
|
|
||||||
|
|
||||||
private const val SESSION_ID_HEADER = "X-Session-Id"
|
|
||||||
|
|
||||||
interface ShioriApi {
|
|
||||||
@POST("/api/login") suspend fun login(@Body body: AuthRequest): ApiResult<AuthResponse, Unit>
|
|
||||||
|
|
||||||
@HTTP(method = "POST", path = "/api/logout", hasBody = false)
|
|
||||||
suspend fun logout(@Header(SESSION_ID_HEADER) sessionId: String): ApiResult<Unit, Unit>
|
|
||||||
|
|
||||||
@GET("/api/bookmarks")
|
|
||||||
suspend fun getBookmarks(
|
|
||||||
@Header(SESSION_ID_HEADER) sessionId: String,
|
|
||||||
): ApiResult<BookmarksResponse, Unit>
|
|
||||||
|
|
||||||
@POST("/api/bookmarks")
|
|
||||||
suspend fun addBookmark(
|
|
||||||
@Header(SESSION_ID_HEADER) sessionId: String,
|
|
||||||
@Body bookmarkRequest: BookmarkRequest,
|
|
||||||
): ApiResult<Bookmark, Unit>
|
|
||||||
|
|
||||||
@PUT("/api/bookmarks")
|
|
||||||
suspend fun editBookmark(
|
|
||||||
@Header(SESSION_ID_HEADER) sessionId: String,
|
|
||||||
@Body bookmark: EditedBookmark,
|
|
||||||
): ApiResult<Bookmark, Unit>
|
|
||||||
|
|
||||||
@HTTP(method = "DELETE", path = "/api/bookmarks", hasBody = true)
|
|
||||||
suspend fun deleteBookmark(
|
|
||||||
@Header(SESSION_ID_HEADER) sessionId: String,
|
|
||||||
@Body ids: List<Int>,
|
|
||||||
): ApiResult<Int, Unit>
|
|
||||||
}
|
|
|
@ -16,7 +16,6 @@ import dagger.multibindings.IntKey
|
||||||
import dagger.multibindings.IntoMap
|
import dagger.multibindings.IntoMap
|
||||||
import dev.msfjarvis.claw.api.LobstersApi
|
import dev.msfjarvis.claw.api.LobstersApi
|
||||||
import dev.msfjarvis.claw.api.LobstersSearchApi
|
import dev.msfjarvis.claw.api.LobstersSearchApi
|
||||||
import dev.msfjarvis.claw.api.ShioriApi
|
|
||||||
import dev.msfjarvis.claw.api.converters.CSRFTokenConverter
|
import dev.msfjarvis.claw.api.converters.CSRFTokenConverter
|
||||||
import dev.msfjarvis.claw.api.converters.SearchConverter
|
import dev.msfjarvis.claw.api.converters.SearchConverter
|
||||||
import javax.inject.Named
|
import javax.inject.Named
|
||||||
|
@ -74,8 +73,6 @@ object RetrofitModule {
|
||||||
@Provides
|
@Provides
|
||||||
fun provideSearchApi(@SearchApi retrofit: Retrofit): LobstersSearchApi = retrofit.create()
|
fun provideSearchApi(@SearchApi retrofit: Retrofit): LobstersSearchApi = retrofit.create()
|
||||||
|
|
||||||
@Provides fun provideShioriApi(retrofit: Retrofit): ShioriApi = retrofit.create()
|
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@IntKey(0)
|
@IntKey(0)
|
||||||
@IntoMap
|
@IntoMap
|
||||||
|
|
|
@ -1,173 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright © 2023 Harsh Shandilya.
|
|
||||||
* Use of this source code is governed by an MIT-style
|
|
||||||
* license that can be found in the LICENSE file or at
|
|
||||||
* https://opensource.org/licenses/MIT.
|
|
||||||
*/
|
|
||||||
package dev.msfjarvis.claw.api
|
|
||||||
|
|
||||||
import com.google.common.truth.Truth.assertThat
|
|
||||||
import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
|
|
||||||
import com.slack.eithernet.ApiResultCallAdapterFactory
|
|
||||||
import com.slack.eithernet.ApiResultConverterFactory
|
|
||||||
import com.slack.eithernet.successOrNull
|
|
||||||
import dev.msfjarvis.claw.model.shiori.AuthRequest
|
|
||||||
import dev.msfjarvis.claw.model.shiori.AuthResponse
|
|
||||||
import dev.msfjarvis.claw.model.shiori.Bookmark
|
|
||||||
import dev.msfjarvis.claw.model.shiori.BookmarkRequest
|
|
||||||
import dev.msfjarvis.claw.model.shiori.BookmarksResponse
|
|
||||||
import dev.msfjarvis.claw.model.shiori.EditedBookmark
|
|
||||||
import dev.msfjarvis.claw.model.shiori.Tag
|
|
||||||
import dev.msfjarvis.claw.util.TestUtils.assertIs
|
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import kotlinx.coroutines.test.runTest
|
|
||||||
import kotlinx.serialization.json.Json
|
|
||||||
import okhttp3.MediaType
|
|
||||||
import org.junit.jupiter.api.AfterEach
|
|
||||||
import org.junit.jupiter.api.BeforeEach
|
|
||||||
import org.junit.jupiter.api.Test
|
|
||||||
import org.testcontainers.containers.GenericContainer
|
|
||||||
import retrofit2.Retrofit
|
|
||||||
import retrofit2.create
|
|
||||||
|
|
||||||
class ShioriApiTest {
|
|
||||||
|
|
||||||
private lateinit var credentials: AuthResponse
|
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
fun setUp() {
|
|
||||||
container.start()
|
|
||||||
runBlocking {
|
|
||||||
credentials =
|
|
||||||
requireNotNull(api.login(AuthRequest(USER, PASSWORD)).successOrNull()) { "Login failed" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@AfterEach
|
|
||||||
fun tearDown() {
|
|
||||||
container.stop()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun getBookmarks() = runTest {
|
|
||||||
val response = api.getBookmarks(credentials.session).successOrNull()
|
|
||||||
assertIs<BookmarksResponse>(response)
|
|
||||||
assertThat(response.page).isEqualTo(1)
|
|
||||||
assertThat(response.bookmarks).isEmpty()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun addBookmark() = runTest {
|
|
||||||
val response =
|
|
||||||
api
|
|
||||||
.addBookmark(
|
|
||||||
credentials.session,
|
|
||||||
BookmarkRequest(
|
|
||||||
"https://example.com",
|
|
||||||
false,
|
|
||||||
0,
|
|
||||||
emptyList(),
|
|
||||||
"Example Domain",
|
|
||||||
"""
|
|
||||||
This domain is for use in illustrative examples in documents.
|
|
||||||
You may use this domain in literature without prior coordination or asking for permission.
|
|
||||||
"""
|
|
||||||
.trimIndent(),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.successOrNull()
|
|
||||||
assertIs<Bookmark>(response)
|
|
||||||
assertThat(response.url).isEqualTo("https://example.com")
|
|
||||||
assertThat(response.title).isEqualTo("Example Domain")
|
|
||||||
assertThat(response.excerpt)
|
|
||||||
.isEqualTo(
|
|
||||||
"""
|
|
||||||
This domain is for use in illustrative examples in documents.
|
|
||||||
You may use this domain in literature without prior coordination or asking for permission.
|
|
||||||
"""
|
|
||||||
.trimIndent()
|
|
||||||
)
|
|
||||||
assertThat(response.id).isAtLeast(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun editBookmark() = runTest {
|
|
||||||
val response =
|
|
||||||
api
|
|
||||||
.addBookmark(
|
|
||||||
credentials.session,
|
|
||||||
BookmarkRequest(
|
|
||||||
"https://example.com",
|
|
||||||
false,
|
|
||||||
0,
|
|
||||||
emptyList(),
|
|
||||||
"Example Domain",
|
|
||||||
"""
|
|
||||||
This domain is for use in illustrative examples in documents.
|
|
||||||
You may use this domain in literature without prior coordination or asking for permission.
|
|
||||||
"""
|
|
||||||
.trimIndent(),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.successOrNull()
|
|
||||||
assertIs<Bookmark>(response)
|
|
||||||
assertThat(response.tags).isEmpty()
|
|
||||||
val newBookmark =
|
|
||||||
EditedBookmark(
|
|
||||||
id = response.id,
|
|
||||||
url = response.url,
|
|
||||||
title = response.title,
|
|
||||||
tags = listOf(Tag("examples")),
|
|
||||||
)
|
|
||||||
val edited = api.editBookmark(credentials.session, newBookmark).successOrNull()
|
|
||||||
assertIs<Bookmark>(edited)
|
|
||||||
assertThat(edited.tags).isNotEmpty()
|
|
||||||
assertThat(edited.tags).containsExactly(Tag("examples"))
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun deleteBookmark() = runTest {
|
|
||||||
val response =
|
|
||||||
api
|
|
||||||
.addBookmark(
|
|
||||||
credentials.session,
|
|
||||||
BookmarkRequest(
|
|
||||||
"https://example.com",
|
|
||||||
false,
|
|
||||||
0,
|
|
||||||
emptyList(),
|
|
||||||
"Example Domain",
|
|
||||||
"""
|
|
||||||
This domain is for use in illustrative examples in documents.
|
|
||||||
You may use this domain in literature without prior coordination or asking for permission.
|
|
||||||
"""
|
|
||||||
.trimIndent(),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.successOrNull()
|
|
||||||
assertIs<Bookmark>(response)
|
|
||||||
val count = api.deleteBookmark(credentials.session, listOf(response.id)).successOrNull()
|
|
||||||
assertThat(count).isEqualTo(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
// Default settings for the container
|
|
||||||
private const val USER = "shiori"
|
|
||||||
private const val PASSWORD = "gopher"
|
|
||||||
|
|
||||||
private val container =
|
|
||||||
GenericContainer("ghcr.io/go-shiori/shiori:v1.5.5").withExposedPorts(8080)
|
|
||||||
|
|
||||||
private val json = Json { ignoreUnknownKeys = true }
|
|
||||||
|
|
||||||
private val api
|
|
||||||
get() =
|
|
||||||
Retrofit.Builder()
|
|
||||||
.baseUrl("http://${container.host}:${container.firstMappedPort}")
|
|
||||||
.addConverterFactory(ApiResultConverterFactory)
|
|
||||||
.addConverterFactory(json.asConverterFactory(MediaType.get("application/json")))
|
|
||||||
.addCallAdapterFactory(ApiResultCallAdapterFactory)
|
|
||||||
.build()
|
|
||||||
.create<ShioriApi>()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -97,7 +97,6 @@ sqldelight-jvmDriver = { module = "app.cash.sqldelight:sqlite-driver", version.r
|
||||||
sqldelight-primitiveAdapters = { module = "app.cash.sqldelight:primitive-adapters", version.ref = "sqldelight" }
|
sqldelight-primitiveAdapters = { module = "app.cash.sqldelight:primitive-adapters", version.ref = "sqldelight" }
|
||||||
sqlite-android = "com.github.requery:sqlite-android:3.43.0"
|
sqlite-android = "com.github.requery:sqlite-android:3.43.0"
|
||||||
swipe = "me.saket.swipe:swipe:1.3.0-SNAPSHOT"
|
swipe = "me.saket.swipe:swipe:1.3.0-SNAPSHOT"
|
||||||
testcontainers = "org.testcontainers:testcontainers:1.19.3"
|
|
||||||
truth = "com.google.truth:truth:1.1.5"
|
truth = "com.google.truth:truth:1.1.5"
|
||||||
unfurl = "me.saket.unfurl:unfurl:1.7.0"
|
unfurl = "me.saket.unfurl:unfurl:1.7.0"
|
||||||
|
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright © 2021-2023 Harsh Shandilya.
|
|
||||||
* Use of this source code is governed by an MIT-style
|
|
||||||
* license that can be found in the LICENSE file or at
|
|
||||||
* https://opensource.org/licenses/MIT.
|
|
||||||
*/
|
|
||||||
package dev.msfjarvis.claw.model.shiori
|
|
||||||
|
|
||||||
import dev.drewhamilton.poko.Poko
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
@Poko
|
|
||||||
class Account(
|
|
||||||
val id: Int,
|
|
||||||
val username: String,
|
|
||||||
val owner: Boolean,
|
|
||||||
)
|
|
|
@ -1,19 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright © 2021-2023 Harsh Shandilya.
|
|
||||||
* Use of this source code is governed by an MIT-style
|
|
||||||
* license that can be found in the LICENSE file or at
|
|
||||||
* https://opensource.org/licenses/MIT.
|
|
||||||
*/
|
|
||||||
package dev.msfjarvis.claw.model.shiori
|
|
||||||
|
|
||||||
import dev.drewhamilton.poko.Poko
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
@Poko
|
|
||||||
class AuthRequest(
|
|
||||||
val username: String,
|
|
||||||
val password: String,
|
|
||||||
val remember: Boolean = true,
|
|
||||||
val owner: Boolean = false,
|
|
||||||
)
|
|
|
@ -1,18 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright © 2022-2023 Harsh Shandilya.
|
|
||||||
* Use of this source code is governed by an MIT-style
|
|
||||||
* license that can be found in the LICENSE file or at
|
|
||||||
* https://opensource.org/licenses/MIT.
|
|
||||||
*/
|
|
||||||
package dev.msfjarvis.claw.model.shiori
|
|
||||||
|
|
||||||
import dev.drewhamilton.poko.Poko
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
@Poko
|
|
||||||
class AuthResponse(
|
|
||||||
val session: String,
|
|
||||||
val expires: String,
|
|
||||||
val account: Account,
|
|
||||||
)
|
|
|
@ -1,27 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright © 2021-2023 Harsh Shandilya.
|
|
||||||
* Use of this source code is governed by an MIT-style
|
|
||||||
* license that can be found in the LICENSE file or at
|
|
||||||
* https://opensource.org/licenses/MIT.
|
|
||||||
*/
|
|
||||||
package dev.msfjarvis.claw.model.shiori
|
|
||||||
|
|
||||||
import dev.drewhamilton.poko.Poko
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
@Poko
|
|
||||||
class Bookmark(
|
|
||||||
val id: Int,
|
|
||||||
val url: String,
|
|
||||||
val title: String,
|
|
||||||
val excerpt: String,
|
|
||||||
val author: String,
|
|
||||||
val public: Int,
|
|
||||||
val modified: String,
|
|
||||||
val imageURL: String,
|
|
||||||
val hasContent: Boolean,
|
|
||||||
val hasArchive: Boolean,
|
|
||||||
val tags: List<Tag>,
|
|
||||||
val createArchive: Boolean,
|
|
||||||
)
|
|
|
@ -1,21 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright © 2021-2023 Harsh Shandilya.
|
|
||||||
* Use of this source code is governed by an MIT-style
|
|
||||||
* license that can be found in the LICENSE file or at
|
|
||||||
* https://opensource.org/licenses/MIT.
|
|
||||||
*/
|
|
||||||
package dev.msfjarvis.claw.model.shiori
|
|
||||||
|
|
||||||
import dev.drewhamilton.poko.Poko
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
@Poko
|
|
||||||
class BookmarkRequest(
|
|
||||||
val url: String,
|
|
||||||
val createArchive: Boolean,
|
|
||||||
val public: Int,
|
|
||||||
val tags: List<Tag>,
|
|
||||||
val title: String,
|
|
||||||
val excerpt: String,
|
|
||||||
)
|
|
|
@ -1,18 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright © 2022-2023 Harsh Shandilya.
|
|
||||||
* Use of this source code is governed by an MIT-style
|
|
||||||
* license that can be found in the LICENSE file or at
|
|
||||||
* https://opensource.org/licenses/MIT.
|
|
||||||
*/
|
|
||||||
package dev.msfjarvis.claw.model.shiori
|
|
||||||
|
|
||||||
import dev.drewhamilton.poko.Poko
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
@Poko
|
|
||||||
class BookmarksResponse(
|
|
||||||
val bookmarks: List<Bookmark>,
|
|
||||||
val maxPage: Int,
|
|
||||||
val page: Int,
|
|
||||||
)
|
|
|
@ -1,27 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright © 2023 Harsh Shandilya.
|
|
||||||
* Use of this source code is governed by an MIT-style
|
|
||||||
* license that can be found in the LICENSE file or at
|
|
||||||
* https://opensource.org/licenses/MIT.
|
|
||||||
*/
|
|
||||||
package dev.msfjarvis.claw.model.shiori
|
|
||||||
|
|
||||||
import dev.drewhamilton.poko.Poko
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
@Poko
|
|
||||||
class EditedBookmark(
|
|
||||||
val id: Int,
|
|
||||||
val url: String,
|
|
||||||
val title: String,
|
|
||||||
val excerpt: String? = null,
|
|
||||||
val author: String? = null,
|
|
||||||
val public: Int? = null,
|
|
||||||
val modified: String? = null,
|
|
||||||
val imageURL: String? = null,
|
|
||||||
val hasContent: Boolean? = null,
|
|
||||||
val hasArchive: Boolean? = null,
|
|
||||||
val tags: List<Tag>? = null,
|
|
||||||
val createArchive: Boolean? = null,
|
|
||||||
)
|
|
|
@ -1,12 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright © 2022-2023 Harsh Shandilya.
|
|
||||||
* Use of this source code is governed by an MIT-style
|
|
||||||
* license that can be found in the LICENSE file or at
|
|
||||||
* https://opensource.org/licenses/MIT.
|
|
||||||
*/
|
|
||||||
package dev.msfjarvis.claw.model.shiori
|
|
||||||
|
|
||||||
import dev.drewhamilton.poko.Poko
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable @Poko class Tag(val name: String)
|
|
Loading…
Add table
Add a link
Reference in a new issue