Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import uniffi.wp_api.UniffiWpApiClient
import uniffi.wp_api.UserAvatarSize
import uniffi.wp_api.WpErrorCode
import uniffi.wp_api.WpApiParamCommentsOrderBy
import uniffi.wp_api.WpApiParamCommentsStatus
import uniffi.wp_api.WpApiParamOrder
import java.util.Date
import java.util.concurrent.ConcurrentHashMap
Expand Down Expand Up @@ -143,7 +144,7 @@ class CommentsRsDataSource @Inject constructor(
}
}

fun firstPageParams(status: RsCommentStatus?, search: String? = null): CommentListParams =
fun firstPageParams(status: WpApiParamCommentsStatus?, search: String? = null): CommentListParams =
CommentListParams(
perPage = COMMENTS_PAGE_SIZE,
search = search,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,62 +2,60 @@ package org.wordpress.android.ui.commentsrs

import androidx.annotation.StringRes
import org.wordpress.android.R
import uniffi.wp_api.CommentStatus as RsCommentStatus
import uniffi.wp_api.WpApiParamCommentsStatus

/**
* Filter tabs for the rs comments list, matching the legacy unified list.
*
* [queryStatus] is the `status` query param for `/wp/v2/comments`. Three tabs use
* [RsCommentStatus.Custom] because `WP_Comment_Query` only recognises the literal values
* `approve` and `all` — wordpress-rs serialises [RsCommentStatus.Approved] as `approved`,
* which WordPress core treats as an unknown status and returns nothing for (wordpress-rs
* `comments.rs` serialisation test asserts `status=approved`). `all` means approved+hold,
* matching the legacy ALL filter (APPROVED+UNAPPROVED).
* [queryStatus] is the `status` query param for `/wp/v2/comments`.
* [WpApiParamCommentsStatus.All] is approved+hold, matching the legacy ALL filter
* (APPROVED+UNAPPROVED); [WpApiParamCommentsStatus.Any] additionally returns spam and trash.
*
* [UNREPLIED] has no server status: it queries `all` (like [ALL]) and is threaded client-side by
* [filterUnreplied] to keep only top-level comments the user hasn't replied to, mirroring legacy.
* [UNREPLIED] has no server status: it queries [WpApiParamCommentsStatus.All] (like [ALL]) and is
* threaded client-side by [filterUnreplied] to keep only top-level comments the user hasn't
* replied to, mirroring legacy.
*/
enum class CommentsRsListTab(
@StringRes val labelResId: Int,
@StringRes val emptyMessageResId: Int,
/** The `selected_filter` property value for COMMENT_FILTER_CHANGED, matching the legacy list. */
@StringRes val trackingLabelResId: Int,
val queryStatus: RsCommentStatus
val queryStatus: WpApiParamCommentsStatus
) {
ALL(
R.string.comment_status_all,
R.string.comments_empty_list,
R.string.comment_tracker_label_all,
RsCommentStatus.Custom("all")
WpApiParamCommentsStatus.All
),
PENDING(
R.string.comment_status_unapproved,
R.string.comments_empty_list_filtered_pending,
R.string.comment_tracker_label_pending,
RsCommentStatus.Hold
WpApiParamCommentsStatus.Hold
),
UNREPLIED(
R.string.comment_status_unreplied,
R.string.comments_empty_list_filtered_unreplied,
R.string.comment_tracker_label_unreplied,
RsCommentStatus.Custom("all")
WpApiParamCommentsStatus.All
),
APPROVED(
R.string.comment_status_approved,
R.string.comments_empty_list_filtered_approved,
R.string.comment_tracker_label_approved,
RsCommentStatus.Custom("approve")
WpApiParamCommentsStatus.Approve
),
SPAM(
R.string.comment_status_spam,
R.string.comments_empty_list_filtered_spam,
R.string.comment_tracker_label_spam,
RsCommentStatus.Spam
WpApiParamCommentsStatus.Spam
),
TRASHED(
R.string.comment_status_trash,
R.string.comments_empty_list_filtered_trashed,
R.string.comment_tracker_label_trashed,
RsCommentStatus.Trash
WpApiParamCommentsStatus.Trash
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,9 @@ class FetchAllDomainsUseCase @Inject constructor(
*
* `DefaultAddress` is the exact equivalent rather than an approximation:
* the server assigns that subtype to precisely the domains `no_wpcom`
* removed — free `*.wordpress.com` addresses along with staging, garden,
* managed, and partner subdomains.
* removed — the free `*.wordpress.com` address, along with the staging
* (`*.wpcomstaging.com`) and garden subdomains it also surfaces as a site
* address.
*/
suspend fun execute(): AllDomains {
val client = getOrCreateClient() ?: run {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import uniffi.wp_api.CommentWithViewContext
import uniffi.wp_api.UserAvatarSize
import uniffi.wp_api.WpAdditionalFields
import uniffi.wp_api.WpApiParamCommentsOrderBy
import uniffi.wp_api.WpApiParamCommentsStatus
import uniffi.wp_api.WpApiParamOrder
import java.util.Date
import uniffi.wp_api.CommentStatus as RsCommentStatus
Expand Down Expand Up @@ -69,10 +70,10 @@ class CommentsRsListMappingTest {
fun `firstPageParams requests newest comments with the given status and search`() {
val dataSource = CommentsRsDataSource(mock())

val params = dataSource.firstPageParams(RsCommentStatus.Spam, search = "query")
val params = dataSource.firstPageParams(WpApiParamCommentsStatus.Spam, search = "query")

assertThat(params.perPage).isEqualTo(CommentsRsDataSource.COMMENTS_PAGE_SIZE)
assertThat(params.status).isEqualTo(RsCommentStatus.Spam)
assertThat(params.status).isEqualTo(WpApiParamCommentsStatus.Spam)
assertThat(params.search).isEqualTo("query")
assertThat(params.orderby).isEqualTo(WpApiParamCommentsOrderBy.DATE_GMT)
assertThat(params.order).isEqualTo(WpApiParamOrder.DESC)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,24 @@ package org.wordpress.android.ui.commentsrs

import org.assertj.core.api.Assertions.assertThat
import org.junit.Test
import uniffi.wp_api.CommentStatus as RsCommentStatus
import uniffi.wp_api.WpApiParamCommentsStatus

class CommentsRsListTabTest {
@Test
fun `all tab queries status all which the server treats as approved plus hold`() {
assertThat(CommentsRsListTab.ALL.queryStatus).isEqualTo(RsCommentStatus.Custom("all"))
assertThat(CommentsRsListTab.ALL.queryStatus).isEqualTo(WpApiParamCommentsStatus.All)
}

@Test
fun `approved tab queries the literal approve status`() {
// WP_Comment_Query only recognises "approve"; the RsCommentStatus.Approved enum
// serialises to "approved", which the server treats as unknown and returns nothing for.
assertThat(CommentsRsListTab.APPROVED.queryStatus).isEqualTo(RsCommentStatus.Custom("approve"))
fun `approved tab queries the approve status`() {
assertThat(CommentsRsListTab.APPROVED.queryStatus).isEqualTo(WpApiParamCommentsStatus.Approve)
}

@Test
fun `unreplied tab queries status all and is threaded client-side`() {
// Unreplied has no server status: it fetches everything (approved + hold, like ALL) and
// Unreplied has no server status: it fetches approved + hold, like ALL, and
// filterUnreplied() narrows it to comments the user hasn't replied to.
assertThat(CommentsRsListTab.UNREPLIED.queryStatus).isEqualTo(RsCommentStatus.Custom("all"))
assertThat(CommentsRsListTab.UNREPLIED.queryStatus).isEqualTo(WpApiParamCommentsStatus.All)
}

@Test
Expand All @@ -33,8 +31,8 @@ class CommentsRsListTabTest {

@Test
fun `remaining tabs use the built-in statuses`() {
assertThat(CommentsRsListTab.PENDING.queryStatus).isEqualTo(RsCommentStatus.Hold)
assertThat(CommentsRsListTab.SPAM.queryStatus).isEqualTo(RsCommentStatus.Spam)
assertThat(CommentsRsListTab.TRASHED.queryStatus).isEqualTo(RsCommentStatus.Trash)
assertThat(CommentsRsListTab.PENDING.queryStatus).isEqualTo(WpApiParamCommentsStatus.Hold)
assertThat(CommentsRsListTab.SPAM.queryStatus).isEqualTo(WpApiParamCommentsStatus.Spam)
assertThat(CommentsRsListTab.TRASHED.queryStatus).isEqualTo(WpApiParamCommentsStatus.Trash)
}
}
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ wellsql = '2.0.0'
wordpress-aztec = 'v2.1.4'
wordpress-lint = '2.2.0'
wordpress-persistent-edittext = '1.0.2'
wordpress-rs = '0.6.0'
wordpress-rs = '0.7.0'
wordpress-utils = '3.14.0'
automattic-ucrop = '2.2.11'
zendesk = '5.5.3'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,15 @@ class MediaRSApiRestClient @Inject constructor(
}
}

// The file was readable when the multipart body was built, but could not be opened or
// read once the upload started — deleted mid-upload, or a storage read failure.
is WpRequestResult.MediaFileUnreadable<*> -> {
appLogWrapper.e(AppLog.T.MEDIA, "Media file unreadable: $mediaResponse")
MediaError(MediaErrorType.GENERIC_ERROR).apply {
message = "Media file could not be read"
}
}

is WpRequestResult.ResponseParsingError<*> -> {
appLogWrapper.e(AppLog.T.MEDIA, "Response parsing error: $mediaResponse")
MediaError(MediaErrorType.PARSE_ERROR).apply {
Expand Down Expand Up @@ -257,6 +266,7 @@ class MediaRSApiRestClient @Inject constructor(
when (reason) {
is RequestExecutionErrorReason.HttpTimeoutError -> MediaErrorType.TIMEOUT
is RequestExecutionErrorReason.DeviceIsOfflineError,
is RequestExecutionErrorReason.ConnectionError,
is RequestExecutionErrorReason.InvalidSslError -> MediaErrorType.CONNECTION_ERROR
is RequestExecutionErrorReason.NonExistentSiteError -> MediaErrorType.NOT_FOUND
// Keep this aligned with MediaErrorType.fromHttpStatusCode: a 403 (forbidden) maps to
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -392,7 +392,7 @@ class MediaRsApiRestClientTest {
}

@Test
fun `uploadMedia with unreadable file dispatches error action immediately`() = runTest {
fun `uploadMedia failing the pre-flight read check dispatches error action immediately`() = runTest {
val testSite = createTestSite()
val testMedia = createTestMedia().apply {
filePath = "" // Empty file path will fail MediaUtils.canReadFile
Expand Down
Loading