diff --git a/WordPress/src/main/java/org/wordpress/android/ui/jetpackrestconnection/JetpackConnectionHelper.kt b/WordPress/src/main/java/org/wordpress/android/ui/jetpackrestconnection/JetpackConnectionHelper.kt index dbca21b5af31..e512a5851c5b 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/jetpackrestconnection/JetpackConnectionHelper.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/jetpackrestconnection/JetpackConnectionHelper.kt @@ -58,7 +58,7 @@ class JetpackConnectionHelper @Inject constructor( site.wpApiRestUrl ?: "${site.url}/wp-json" private inner class InvalidAuthNotifier : WpAppNotifier { - override suspend fun requestedWithInvalidAuthentication() { + override suspend fun requestedWithInvalidAuthentication(requestUrl: String) { appLogWrapper.d(AppLog.T.API, "$TAG: requestedWithInvalidAuthentication") throw IllegalArgumentException("Invalid credentials") } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/posts/EditCategoryUseCase.kt b/WordPress/src/main/java/org/wordpress/android/ui/posts/EditCategoryUseCase.kt index b8349d2a3a6f..3f1957e8daf9 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/posts/EditCategoryUseCase.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/posts/EditCategoryUseCase.kt @@ -29,6 +29,7 @@ class EditCategoryUseCase @Inject constructor( existingCategory.slug, existingCategory.description, parentCategoryId, + existingCategory.isHierarchical, existingCategory.postCount ) val payload = RemoteTermPayload(editedCategory, siteModel) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/selfhostedusers/SampleUsers.kt b/WordPress/src/main/java/org/wordpress/android/ui/selfhostedusers/SampleUsers.kt index 7a61d84afaef..b823d4d9b930 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/selfhostedusers/SampleUsers.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/selfhostedusers/SampleUsers.kt @@ -1,5 +1,6 @@ package org.wordpress.android.ui.selfhostedusers +import uniffi.wp_api.UserRole import uniffi.wp_api.UserWithEditContext /** @@ -24,7 +25,7 @@ object SampleUsers { name = "Sample User", nickname = "User nickname", registeredDate = "2023-01-01", - roles = listOf("admin"), + roles = listOf(UserRole.Administrator), slug = "sample-user", url = "example.com", description = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam non quam viverra, viverra est vel, interdum felis. Pellentesque interdum libero quis metus pharetra ullamcorper. Morbi nec libero ligula. Quisque consectetur, purus sit amet lobortis porttitor, ligula ex imperdiet massa, in ullamcorper augue odio sit amet metus. In sollicitudin mauris et risus mollis commodo. Aliquam vel vehicula ante, nec blandit erat. Aenean non turpis porttitor orci fringilla fringilla nec ac nunc. Nulla ultrices urna ut ipsum posuere blandit. Phasellus mauris nulla, tincidunt at leo at, auctor interdum felis. Sed pharetra risus a ullamcorper dictum. Suspendisse pharetra justo molestie risus lobortis facilisis.", @@ -45,7 +46,7 @@ object SampleUsers { name = "Sample User", nickname = "User nickname", registeredDate = "2023-01-01", - roles = listOf("contributor"), + roles = listOf(UserRole.Contributor), slug = "sample-user", url = "example.com", ) @@ -65,7 +66,7 @@ object SampleUsers { name = "Sample User", nickname = "User nickname", registeredDate = "2023-01-01", - roles = listOf("contributor", "editor", "subscriber"), + roles = listOf(UserRole.Contributor, UserRole.Editor, UserRole.Subscriber), slug = "sample-user", url = "example.com", ) diff --git a/WordPress/src/test/java/org/wordpress/android/ui/posts/prepublishing/PrepublishingCategoriesViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/posts/prepublishing/PrepublishingCategoriesViewModelTest.kt index ceacd9a7e49f..7a2867585270 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/posts/prepublishing/PrepublishingCategoriesViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/posts/prepublishing/PrepublishingCategoriesViewModelTest.kt @@ -356,6 +356,7 @@ class PrepublishingCategoriesViewModelTest : BaseUnitTest() { "cars", null, 0, + true, 0 ) } diff --git a/WordPress/src/test/java/org/wordpress/android/ui/prefs/categories/detail/CategoryDetailViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/prefs/categories/detail/CategoryDetailViewModelTest.kt index 04f179b8e63b..18ac5979c76b 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/prefs/categories/detail/CategoryDetailViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/prefs/categories/detail/CategoryDetailViewModelTest.kt @@ -339,6 +339,7 @@ class CategoryDetailViewModelTest : BaseUnitTest() { "animals", null, 0, + true, 0 ) } @@ -353,6 +354,7 @@ class CategoryDetailViewModelTest : BaseUnitTest() { "dog", null, 1, + true, 0 ) } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4dae94486c6c..3140bada2895 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -102,7 +102,7 @@ wiremock = '2.26.3' wordpress-aztec = 'v2.1.4' wordpress-lint = '2.2.0' wordpress-persistent-edittext = '1.0.2' -wordpress-rs = 'trunk-f4e2450ca5545a4909cb08273f37a7f694244921' +wordpress-rs = 'trunk-d0c9eebab77e8701810077ac1fba7d39ef8d121f' wordpress-utils = '3.14.0' automattic-ucrop = '2.2.11' zendesk = '5.5.0' diff --git a/libs/fluxc/src/main/java/org/wordpress/android/fluxc/model/TermModel.java b/libs/fluxc/src/main/java/org/wordpress/android/fluxc/model/TermModel.java index a18283d533d5..f458f8d1c538 100644 --- a/libs/fluxc/src/main/java/org/wordpress/android/fluxc/model/TermModel.java +++ b/libs/fluxc/src/main/java/org/wordpress/android/fluxc/model/TermModel.java @@ -27,6 +27,7 @@ public class TermModel extends Payload implements Identifiable @Nullable @Column private String mSlug; @Nullable @Column private String mDescription; @Column private long mParentRemoteId; + @Column private boolean mIsHierarchical; @Column private int mPostCount; @Deprecated @@ -86,6 +87,7 @@ public TermModel( @Nullable String slug, @Nullable String description, long parentRemoteId, + boolean isHierarchical, int postCount) { this.mId = id; this.mLocalSiteId = localSiteId; @@ -95,6 +97,7 @@ public TermModel( this.mSlug = slug; this.mDescription = description; this.mParentRemoteId = parentRemoteId; + this.mIsHierarchical = isHierarchical; this.mPostCount = postCount; } @@ -168,6 +171,14 @@ public void setParentRemoteId(long parentRemoteId) { mParentRemoteId = parentRemoteId; } + public boolean isHierarchical() { + return mIsHierarchical; + } + + public void setIsHierarchical(boolean hierarchical) { + mIsHierarchical = hierarchical; + } + public int getPostCount() { return mPostCount; } diff --git a/libs/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpapi/rs/WpApiClientProvider.kt b/libs/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpapi/rs/WpApiClientProvider.kt index 4cd6033ec259..8fe5542ff4be 100644 --- a/libs/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpapi/rs/WpApiClientProvider.kt +++ b/libs/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpapi/rs/WpApiClientProvider.kt @@ -25,7 +25,7 @@ class WpApiClientProvider @Inject constructor( authProvider = authProvider, requestExecutor = WpRequestExecutor(uploadListener = uploadListener), appNotifier = object : WpAppNotifier { - override suspend fun requestedWithInvalidAuthentication() { + override suspend fun requestedWithInvalidAuthentication(requestUrl: String) { wpAppNotifierHandler.notifyRequestedWithInvalidAuthentication(site) } } diff --git a/libs/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpapi/taxonomy/TaxonomyRsApiRestClient.kt b/libs/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpapi/taxonomy/TaxonomyRsApiRestClient.kt index 5721a5420800..38332b44ccf9 100644 --- a/libs/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpapi/taxonomy/TaxonomyRsApiRestClient.kt +++ b/libs/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpapi/taxonomy/TaxonomyRsApiRestClient.kt @@ -17,18 +17,11 @@ import org.wordpress.android.fluxc.store.TaxonomyStore.TaxonomyError import org.wordpress.android.fluxc.store.TaxonomyStore.TaxonomyErrorType import org.wordpress.android.fluxc.utils.AppLogWrapper import org.wordpress.android.util.AppLog -import rs.wordpress.api.kotlin.WpApiClient import rs.wordpress.api.kotlin.WpRequestResult -import uniffi.wp_api.CategoryCreateParams -import uniffi.wp_api.CategoryDeleteResponse -import uniffi.wp_api.CategoryListParams -import uniffi.wp_api.CategoryUpdateParams -import uniffi.wp_api.CategoryWithEditContext -import uniffi.wp_api.TagCreateParams -import uniffi.wp_api.TagDeleteResponse -import uniffi.wp_api.TagListParams -import uniffi.wp_api.TagUpdateParams -import uniffi.wp_api.TagWithEditContext +import uniffi.wp_api.TermCreateParams +import uniffi.wp_api.TermEndpointType +import uniffi.wp_api.TermListParams +import uniffi.wp_api.TermUpdateParams import javax.inject.Inject import javax.inject.Named import javax.inject.Singleton @@ -42,206 +35,126 @@ class TaxonomyRsApiRestClient @Inject constructor( ) { fun deleteTerm(site: SiteModel, term: TermModel) { scope.launch { - val client = wpApiClientProvider.getWpApiClient(site) - when (term.taxonomy) { - DEFAULT_TAXONOMY_CATEGORY -> deleteCategory(client, term, site) - DEFAULT_TAXONOMY_TAG -> deleteTag(client, term, site) + DEFAULT_TAXONOMY_CATEGORY -> deleteTerm(TermEndpointType.Categories, term, site) + DEFAULT_TAXONOMY_TAG -> deleteTerm(TermEndpointType.Tags, term, site) else -> {} // TODO We are not supporting any other taxonomy yet } } } - private suspend fun deleteCategory( - client: WpApiClient, - term: TermModel, - site: SiteModel - ) { - val categoriesResponse = client.request { requestBuilder -> - requestBuilder.categories().delete(categoryId = term.id.toLong()) - } - handleDeleteResponse( - response = categoriesResponse, - termType = "category", - term = term, - site = site, - taxonomy = DEFAULT_TAXONOMY_CATEGORY, - extractData = { it.response.data }, - checkDeleted = { data -> (data as CategoryDeleteResponse).deleted } - ) - } - - private suspend fun deleteTag( - client: WpApiClient, + private suspend fun deleteTerm( + termEndpointType: TermEndpointType, term: TermModel, site: SiteModel ) { - val tagsResponse = client.request { requestBuilder -> - requestBuilder.tags().delete(tagId = term.id.toLong()) + val client = wpApiClientProvider.getWpApiClient(site) + val taxonomyName = termEndpointType.toTaxonomyName() + val termResponse = client.request { requestBuilder -> + requestBuilder.terms().delete( + termEndpointType = termEndpointType, + termId = term.id.toLong() + ) } - handleDeleteResponse( - response = tagsResponse, - termType = "tag", - term = term, - site = site, - taxonomy = DEFAULT_TAXONOMY_TAG, - extractData = { it.response.data }, - checkDeleted = { data -> (data as TagDeleteResponse).deleted } - ) - } - - @Suppress("LongParameterList") - private inline fun handleDeleteResponse( - response: WpRequestResult, - termType: String, - term: TermModel, - site: SiteModel, - taxonomy: String, - extractData: (WpRequestResult.Success) -> Any, - checkDeleted: (Any) -> Boolean - ) { - when (response) { + when (termResponse) { is WpRequestResult.Success -> { - val data = extractData(response) - appLogWrapper.d(AppLog.T.POSTS, "Deleted $termType: ${term.name} - ${checkDeleted(data)}") - if (checkDeleted(data)) { - val termModel = createTermModelForDelete(term, site, taxonomy) + appLogWrapper.d( + AppLog.T.POSTS, + "Deleting $taxonomyName: ${term.name} - ${termResponse.response.data.deleted}" + ) + if (termResponse.response.data.deleted) { + val termModel = TermModel( + term.id, + site.id, + term.id.toLong(), + taxonomyName, + term.name, + term.slug, + term.description, + term.parentRemoteId, + term.isHierarchical, + term.postCount + ) notifyTermDeleted(RemoteTermPayload(termModel, site)) } else { - notifyFailedDeleting(termType, site, term) + notifyFailedDeleting(taxonomyName, site, term) } } else -> { - notifyFailedDeleting(termType, site, term) + notifyFailedDeleting(taxonomyName, site, term) } } } - private fun notifyFailedDeleting(termType: String, site: SiteModel, term: TermModel) { - appLogWrapper.e(AppLog.T.POSTS, "Failed deleting $termType") + private fun notifyFailedDeleting(taxonomyName: String, site: SiteModel, term: TermModel) { + appLogWrapper.e(AppLog.T.POSTS, "Failed deleting $taxonomyName") val payload = RemoteTermPayload(term, site) payload.error = TaxonomyError(TaxonomyErrorType.GENERIC_ERROR, "") notifyTermDeleted(payload) } + private fun notifyTermDeleted( + payload: RemoteTermPayload, + ) { + dispatcher.dispatch(TaxonomyActionBuilder.newDeletedTermAction(payload)) + } + fun createTerm(site: SiteModel, term: TermModel) { scope.launch { - val client = wpApiClientProvider.getWpApiClient(site) - when (term.taxonomy) { - DEFAULT_TAXONOMY_CATEGORY -> createCategory(client, term, site) - DEFAULT_TAXONOMY_TAG -> createTag(client, term, site) + DEFAULT_TAXONOMY_CATEGORY -> createTerm(TermEndpointType.Categories, term, site) + DEFAULT_TAXONOMY_TAG -> createTerm(TermEndpointType.Tags, term, site) else -> {} // TODO We are not supporting any other taxonomy yet } } } - private suspend fun createCategory( - client: WpApiClient, + private suspend fun createTerm( + termEndpointType: TermEndpointType, term: TermModel, site: SiteModel ) { - val categoriesResponse = client.request { requestBuilder -> - requestBuilder.categories().create( - CategoryCreateParams( + val client = wpApiClientProvider.getWpApiClient(site) + val taxonomyName = termEndpointType.toTaxonomyName() + val termResponse = client.request { requestBuilder -> + requestBuilder.terms().create( + termEndpointType = termEndpointType, + TermCreateParams( name = term.name, description = term.description, slug = term.slug, - parent = term.parentRemoteId + // Right now, this is the only way we have to know if it's hierarchical + parent = if (termEndpointType == TermEndpointType.Categories) term.parentRemoteId else null ) ) } - handleCreateResponse( - response = categoriesResponse, - termType = "category", - term = term, - site = site, - extractData = { it.response.data }, - createTermModel = { data -> - val category = data as CategoryWithEditContext - TermModel( - category.id.toInt(), - site.id, - category.id, - DEFAULT_TAXONOMY_CATEGORY, - category.name, - category.slug, - category.description, - category.parent, - category.count.toInt() - ) - } - ) - } - - private suspend fun createTag( - client: WpApiClient, - term: TermModel, - site: SiteModel - ) { - val tagResponse = client.request { requestBuilder -> - requestBuilder.tags().create( - TagCreateParams( - name = term.name, - description = term.description, - slug = term.slug, - ) - ) - } - handleCreateResponse( - response = tagResponse, - termType = "tag", - term = term, - site = site, - extractData = { it.response.data }, - createTermModel = { data -> - val tag = data as TagWithEditContext - TermModel( - tag.id.toInt(), - site.id, - tag.id, - DEFAULT_TAXONOMY_TAG, - tag.name, - tag.slug, - tag.description, - 0, - tag.count.toInt() - ) - } - ) - } - - @Suppress("LongParameterList") - private inline fun handleCreateResponse( - response: WpRequestResult, - termType: String, - term: TermModel, - site: SiteModel, - extractData: (WpRequestResult.Success) -> Any, - createTermModel: (Any) -> TermModel - ) { - when (response) { + when (termResponse) { is WpRequestResult.Success -> { - val data = extractData(response) - val name = when (data) { - is CategoryWithEditContext -> data.name - is TagWithEditContext -> data.name - else -> "unknown" - } - appLogWrapper.d(AppLog.T.POSTS, "Created $termType: $name") - val payload = RemoteTermPayload(createTermModel(data), site) - notifyTermCreated(payload) + val term = termResponse.response.data + appLogWrapper.d(AppLog.T.POSTS, "Created $taxonomyName: ${term.name}") + val payload = RemoteTermPayload( + TermModel( + term.id.toInt(), + site.id, + term.id, + taxonomyName, + term.name, + term.slug, + term.description, + term.parent ?: 0, + term.parent != null, + term.count.toInt() + ), + site + ) + dispatcher.dispatch(TaxonomyActionBuilder.newPushedTermAction(payload)) } else -> { - notifyFailedOperation( - operation = "creating", - termType = termType, - term = term, - site = site, - errorDetails = response.toString(), - notifier = ::notifyTermCreated - ) + appLogWrapper.e(AppLog.T.POSTS, "Failed creating $taxonomyName: ${term.name} - $termResponse") + val payload = RemoteTermPayload(term, site) + payload.error = TaxonomyError(TaxonomyErrorType.GENERIC_ERROR, "") + dispatcher.dispatch(TaxonomyActionBuilder.newPushedTermAction(payload)) } } } @@ -252,300 +165,135 @@ class TaxonomyRsApiRestClient @Inject constructor( appLogWrapper.e(AppLog.T.POSTS, "Failed updating term: $term - id <= 0") val payload = RemoteTermPayload(term, site) payload.error = TaxonomyError(TaxonomyErrorType.GENERIC_ERROR, "") - notifyTermCreated(payload) // FluxC uses notifyTermCreated for updates + notifyTermUpdated(payload) return@launch } - val client = wpApiClientProvider.getWpApiClient(site) - when (term.taxonomy) { - DEFAULT_TAXONOMY_CATEGORY -> updateCategory(client, term, site) - DEFAULT_TAXONOMY_TAG -> updateTag(client, term, site) + DEFAULT_TAXONOMY_CATEGORY -> updateTerm(TermEndpointType.Categories, term, site) + DEFAULT_TAXONOMY_TAG -> updateTerm(TermEndpointType.Tags, term, site) else -> {} // TODO We are not supporting any other taxonomy yet } } } - private suspend fun updateCategory( - client: WpApiClient, + private suspend fun updateTerm( + termEndpointType: TermEndpointType, term: TermModel, site: SiteModel ) { - val categoriesResponse = client.request { requestBuilder -> - requestBuilder.categories().update( - categoryId = term.remoteTermId, - params = CategoryUpdateParams( + val client = wpApiClientProvider.getWpApiClient(site) + val taxonomyName = termEndpointType.toTaxonomyName() + val termResponse = client.request { requestBuilder -> + requestBuilder.terms().update( + termEndpointType = termEndpointType, + termId = term.remoteTermId, + params = TermUpdateParams( name = term.name, description = term.description, slug = term.slug, - parent = term.parentRemoteId + parent = if (term.isHierarchical) term.parentRemoteId else null ) ) } - handleUpdateResponse( - response = categoriesResponse, - termType = "category", - term = term, - site = site, - extractData = { it.response.data }, - createTermModel = { data -> - val category = data as CategoryWithEditContext - TermModel( - category.id.toInt(), - site.id, - category.id, - DEFAULT_TAXONOMY_CATEGORY, - category.name, - category.slug, - category.description, - category.parent, - category.count.toInt() + when (termResponse) { + is WpRequestResult.Success -> { + val term = termResponse.response.data + appLogWrapper.d(AppLog.T.POSTS, "Updated $taxonomyName: ${term.name}") + val payload = RemoteTermPayload( + TermModel( + term.id.toInt(), + site.id, + term.id, + taxonomyName, + term.name, + term.slug, + term.description, + term.parent ?: 0, + term.parent != null, + term.count.toInt() + ), + site ) + notifyTermUpdated(payload) } - ) - } - - private suspend fun updateTag( - client: WpApiClient, - term: TermModel, - site: SiteModel - ) { - val tagResponse = client.request { requestBuilder -> - requestBuilder.tags().update( - tagId = term.remoteTermId, - params = TagUpdateParams( - name = term.name, - description = term.description, - slug = term.slug, - ) - ) - } - handleUpdateResponse( - response = tagResponse, - termType = "tag", - term = term, - site = site, - extractData = { it.response.data }, - createTermModel = { data -> - val tag = data as TagWithEditContext - TermModel( - tag.id.toInt(), - site.id, - tag.id, - DEFAULT_TAXONOMY_TAG, - tag.name, - tag.slug, - tag.description, - 0, - tag.count.toInt() - ) + else -> { + appLogWrapper.e(AppLog.T.POSTS, "Failed updating ${term.name}: $termResponse") + val payload = RemoteTermPayload(term, site) + payload.error = TaxonomyError(TaxonomyErrorType.GENERIC_ERROR, "") + notifyTermUpdated(payload) } - ) + } } - @Suppress("LongParameterList") - private inline fun handleUpdateResponse( - response: WpRequestResult, - termType: String, - term: TermModel, - site: SiteModel, - extractData: (WpRequestResult.Success) -> Any, - createTermModel: (Any) -> TermModel + private fun notifyTermUpdated( + payload: RemoteTermPayload, ) { - when (response) { - is WpRequestResult.Success -> { - val data = extractData(response) - val name = when (data) { - is CategoryWithEditContext -> data.name - is TagWithEditContext -> data.name - else -> "unknown" - } - appLogWrapper.d(AppLog.T.POSTS, "${termType.replaceFirstChar { it.uppercase() }} updated: $name") - val payload = RemoteTermPayload(createTermModel(data), site) - notifyTermCreated(payload) // FluxC uses notifyTermCreated for updates - } - else -> { - notifyFailedOperation( - operation = "updating", - termType = termType, - term = term, - site = site, - errorDetails = response.toString(), - notifier = ::notifyTermCreated - ) - } - } + // FluxC uses notifyTermCreated for updates + dispatcher.dispatch(TaxonomyActionBuilder.newPushedTermAction(payload)) } fun fetchTerms(site: SiteModel, taxonomyName: String) { scope.launch { - val client = wpApiClientProvider.getWpApiClient(site) - when (taxonomyName) { - DEFAULT_TAXONOMY_CATEGORY -> fetchCategories(client, site) - DEFAULT_TAXONOMY_TAG -> fetchTags(client, site) + DEFAULT_TAXONOMY_CATEGORY -> fetchTerms(TermEndpointType.Categories, site) + DEFAULT_TAXONOMY_TAG -> fetchTerms(TermEndpointType.Tags, site) else -> {} // TODO We are not supporting any other taxonomy yet } } } - private suspend fun fetchCategories( - client: WpApiClient, + private suspend fun fetchTerms( + termEndpointType: TermEndpointType, site: SiteModel ) { - val categoriesResponse = client.request { requestBuilder -> - requestBuilder.categories().listWithEditContext( - CategoryListParams() + val client = wpApiClientProvider.getWpApiClient(site) + val taxonomyName = termEndpointType.toTaxonomyName() + val termsResponse = client.request { requestBuilder -> + requestBuilder.terms().listWithEditContext( + termEndpointType = termEndpointType, + params = TermListParams() ) } - handleFetchResponse( - response = categoriesResponse, - termType = "categories", - taxonomy = DEFAULT_TAXONOMY_CATEGORY, - site = site, - extractData = { it.response.data }, - createTermModels = { data -> - (data as List<*>).map { category -> - val cat = category as CategoryWithEditContext - TermModel( - cat.id.toInt(), - site.id, - cat.id, - DEFAULT_TAXONOMY_CATEGORY, - cat.name, - cat.slug, - cat.description, - cat.parent, - cat.count.toInt() - ) - } - } - ) - } - - private suspend fun fetchTags( - client: WpApiClient, - site: SiteModel - ) { - val tagsResponse = client.request { requestBuilder -> - requestBuilder.tags().listWithEditContext( - TagListParams() - ) - } - handleFetchResponse( - response = tagsResponse, - termType = "tags", - taxonomy = DEFAULT_TAXONOMY_TAG, - site = site, - extractData = { it.response.data }, - createTermModels = { data -> - (data as List<*>).map { tag -> - val t = tag as TagWithEditContext - TermModel( - t.id.toInt(), - site.id, - t.id, - DEFAULT_TAXONOMY_TAG, - t.name, - t.slug, - t.description, - 0, - t.count.toInt() - ) - } - } - ) - } - - @Suppress("LongParameterList") - private inline fun handleFetchResponse( - response: WpRequestResult, - termType: String, - taxonomy: String, - site: SiteModel, - extractData: (WpRequestResult.Success) -> Any, - createTermModels: (Any) -> List - ) { - val termsResponsePayload = when (response) { + val termsResponsePayload = when (termsResponse) { is WpRequestResult.Success -> { - val data = extractData(response) - val dataList = data as List<*> - appLogWrapper.d(AppLog.T.POSTS, "Fetched $termType list: ${dataList.size}") - createTermsResponsePayload( - createTermModels(data), + appLogWrapper.d(AppLog.T.POSTS, "Fetched $taxonomyName list: ${termsResponse.response.data.size}") + FetchTermsResponsePayload( + TermsModel( + termsResponse.response.data.map { term -> + TermModel( + term.id.toInt(), + site.id, + term.id, + taxonomyName, + term.name, + term.slug, + term.description, + term.parent ?: 0, + term.parent != null, + term.count.toInt() + ) + }, + ), site, - taxonomy + taxonomyName ) } else -> { - appLogWrapper.e(AppLog.T.POSTS, "Fetch $termType list failed: $response") - createErrorResponsePayload(taxonomy) + appLogWrapper.e(AppLog.T.POSTS, "Fetch $termEndpointType list failed: $termsResponse") + FetchTermsResponsePayload( + TaxonomyError(TaxonomyErrorType.GENERIC_ERROR, ""), + taxonomyName + ) } } - notifyTermsFetched(termsResponsePayload) - } - - private fun notifyTermsFetched( - payload: FetchTermsResponsePayload, - ) { - dispatcher.dispatch(TaxonomyActionBuilder.newFetchedTermsAction(payload)) - } - - private fun notifyTermCreated( - payload: RemoteTermPayload, - ) { - dispatcher.dispatch(TaxonomyActionBuilder.newPushedTermAction(payload)) + dispatcher.dispatch(TaxonomyActionBuilder.newFetchedTermsAction(termsResponsePayload)) } - private fun notifyTermDeleted( - payload: RemoteTermPayload, - ) { - dispatcher.dispatch(TaxonomyActionBuilder.newDeletedTermAction(payload)) - } - @Suppress("LongParameterList") - private fun notifyFailedOperation( - operation: String, - termType: String, - term: TermModel, - site: SiteModel, - errorDetails: String, - notifier: (RemoteTermPayload) -> Unit - ) { - appLogWrapper.e(AppLog.T.POSTS, "Failed $operation $termType: $errorDetails") - val payload = RemoteTermPayload(term, site) - payload.error = TaxonomyError(TaxonomyErrorType.GENERIC_ERROR, "") - notifier(payload) + private fun TermEndpointType.toTaxonomyName(): String = when (this) { + TermEndpointType.Categories -> DEFAULT_TAXONOMY_CATEGORY + TermEndpointType.Tags -> DEFAULT_TAXONOMY_TAG + is TermEndpointType.Custom -> this.v1 } - - private fun createErrorResponsePayload(taxonomyName: String): FetchTermsResponsePayload = - FetchTermsResponsePayload( - TaxonomyError(TaxonomyErrorType.GENERIC_ERROR, ""), - taxonomyName - ) - - - private fun createTermModelForDelete(term: TermModel, site: SiteModel, taxonomy: String): TermModel { - return TermModel( - term.id, - site.id, - term.id.toLong(), - taxonomy, - term.name, - term.slug, - term.description, - term.parentRemoteId, - term.postCount - ) - } - - private fun createTermsResponsePayload( - terms: List, - site: SiteModel, - taxonomyName: String - ): FetchTermsResponsePayload = FetchTermsResponsePayload( - TermsModel(terms), - site, - taxonomyName - ) } diff --git a/libs/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/taxonomy/TaxonomyRestClient.java b/libs/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/taxonomy/TaxonomyRestClient.java index 3e4f79b0e524..8e8945e38c09 100644 --- a/libs/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/taxonomy/TaxonomyRestClient.java +++ b/libs/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/taxonomy/TaxonomyRestClient.java @@ -174,6 +174,7 @@ private TermModel termResponseToTermModel( from.slug, StringEscapeUtils.unescapeHtml4(from.description), from.parent, + true, // this is only applicable for the new Rest API from.post_count ); } diff --git a/libs/fluxc/src/main/java/org/wordpress/android/fluxc/network/xmlrpc/taxonomy/TaxonomyXMLRPCClient.java b/libs/fluxc/src/main/java/org/wordpress/android/fluxc/network/xmlrpc/taxonomy/TaxonomyXMLRPCClient.java index 67bf4d2a69d5..f282b98a0ffe 100644 --- a/libs/fluxc/src/main/java/org/wordpress/android/fluxc/network/xmlrpc/taxonomy/TaxonomyXMLRPCClient.java +++ b/libs/fluxc/src/main/java/org/wordpress/android/fluxc/network/xmlrpc/taxonomy/TaxonomyXMLRPCClient.java @@ -239,6 +239,7 @@ private TermModel termResponseObjectToTermModel(@NonNull Object termObject, @Non MapUtils.getMapStr(termMap, "slug"), StringEscapeUtils.unescapeHtml4(MapUtils.getMapStr(termMap, "description")), MapUtils.getMapLong(termMap, "parent"), + true, // this is only applicable for the new Rest API MapUtils.getMapInt(termMap, "count", 0) ); } diff --git a/libs/fluxc/src/main/java/org/wordpress/android/fluxc/persistence/WellSqlConfig.kt b/libs/fluxc/src/main/java/org/wordpress/android/fluxc/persistence/WellSqlConfig.kt index 380f9a7e4bba..a8f18b82a34f 100644 --- a/libs/fluxc/src/main/java/org/wordpress/android/fluxc/persistence/WellSqlConfig.kt +++ b/libs/fluxc/src/main/java/org/wordpress/android/fluxc/persistence/WellSqlConfig.kt @@ -41,7 +41,7 @@ open class WellSqlConfig : DefaultWellConfig { annotation class AddOn override fun getDbVersion(): Int { - return 210 + return 211 } override fun getDbName(): String { @@ -2085,6 +2085,10 @@ open class WellSqlConfig : DefaultWellConfig { db.execSQL("ALTER TABLE MediaModel ADD FILE_SIZE INTEGER") db.execSQL("ALTER TABLE MediaModel ADD FILE_SIZE_FORMATTED TEXT") } + + 210 -> { + db.execSQL("ALTER TABLE TermModel ADD IS_HIERARCHICAL BOOLEAN") + } } } db.setTransactionSuccessful() diff --git a/libs/fluxc/src/main/java/org/wordpress/android/fluxc/store/TaxonomyStore.java b/libs/fluxc/src/main/java/org/wordpress/android/fluxc/store/TaxonomyStore.java index 83980582afd0..13ca0bde49ae 100644 --- a/libs/fluxc/src/main/java/org/wordpress/android/fluxc/store/TaxonomyStore.java +++ b/libs/fluxc/src/main/java/org/wordpress/android/fluxc/store/TaxonomyStore.java @@ -408,8 +408,8 @@ private void handlePushTermCompleted(@NonNull RemoteTermPayload payload) { onTermUploaded.error = payload.error; emitChange(onTermUploaded); } else { - if (payload.site.isUsingWpComRestApi()) { - // The WP.COM REST API response contains the modified term, so we're already in sync with the server + if (payload.site.isUsingWpComRestApi() || payload.site.isUsingSelfHostedRestApi()) { + // The WP.COM and REST API response contains the modified term, so we're already in sync with the server // All we need to do is store it and emit OnTaxonomyChanged updateTerm(payload.term); emitChange(new OnTermUploaded(payload.term)); diff --git a/libs/fluxc/src/test/java/org/wordpress/android/fluxc/network/rest/wpapi/taxonomy/TaxonomyRsApiRestClientTest.kt b/libs/fluxc/src/test/java/org/wordpress/android/fluxc/network/rest/wpapi/taxonomy/TaxonomyRsApiRestClientTest.kt index 54d3c7fc8b70..45fdcc29efaa 100644 --- a/libs/fluxc/src/test/java/org/wordpress/android/fluxc/network/rest/wpapi/taxonomy/TaxonomyRsApiRestClientTest.kt +++ b/libs/fluxc/src/test/java/org/wordpress/android/fluxc/network/rest/wpapi/taxonomy/TaxonomyRsApiRestClientTest.kt @@ -31,18 +31,12 @@ import org.wordpress.android.fluxc.store.TaxonomyStore.TaxonomyErrorType import org.wordpress.android.fluxc.utils.AppLogWrapper import rs.wordpress.api.kotlin.WpApiClient import rs.wordpress.api.kotlin.WpRequestResult -import uniffi.wp_api.CategoryDeleteResponse -import uniffi.wp_api.CategoryWithEditContext -import uniffi.wp_api.CategoriesRequestCreateResponse -import uniffi.wp_api.CategoriesRequestDeleteResponse -import uniffi.wp_api.CategoriesRequestListWithEditContextResponse -import uniffi.wp_api.CategoriesRequestUpdateResponse -import uniffi.wp_api.TagDeleteResponse -import uniffi.wp_api.TagWithEditContext -import uniffi.wp_api.TagsRequestCreateResponse -import uniffi.wp_api.TagsRequestDeleteResponse -import uniffi.wp_api.TagsRequestListWithEditContextResponse -import uniffi.wp_api.TagsRequestUpdateResponse +import uniffi.wp_api.AnyTermWithEditContext +import uniffi.wp_api.TermDeleteResponse +import uniffi.wp_api.TermsRequestCreateResponse +import uniffi.wp_api.TermsRequestDeleteResponse +import uniffi.wp_api.TermsRequestListWithEditContextResponse +import uniffi.wp_api.TermsRequestUpdateResponse import uniffi.wp_api.TaxonomyType import uniffi.wp_api.WpNetworkHeaderMap @@ -66,7 +60,7 @@ class TaxonomyRsApiRestClientTest { url = "https://test.wordpress.com" } - private val testTermModel = TermModel( + private val testCategoryTermModel = TermModel( 1, // id 123, // localSiteId 2L, // remoteTermId @@ -75,6 +69,7 @@ class TaxonomyRsApiRestClientTest { "test-category", // slug "Test category description", // description 0L, // parentRemoteId + true, // isHierarchical 0 // postCount ) @@ -87,6 +82,7 @@ class TaxonomyRsApiRestClientTest { "test-tag", // slug "Test tag description", // description 0L, // parentRemoteId + false, // isHierarchical 0 // postCount ) @@ -137,24 +133,24 @@ class TaxonomyRsApiRestClientTest { @Test fun `fetchTerms tags with success response dispatches success action`() = runTest { - val tagWithEditContext = listOf( - createTestTagWithEditContext(), - createTestTagWithEditContext() + val anyTermWithEditContext = listOf( + createTestAnyTermWithEditContext(), + createTestAnyTermWithEditContext() ) // Create the correct response structure following the MediaRSApiRestClientTest pattern - val tagResponse = TagsRequestListWithEditContextResponse( - tagWithEditContext, + val tagResponse = TermsRequestListWithEditContextResponse( + anyTermWithEditContext, mock(), null, null ) - val successResponse: WpRequestResult = WpRequestResult.Success( + val successResponse: WpRequestResult = WpRequestResult.Success( response = tagResponse ) - whenever(wpApiClient.request(any())).thenReturn(successResponse) + whenever(wpApiClient.request(any())).thenReturn(successResponse) taxonomyClient.fetchTerms(testSite, testTagTaxonomyName) @@ -198,24 +194,24 @@ class TaxonomyRsApiRestClientTest { @Test fun `fetchTerms categories with success response dispatches success action`() = runTest { - val categoryWithEditContext = listOf( - createTestCategoryWithEditContext(), - createTestCategoryWithEditContext() + val anyTermWithEditContext = listOf( + createTestAnyTermWithEditContext(), + createTestAnyTermWithEditContext() ) // Create the correct response structure following the MediaRSApiRestClientTest pattern - val categoryResponse = CategoriesRequestListWithEditContextResponse( - categoryWithEditContext, + val categoryResponse = TermsRequestListWithEditContextResponse( + anyTermWithEditContext, mock(), null, null ) - val successResponse: WpRequestResult = WpRequestResult.Success( + val successResponse: WpRequestResult = WpRequestResult.Success( response = categoryResponse ) - whenever(wpApiClient.request(any())).thenReturn(successResponse) + whenever(wpApiClient.request(any())).thenReturn(successResponse) taxonomyClient.fetchTerms(testSite, testCategoryTaxonomyName) @@ -243,7 +239,7 @@ class TaxonomyRsApiRestClientTest { whenever(wpApiClient.request(any())).thenReturn(errorResponse) - taxonomyClient.createTerm(testSite, testTermModel) + taxonomyClient.createTerm(testSite, testCategoryTermModel) // Verify dispatcher was called with error action val actionCaptor = ArgumentCaptor.forClass(Action::class.java) @@ -253,28 +249,28 @@ class TaxonomyRsApiRestClientTest { val payload = capturedAction.payload as RemoteTermPayload assertEquals(capturedAction.type, TaxonomyAction.PUSHED_TERM) assertEquals(testSite, payload.site) - assertEquals(testTermModel, payload.term) + assertEquals(testCategoryTermModel, payload.term) assertNotNull(payload.error) assertEquals(TaxonomyErrorType.GENERIC_ERROR, payload.error?.type) } @Test fun `createTerm category with success response dispatches success action`() = runTest { - val categoryWithEditContext = createTestCategoryWithEditContext() + val anyTermWithEditContext = createTestAnyTermWithEditContext() // Create the correct response structure following the MediaRSApiRestClientTest pattern - val categoryResponse = CategoriesRequestCreateResponse( - categoryWithEditContext, + val categoryResponse = TermsRequestCreateResponse( + anyTermWithEditContext, mock() ) - val successResponse: WpRequestResult = WpRequestResult.Success( + val successResponse: WpRequestResult = WpRequestResult.Success( response = categoryResponse ) - whenever(wpApiClient.request(any())).thenReturn(successResponse) + whenever(wpApiClient.request(any())).thenReturn(successResponse) - taxonomyClient.createTerm(testSite, testTermModel) + taxonomyClient.createTerm(testSite, testCategoryTermModel) // Verify dispatcher was called with success action val actionCaptor = ArgumentCaptor.forClass(Action::class.java) @@ -286,14 +282,14 @@ class TaxonomyRsApiRestClientTest { assertEquals(testSite, payload.site) assertNotNull(payload.term) // Verify the created term has the correct properties - assertEquals(categoryWithEditContext.id.toInt(), payload.term.id) + assertEquals(anyTermWithEditContext.id.toInt(), payload.term.id) assertEquals(testSite.id, payload.term.localSiteId) - assertEquals(categoryWithEditContext.id, payload.term.remoteTermId) + assertEquals(anyTermWithEditContext.id, payload.term.remoteTermId) assertEquals(testCategoryTaxonomyName, payload.term.taxonomy) - assertEquals(categoryWithEditContext.name, payload.term.name) - assertEquals(categoryWithEditContext.slug, payload.term.slug) - assertEquals(categoryWithEditContext.description, payload.term.description) - assertEquals(categoryWithEditContext.count.toInt(), payload.term.postCount) + assertEquals(anyTermWithEditContext.name, payload.term.name) + assertEquals(anyTermWithEditContext.slug, payload.term.slug) + assertEquals(anyTermWithEditContext.description, payload.term.description) + assertEquals(anyTermWithEditContext.count.toInt(), payload.term.postCount) assertNull(payload.error) } @@ -324,19 +320,19 @@ class TaxonomyRsApiRestClientTest { @Test fun `createTerm tag with success response dispatches success action`() = runTest { - val tagWithEditContext = createTestTagWithEditContext() + val anyTermWithEditContext = createTestAnyTermWithEditContext() // Create the correct response structure following the MediaRSApiRestClientTest pattern - val tagResponse = TagsRequestCreateResponse( - tagWithEditContext, + val tagResponse = TermsRequestCreateResponse( + anyTermWithEditContext, mock() ) - val successResponse: WpRequestResult = WpRequestResult.Success( + val successResponse: WpRequestResult = WpRequestResult.Success( response = tagResponse ) - whenever(wpApiClient.request(any())).thenReturn(successResponse) + whenever(wpApiClient.request(any())).thenReturn(successResponse) taxonomyClient.createTerm(testSite, testTagTermModel) @@ -350,14 +346,14 @@ class TaxonomyRsApiRestClientTest { assertEquals(testSite, payload.site) assertNotNull(payload.term) // Verify the created term has the correct properties - assertEquals(tagWithEditContext.id.toInt(), payload.term.id) + assertEquals(anyTermWithEditContext.id.toInt(), payload.term.id) assertEquals(testSite.id, payload.term.localSiteId) - assertEquals(tagWithEditContext.id, payload.term.remoteTermId) + assertEquals(anyTermWithEditContext.id, payload.term.remoteTermId) assertEquals(testTagTaxonomyName, payload.term.taxonomy) - assertEquals(tagWithEditContext.name, payload.term.name) - assertEquals(tagWithEditContext.slug, payload.term.slug) - assertEquals(tagWithEditContext.description, payload.term.description) - assertEquals(tagWithEditContext.count.toInt(), payload.term.postCount) + assertEquals(anyTermWithEditContext.name, payload.term.name) + assertEquals(anyTermWithEditContext.slug, payload.term.slug) + assertEquals(anyTermWithEditContext.description, payload.term.description) + assertEquals(anyTermWithEditContext.count.toInt(), payload.term.postCount) assertNull(payload.error) } @@ -371,7 +367,7 @@ class TaxonomyRsApiRestClientTest { whenever(wpApiClient.request(any())).thenReturn(errorResponse) - taxonomyClient.deleteTerm(testSite, testTermModel) + taxonomyClient.deleteTerm(testSite, testCategoryTermModel) // Verify dispatcher was called with error action val actionCaptor = ArgumentCaptor.forClass(Action::class.java) @@ -381,7 +377,7 @@ class TaxonomyRsApiRestClientTest { val payload = capturedAction.payload as RemoteTermPayload assertEquals(capturedAction.type, TaxonomyAction.DELETED_TERM) assertEquals(testSite, payload.site) - assertEquals(testTermModel, payload.term) + assertEquals(testCategoryTermModel, payload.term) assertNotNull(payload.error) assertEquals(TaxonomyErrorType.GENERIC_ERROR, payload.error?.type) } @@ -391,18 +387,18 @@ class TaxonomyRsApiRestClientTest { val categoryDeleteData = createTestCategoryDeleteData(deleted = true) // Create the correct response structure following the MediaRsApiRestClientTest pattern - val categoryResponse = CategoriesRequestDeleteResponse( + val categoryResponse = TermsRequestDeleteResponse( categoryDeleteData, mock() ) - val successResponse: WpRequestResult = WpRequestResult.Success( + val successResponse: WpRequestResult = WpRequestResult.Success( response = categoryResponse ) - whenever(wpApiClient.request(any())).thenReturn(successResponse) + whenever(wpApiClient.request(any())).thenReturn(successResponse) - taxonomyClient.deleteTerm(testSite, testTermModel) + taxonomyClient.deleteTerm(testSite, testCategoryTermModel) // Verify dispatcher was called with success action val actionCaptor = ArgumentCaptor.forClass(Action::class.java) @@ -414,14 +410,14 @@ class TaxonomyRsApiRestClientTest { assertEquals(testSite, payload.site) assertNotNull(payload.term) // Verify the deleted term has the correct properties - assertEquals(testTermModel.id, payload.term.id) + assertEquals(testCategoryTermModel.id, payload.term.id) assertEquals(testSite.id, payload.term.localSiteId) - assertEquals(testTermModel.id.toLong(), payload.term.remoteTermId) + assertEquals(testCategoryTermModel.id.toLong(), payload.term.remoteTermId) assertEquals(testCategoryTaxonomyName, payload.term.taxonomy) - assertEquals(testTermModel.name, payload.term.name) - assertEquals(testTermModel.slug, payload.term.slug) - assertEquals(testTermModel.description, payload.term.description) - assertEquals(testTermModel.postCount, payload.term.postCount) + assertEquals(testCategoryTermModel.name, payload.term.name) + assertEquals(testCategoryTermModel.slug, payload.term.slug) + assertEquals(testCategoryTermModel.description, payload.term.description) + assertEquals(testCategoryTermModel.postCount, payload.term.postCount) assertNull(payload.error) } @@ -430,18 +426,18 @@ class TaxonomyRsApiRestClientTest { val categoryDeleteData = createTestCategoryDeleteData(deleted = false) // Create the correct response structure with deleted = false - val categoryResponse = CategoriesRequestDeleteResponse( + val categoryResponse = TermsRequestDeleteResponse( categoryDeleteData, mock() ) - val successResponse: WpRequestResult = WpRequestResult.Success( + val successResponse: WpRequestResult = WpRequestResult.Success( response = categoryResponse ) - whenever(wpApiClient.request(any())).thenReturn(successResponse) + whenever(wpApiClient.request(any())).thenReturn(successResponse) - taxonomyClient.deleteTerm(testSite, testTermModel) + taxonomyClient.deleteTerm(testSite, testCategoryTermModel) // Verify dispatcher was called with error action val actionCaptor = ArgumentCaptor.forClass(Action::class.java) @@ -451,7 +447,7 @@ class TaxonomyRsApiRestClientTest { val payload = capturedAction.payload as RemoteTermPayload assertEquals(capturedAction.type, TaxonomyAction.DELETED_TERM) assertEquals(testSite, payload.site) - assertEquals(testTermModel, payload.term) + assertEquals(testCategoryTermModel, payload.term) assertNotNull(payload.error) assertEquals(TaxonomyErrorType.GENERIC_ERROR, payload.error?.type) } @@ -486,16 +482,16 @@ class TaxonomyRsApiRestClientTest { val tagDeleteData = createTestTagDeleteData(deleted = true) // Create the correct response structure following the MediaRsApiRestClientTest pattern - val tagResponse = TagsRequestDeleteResponse( + val tagResponse = TermsRequestDeleteResponse( tagDeleteData, mock() ) - val successResponse: WpRequestResult = WpRequestResult.Success( + val successResponse: WpRequestResult = WpRequestResult.Success( response = tagResponse ) - whenever(wpApiClient.request(any())).thenReturn(successResponse) + whenever(wpApiClient.request(any())).thenReturn(successResponse) taxonomyClient.deleteTerm(testSite, testTagTermModel) @@ -525,16 +521,16 @@ class TaxonomyRsApiRestClientTest { val tagDeleteData = createTestTagDeleteData(deleted = false) // Create the correct response structure with deleted = false - val tagResponse = TagsRequestDeleteResponse( + val tagResponse = TermsRequestDeleteResponse( tagDeleteData, mock() ) - val successResponse: WpRequestResult = WpRequestResult.Success( + val successResponse: WpRequestResult = WpRequestResult.Success( response = tagResponse ) - whenever(wpApiClient.request(any())).thenReturn(successResponse) + whenever(wpApiClient.request(any())).thenReturn(successResponse) taxonomyClient.deleteTerm(testSite, testTagTermModel) @@ -560,7 +556,7 @@ class TaxonomyRsApiRestClientTest { whenever(wpApiClient.request(any())).thenReturn(errorResponse) - taxonomyClient.updateTerm(testSite, testTermModel) + taxonomyClient.updateTerm(testSite, testCategoryTermModel) val actionCaptor = ArgumentCaptor.forClass(Action::class.java) verify(dispatcher).dispatch(actionCaptor.capture()) @@ -569,27 +565,27 @@ class TaxonomyRsApiRestClientTest { val payload = capturedAction.payload as RemoteTermPayload assertEquals(capturedAction.type, TaxonomyAction.PUSHED_TERM) assertEquals(testSite, payload.site) - assertEquals(testTermModel, payload.term) + assertEquals(testCategoryTermModel, payload.term) assertNotNull(payload.error) assertEquals(TaxonomyErrorType.GENERIC_ERROR, payload.error?.type) } @Test fun `updateTerm category with success response dispatches success action`() = runTest { - val categoryWithEditContext = createTestCategoryWithEditContext() + val anyTermWithEditContext = createTestAnyTermWithEditContext() - val categoryResponse = CategoriesRequestUpdateResponse( - categoryWithEditContext, + val categoryResponse = TermsRequestUpdateResponse( + anyTermWithEditContext, mock() ) - val successResponse: WpRequestResult = WpRequestResult.Success( + val successResponse: WpRequestResult = WpRequestResult.Success( response = categoryResponse ) - whenever(wpApiClient.request(any())).thenReturn(successResponse) + whenever(wpApiClient.request(any())).thenReturn(successResponse) - taxonomyClient.updateTerm(testSite, testTermModel) + taxonomyClient.updateTerm(testSite, testCategoryTermModel) val actionCaptor = ArgumentCaptor.forClass(Action::class.java) verify(dispatcher).dispatch(actionCaptor.capture()) @@ -599,29 +595,30 @@ class TaxonomyRsApiRestClientTest { assertEquals(capturedAction.type, TaxonomyAction.PUSHED_TERM) assertEquals(testSite, payload.site) assertNotNull(payload.term) - assertEquals(categoryWithEditContext.id.toInt(), payload.term.id) + assertEquals(anyTermWithEditContext.id.toInt(), payload.term.id) assertEquals(testSite.id, payload.term.localSiteId) - assertEquals(categoryWithEditContext.id, payload.term.remoteTermId) + assertEquals(anyTermWithEditContext.id, payload.term.remoteTermId) assertEquals(testCategoryTaxonomyName, payload.term.taxonomy) - assertEquals(categoryWithEditContext.name, payload.term.name) - assertEquals(categoryWithEditContext.slug, payload.term.slug) - assertEquals(categoryWithEditContext.description, payload.term.description) - assertEquals(categoryWithEditContext.count.toInt(), payload.term.postCount) + assertEquals(anyTermWithEditContext.name, payload.term.name) + assertEquals(anyTermWithEditContext.slug, payload.term.slug) + assertEquals(anyTermWithEditContext.description, payload.term.description) + assertEquals(anyTermWithEditContext.count.toInt(), payload.term.postCount) assertNull(payload.error) } @Test fun `updateTerm category with invalid id dispatches error action`() = runTest { val invalidTermModel = TermModel( - testTermModel.id, - testTermModel.localSiteId, + testCategoryTermModel.id, + testCategoryTermModel.localSiteId, -1L, // invalid remoteTermId - testTermModel.taxonomy, - testTermModel.name, - testTermModel.slug, - testTermModel.description, - testTermModel.parentRemoteId, - testTermModel.postCount + testCategoryTermModel.taxonomy, + testCategoryTermModel.name, + testCategoryTermModel.slug, + testCategoryTermModel.description, + testCategoryTermModel.parentRemoteId, + testCategoryTermModel.isHierarchical, + testCategoryTermModel.postCount ) taxonomyClient.updateTerm(testSite, invalidTermModel) @@ -663,18 +660,18 @@ class TaxonomyRsApiRestClientTest { @Test fun `updateTerm tag with success response dispatches success action`() = runTest { - val tagWithEditContext = createTestTagWithEditContext() + val anyTermWithEditContext = createTestAnyTermWithEditContext() - val tagResponse = TagsRequestUpdateResponse( - tagWithEditContext, + val tagResponse = TermsRequestUpdateResponse( + anyTermWithEditContext, mock() ) - val successResponse: WpRequestResult = WpRequestResult.Success( + val successResponse: WpRequestResult = WpRequestResult.Success( response = tagResponse ) - whenever(wpApiClient.request(any())).thenReturn(successResponse) + whenever(wpApiClient.request(any())).thenReturn(successResponse) taxonomyClient.updateTerm(testSite, testTagTermModel) @@ -686,14 +683,14 @@ class TaxonomyRsApiRestClientTest { assertEquals(capturedAction.type, TaxonomyAction.PUSHED_TERM) assertEquals(testSite, payload.site) assertNotNull(payload.term) - assertEquals(tagWithEditContext.id.toInt(), payload.term.id) + assertEquals(anyTermWithEditContext.id.toInt(), payload.term.id) assertEquals(testSite.id, payload.term.localSiteId) - assertEquals(tagWithEditContext.id, payload.term.remoteTermId) + assertEquals(anyTermWithEditContext.id, payload.term.remoteTermId) assertEquals(testTagTaxonomyName, payload.term.taxonomy) - assertEquals(tagWithEditContext.name, payload.term.name) - assertEquals(tagWithEditContext.slug, payload.term.slug) - assertEquals(tagWithEditContext.description, payload.term.description) - assertEquals(tagWithEditContext.count.toInt(), payload.term.postCount) + assertEquals(anyTermWithEditContext.name, payload.term.name) + assertEquals(anyTermWithEditContext.slug, payload.term.slug) + assertEquals(anyTermWithEditContext.description, payload.term.description) + assertEquals(anyTermWithEditContext.count.toInt(), payload.term.postCount) assertNull(payload.error) } @@ -708,6 +705,7 @@ class TaxonomyRsApiRestClientTest { testTagTermModel.slug, testTagTermModel.description, testTagTermModel.parentRemoteId, + testTagTermModel.isHierarchical, testTagTermModel.postCount ) @@ -725,16 +723,16 @@ class TaxonomyRsApiRestClientTest { assertEquals(TaxonomyErrorType.GENERIC_ERROR, payload.error?.type) } - private fun createTestCategoryDeleteData(deleted: Boolean): CategoryDeleteResponse { - return CategoryDeleteResponse(deleted, createTestCategoryWithEditContext()) + private fun createTestCategoryDeleteData(deleted: Boolean): TermDeleteResponse { + return TermDeleteResponse(deleted, createTestAnyTermWithEditContext()) } - private fun createTestTagDeleteData(deleted: Boolean): TagDeleteResponse { - return TagDeleteResponse(deleted, createTestTagWithEditContext()) + private fun createTestTagDeleteData(deleted: Boolean): TermDeleteResponse { + return TermDeleteResponse(deleted, createTestAnyTermWithEditContext()) } - private fun createTestCategoryWithEditContext(): CategoryWithEditContext { - return CategoryWithEditContext( + private fun createTestAnyTermWithEditContext(): AnyTermWithEditContext { + return AnyTermWithEditContext( id = 2L, count = 3L, description = "Test category description", @@ -745,17 +743,5 @@ class TaxonomyRsApiRestClientTest { parent = 0L ) } - - private fun createTestTagWithEditContext(): TagWithEditContext { - return TagWithEditContext( - id = 1L, - count = 5L, - description = "Test tag description", - link = "https://example.com/tag/test", - name = "Test Tag", - slug = "test-tag", - taxonomy = TaxonomyType.PostTag - ) - } } diff --git a/libs/fluxc/src/test/java/org/wordpress/android/fluxc/taxonomy/TaxonomyTestUtils.java b/libs/fluxc/src/test/java/org/wordpress/android/fluxc/taxonomy/TaxonomyTestUtils.java index cf4c54b16d46..fb9433e0ad33 100644 --- a/libs/fluxc/src/test/java/org/wordpress/android/fluxc/taxonomy/TaxonomyTestUtils.java +++ b/libs/fluxc/src/test/java/org/wordpress/android/fluxc/taxonomy/TaxonomyTestUtils.java @@ -21,6 +21,7 @@ private static TermModel generateSampleTerm(@NonNull String taxonomy) { "travel", "Post about travelling", 0, + false, 0 ); }