diff --git a/WordPress/src/main/java/org/wordpress/android/ui/comments/unified/CommentsRsDataSource.kt b/WordPress/src/main/java/org/wordpress/android/ui/comments/unified/CommentsRsDataSource.kt index 618db04b80a6..27d0d07ca9d4 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/comments/unified/CommentsRsDataSource.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/comments/unified/CommentsRsDataSource.kt @@ -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 @@ -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, diff --git a/WordPress/src/main/java/org/wordpress/android/ui/commentsrs/CommentsRsListTab.kt b/WordPress/src/main/java/org/wordpress/android/ui/commentsrs/CommentsRsListTab.kt index 69d4c0a5ef76..73097a870404 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/commentsrs/CommentsRsListTab.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/commentsrs/CommentsRsListTab.kt @@ -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 ) } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/domains/usecases/FetchAllDomainsUseCase.kt b/WordPress/src/main/java/org/wordpress/android/ui/domains/usecases/FetchAllDomainsUseCase.kt index c840fd8c0200..e3d5dcd2e176 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/domains/usecases/FetchAllDomainsUseCase.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/domains/usecases/FetchAllDomainsUseCase.kt @@ -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 { diff --git a/WordPress/src/test/java/org/wordpress/android/ui/comments/unified/CommentsRsListMappingTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/comments/unified/CommentsRsListMappingTest.kt index 361bd2823361..7189d85eb81a 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/comments/unified/CommentsRsListMappingTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/comments/unified/CommentsRsListMappingTest.kt @@ -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 @@ -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) diff --git a/WordPress/src/test/java/org/wordpress/android/ui/commentsrs/CommentsRsListTabTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/commentsrs/CommentsRsListTabTest.kt index b337e1999875..8c774f7fc325 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/commentsrs/CommentsRsListTabTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/commentsrs/CommentsRsListTabTest.kt @@ -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 @@ -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) } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 76c29d3c9552..f7cdca5b0cc8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -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' diff --git a/libs/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpapi/media/MediaRSApiRestClient.kt b/libs/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpapi/media/MediaRSApiRestClient.kt index 661f17dfe7e7..09c3b18f0356 100644 --- a/libs/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpapi/media/MediaRSApiRestClient.kt +++ b/libs/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpapi/media/MediaRSApiRestClient.kt @@ -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 { @@ -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 diff --git a/libs/fluxc/src/test/java/org/wordpress/android/fluxc/network/rest/wpapi/media/MediaRsApiRestClientTest.kt b/libs/fluxc/src/test/java/org/wordpress/android/fluxc/network/rest/wpapi/media/MediaRsApiRestClientTest.kt index 2b2709b03f4a..66b3823309c5 100644 --- a/libs/fluxc/src/test/java/org/wordpress/android/fluxc/network/rest/wpapi/media/MediaRsApiRestClientTest.kt +++ b/libs/fluxc/src/test/java/org/wordpress/android/fluxc/network/rest/wpapi/media/MediaRsApiRestClientTest.kt @@ -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