fix: adjust for new API changes

This commit is contained in:
Harsh Shandilya 2024-03-16 09:48:08 +05:30
parent 86a40d2e84
commit 85fc5cac21
20 changed files with 65 additions and 90 deletions

View File

@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
### Fixed
* Adapt to changes in lobste.rs API
## [1.41.0] - 2024-03-07
### Fixed

View File

@ -8,7 +8,6 @@ package dev.msfjarvis.claw.api.converters
import dev.msfjarvis.claw.api.LobstersApi
import dev.msfjarvis.claw.model.LobstersPost
import dev.msfjarvis.claw.model.User
import java.lang.reflect.Type
import okhttp3.ResponseBody
import org.jsoup.Jsoup
@ -32,8 +31,7 @@ object SearchConverter : Converter<ResponseBody, List<LobstersPost>> {
val url = titleElement.attr("href")
val tags = elem.select("span.tags > a").map(Element::text)
val (commentCount, commentsUrl) = getCommentsData(elem.select("span.comments_label"))
val submitter =
getSubmitter(elem.select("div.byline").first() ?: error("No byline element found"))
val submitter = elem.select("div.byline > a.u-author").text()
return LobstersPost(
shortId = shortId,
title = title,
@ -55,24 +53,6 @@ object SearchConverter : Converter<ResponseBody, List<LobstersPost>> {
return (countString.toIntOrNull() ?: 0) to commentsUrl
}
/**
* Make a bare-bones [User] object given a byline [elem]. We only need this to be usable for
* displaying in a list.
*/
private fun getSubmitter(elem: Element): User {
val userElement = elem.select("a.u-author")
val avatarElement = elem.select("img.avatar")
val username = userElement.text()
val avatarUrl = avatarElement.attr("src")
return User(
username = username,
about = "",
invitedBy = null,
avatarUrl = avatarUrl,
createdAt = "",
)
}
object Factory : Converter.Factory() {
override fun responseBodyConverter(
type: Type,

View File

@ -33,7 +33,7 @@ class ApiTest {
val posts = api.getHottestPosts(1)
assertIs<Success<List<LobstersPost>>>(posts)
val commentsOnlyPosts = posts.value.asSequence().filter { it.url.isEmpty() }.toSet()
assertThat(commentsOnlyPosts).hasSize(2)
assertThat(commentsOnlyPosts).hasSize(1)
}
@Test

View File

@ -10,7 +10,6 @@ import com.google.common.truth.Truth.assertThat
import com.slack.eithernet.ApiResult
import com.slack.eithernet.test.newEitherNetController
import dev.msfjarvis.claw.model.LobstersPost
import dev.msfjarvis.claw.model.User
import dev.msfjarvis.claw.util.TestUtils.assertIs
import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.Test
@ -38,7 +37,7 @@ class SearchApiTest {
createdAt = "",
commentCount = 3,
commentsUrl = "https://lobste.rs/s/gjlsdg/chatgpt_visits_emacs_doctor",
submitter = User("xenodium", "", null, "/avatars/xenodium-16.png", ""),
submitter = "xenodium",
tags = listOf("ai", "emacs"),
description = "",
),
@ -50,7 +49,7 @@ class SearchApiTest {
createdAt = "",
commentCount = 0,
commentsUrl = "https://lobste.rs/s/astcqf/implementing_question_answering_system",
submitter = User("asteroid", "", null, "/avatars/asteroid-16.png", ""),
submitter = "asteroid",
tags = listOf("ai"),
description = "",
),

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
{"username":"msfjarvis","created_at":"2020-04-24T11:41:56.000-05:00","is_admin":false,"about":"Android and Kotlin developer\r\n","is_moderator":false,"karma":574,"avatar_url":"/avatars/msfjarvis-100.png","invited_by_user":"Amolith","github_username":"msfjarvis","twitter_username":"msfjarvis"}
{"username":"msfjarvis","created_at":"2020-04-24T11:41:56.000-05:00","is_admin":false,"about":"Android and Kotlin developer, currently working for [Dyte](https://dyte.io/)","is_moderator":false,"karma":1343,"avatar_url":"/avatars/msfjarvis-100.png","invited_by_user":"Amolith","github_username":"msfjarvis"}

File diff suppressed because one or more lines are too long

View File

@ -90,13 +90,11 @@ internal fun CommentsHeader(
Spacer(Modifier.height(4.dp))
}
Submitter(
text = AnnotatedString("Submitted by ${post.submitter.username}"),
avatarUrl = "https://lobste.rs/${post.submitter.avatarUrl}",
contentDescription = "User avatar for ${post.submitter.username}",
text = AnnotatedString("Submitted by ${post.submitter}"),
avatarUrl = "https://lobste.rs/avatars/${post.submitter}-100.png",
contentDescription = "User avatar for ${post.submitter}",
modifier =
Modifier.clickable {
uriHandler.openUri("https://lobste.rs/u/${post.submitter.username}")
},
Modifier.clickable { uriHandler.openUri("https://lobste.rs/u/${post.submitter}") },
)
}
}
@ -156,16 +154,15 @@ internal fun CommentEntry(
Submitter(
text =
buildCommenterString(
commenterName = comment.user.username,
commenterName = comment.user,
score = comment.score,
isUnread = commentNode.isUnread,
createdAt = comment.createdAt,
updatedAt = comment.updatedAt,
),
avatarUrl = "https://lobste.rs/${comment.user.avatarUrl}",
contentDescription = "User avatar for ${comment.user.username}",
modifier =
Modifier.clickable { uriHandler.openUri("https://lobste.rs/u/${comment.user.username}") },
avatarUrl = "https://lobste.rs/avatars/${comment.user}-100.png",
contentDescription = "User avatar for ${comment.user}",
modifier = Modifier.clickable { uriHandler.openUri("https://lobste.rs/u/${comment.user}") },
)
if (commentNode.isExpanded) {
ThemedRichText(

View File

@ -53,7 +53,6 @@ import dev.msfjarvis.claw.common.ui.NetworkImage
import dev.msfjarvis.claw.common.ui.preview.ThemePreviews
import dev.msfjarvis.claw.model.LinkMetadata
import dev.msfjarvis.claw.model.UIPost
import dev.msfjarvis.claw.model.User
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toImmutableList
@ -122,9 +121,9 @@ fun PostDetails(post: UIPost, isRead: Boolean, modifier: Modifier = Modifier) {
TagRow(tags = post.tags.toImmutableList())
Spacer(Modifier.height(4.dp))
Submitter(
text = AnnotatedString("Submitted by ${post.submitter.username}"),
avatarUrl = "https://lobste.rs/${post.submitter.avatarUrl}",
contentDescription = "User avatar for ${post.submitter.username}",
text = AnnotatedString("Submitted by ${post.submitter}"),
avatarUrl = "https://lobste.rs/avatars/${post.submitter}-100.png",
contentDescription = "User avatar for ${post.submitter}",
)
}
}
@ -249,7 +248,7 @@ private fun LobstersCardPreview() {
createdAt = "2020-09-21T08:04:24.000-05:00",
commentCount = 1,
commentsUrl = "https://lobste.rs/s/q1hh1g/simple_anomaly_detection_using_plain_sql",
submitter = User("Haki", "", "", "/avatars/Haki-100.png", ""),
submitter = "Haki",
tags = listOf("databases", "apis"),
description = "",
isSaved = true,
@ -275,7 +274,7 @@ private fun LobstersCardPreview() {
commentsUrl = "https://lobste.rs/s/q1hh1g/simple_anomaly_detection_using_plain_sql",
tags = listOf("databases", "apis"),
description = "",
submitter = User("Haki", "", "", "", ""),
submitter = "Haki",
comments = emptyList(),
)
}

View File

@ -1,5 +1,5 @@
/*
* Copyright © 2023 Harsh Shandilya.
* Copyright © 2023-2024 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.
@ -32,7 +32,6 @@ object SavedPostSerializer : KSerializer<SavedPost> {
element<Int?>("commentCount", isOptional = true)
element<String>("commentsUrl")
element<String>("submitterName")
element<String>("submitterAvatarUrl")
element<List<String>>("tags")
element<String>("description")
}
@ -46,7 +45,6 @@ object SavedPostSerializer : KSerializer<SavedPost> {
var commentCount: Int? = null
var commentsUrl = ""
var submitterName = ""
var submitterAvatarUrl = ""
var tags = emptyList<String>()
var description = ""
while (true) {
@ -58,9 +56,8 @@ object SavedPostSerializer : KSerializer<SavedPost> {
4 -> commentCount = decodeNullableSerializableElement(descriptor, 4, Int.serializer())
5 -> commentsUrl = decodeStringElement(descriptor, 5)
6 -> submitterName = decodeStringElement(descriptor, 6)
7 -> submitterAvatarUrl = decodeStringElement(descriptor, 7)
8 -> tags = decodeSerializableElement(descriptor, 8, delegateSerializer)
9 -> description = decodeStringElement(descriptor, 9)
7 -> tags = decodeSerializableElement(descriptor, 7, delegateSerializer)
8 -> description = decodeStringElement(descriptor, 8)
CompositeDecoder.DECODE_DONE -> break
else -> error("Unexpected index: $index")
}
@ -73,7 +70,6 @@ object SavedPostSerializer : KSerializer<SavedPost> {
commentCount = commentCount,
commentsUrl = commentsUrl,
submitterName = submitterName,
submitterAvatarUrl = submitterAvatarUrl,
tags = tags,
description = description,
)
@ -89,9 +85,8 @@ object SavedPostSerializer : KSerializer<SavedPost> {
encodeNullableSerializableElement(descriptor, 4, Int.serializer(), value.commentCount)
encodeStringElement(descriptor, 5, value.commentsUrl)
encodeStringElement(descriptor, 6, value.submitterName)
encodeStringElement(descriptor, 7, value.submitterAvatarUrl)
encodeSerializableElement(descriptor, 8, delegateSerializer, value.tags)
encodeStringElement(descriptor, 9, value.description)
encodeSerializableElement(descriptor, 7, delegateSerializer, value.tags)
encodeStringElement(descriptor, 8, value.description)
}
}
}

View File

@ -10,7 +10,6 @@ CREATE TABLE IF NOT EXISTS SavedPost(
commentCount INTEGER AS Int,
commentsUrl TEXT NOT NULL,
submitterName TEXT NOT NULL,
submitterAvatarUrl TEXT NOT NULL,
tags TEXT AS List<String> NOT NULL,
description TEXT NOT NULL DEFAULT ""
);

View File

@ -1,3 +1,3 @@
CREATE TABLE ReadPosts(
CREATE TABLE IF NOT EXISTS ReadPosts(
id TEXT NOT NULL PRIMARY KEY
);

View File

@ -0,0 +1,23 @@
import kotlin.Int;
import kotlin.String;
import kotlin.collections.List;
ALTER TABLE SavedPost RENAME TO SavedPost_Old;
CREATE TABLE IF NOT EXISTS SavedPost(
shortId TEXT NOT NULL PRIMARY KEY,
title TEXT NOT NULL,
url TEXT NOT NULL,
createdAt TEXT NOT NULL,
commentCount INTEGER AS Int,
commentsUrl TEXT NOT NULL,
submitterName TEXT NOT NULL,
tags TEXT AS List<String> NOT NULL,
description TEXT NOT NULL DEFAULT ""
);
INSERT INTO SavedPost(shortId, title, url, createdAt, commentCount, commentsUrl, submitterName, tags, description)
SELECT shortId, title, url, createdAt, commentCount, commentsUrl, submitterName, tags, description
FROM SavedPost_Old;
DROP TABLE SavedPost_Old;

View File

@ -1,5 +1,5 @@
/*
* Copyright © 2023 Harsh Shandilya.
* Copyright © 2023-2024 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.
@ -52,7 +52,6 @@ class SavedPostSerializerTest {
commentCount = 13,
commentsUrl = "https://lobste.rs/s/nbigsf/fun_format_friday_you_now_have_super",
submitterName = "LenFalken",
submitterAvatarUrl = "/avatars/LenFalken-100.png",
tags = listOf("ask", "programming"),
description =
"<p>You suddenly have in your possession a super computer. What comes next? What projects are suddenly possible for you? What performance tests can you now explore?</p>\n",

View File

@ -1 +1 @@
{"short_id":"nbigsf","title":"Fun Format Friday: You now have a super computer. What next?","url":"","created_at":"2023-05-04T23:43:50.000-05:00","comment_count":13,"comments_url":"https://lobste.rs/s/nbigsf/fun_format_friday_you_now_have_super","submitter_name":"LenFalken","submitter_avatar_url":"/avatars/LenFalken-100.png","tags":["ask","programming"],"description":"<p>You suddenly have in your possession a super computer. What comes next? What projects are suddenly possible for you? What performance tests can you now explore?</p>\n"}
{"short_id":"nbigsf","title":"Fun Format Friday: You now have a super computer. What next?","url":"","created_at":"2023-05-04T23:43:50.000-05:00","comment_count":13,"comments_url":"https://lobste.rs/s/nbigsf/fun_format_friday_you_now_have_super","submitter_name":"LenFalken","tags":["ask","programming"],"description":"<p>You suddenly have in your possession a super computer. What comes next? What projects are suddenly possible for you? What performance tests can you now explore?</p>\n"}

View File

@ -122,7 +122,6 @@ class SavedPostQueriesTest {
commentCount = 0,
commentsUrl = "test_comments_url",
submitterName = "test_user_$i",
submitterAvatarUrl = "test_avatar_url",
tags = listOf(),
description = "",
)

View File

@ -1,5 +1,5 @@
/*
* Copyright © 2021-2023 Harsh Shandilya.
* Copyright © 2021-2024 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.
@ -24,5 +24,5 @@ class Comment(
@Serializable(with = JavaInstantSerializer::class) val createdAt: TemporalAccessor,
@Serializable(with = JavaInstantSerializer::class) val updatedAt: TemporalAccessor,
val parentComment: String?,
@SerialName("commenting_user") val user: User,
@SerialName("commenting_user") val user: String,
)

View File

@ -18,11 +18,7 @@ import kotlinx.serialization.Serializable
@Poko
@KonvertTo(
value = UIPost::class,
mappings =
[
Mapping(target = "submitterName", expression = "it.submitter.username"),
Mapping(target = "submitterAvatarUrl", expression = "it.submitter.avatarUrl"),
],
mappings = [Mapping(target = "submitterName", expression = "it.submitter.username")],
)
class LobstersPost(
val shortId: String,
@ -32,6 +28,6 @@ class LobstersPost(
val description: String,
val commentCount: Int,
val commentsUrl: String,
@SerialName("submitter_user") val submitter: User,
@SerialName("submitter_user") val submitter: String,
val tags: List<String>,
)

View File

@ -19,19 +19,11 @@ import kotlinx.serialization.Serializable
@Poko
@KonvertTo(
value = UIPost::class,
mappings =
[
Mapping(target = "submitterName", expression = "it.submitter.username"),
Mapping(target = "submitterAvatarUrl", expression = "it.submitter.avatarUrl"),
],
mappings = [Mapping(target = "submitterName", expression = "it.submitter")],
)
@KonvertTo(
value = SavedPost::class,
mappings =
[
Mapping(target = "submitterName", expression = "it.submitter.username"),
Mapping(target = "submitterAvatarUrl", expression = "it.submitter.avatarUrl"),
],
mappings = [Mapping(target = "submitterName", expression = "it.submitter")],
)
class LobstersPostDetails(
val shortId: String,
@ -41,7 +33,7 @@ class LobstersPostDetails(
val description: String,
val commentCount: Int,
val commentsUrl: String,
@SerialName("submitter_user") val submitter: User,
@SerialName("submitter_user") val submitter: String,
val tags: List<String>,
val comments: List<Comment>,
)

View File

@ -14,11 +14,7 @@ import kotlinx.serialization.SerialName
@KonvertTo(
value = SavedPost::class,
mappings =
[
Mapping(target = "submitterName", expression = "it.submitter.username"),
Mapping(target = "submitterAvatarUrl", expression = "it.submitter.avatarUrl"),
],
mappings = [Mapping(target = "submitterName", expression = "it.submitter")],
)
data class UIPost(
val shortId: String,
@ -28,7 +24,7 @@ data class UIPost(
val description: String,
val commentCount: Int,
val commentsUrl: String,
@SerialName("submitter_user") val submitter: User,
@SerialName("submitter_user") val submitter: String,
val tags: List<String>,
val comments: List<Comment> = emptyList(),
val isSaved: Boolean = false,
@ -38,10 +34,7 @@ data class UIPost(
value = SavedPost::class,
mappings =
[
Mapping(
target = "submitter",
expression = "User(it.submitterName, \"\", null, it.submitterAvatarUrl, \"\")",
),
Mapping(target = "submitter", expression = "it.submitterName"),
Mapping(target = "commentCount", expression = "it.commentCount ?: 0"),
Mapping(target = "isSaved", expression = "true"),
],