Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

List /tags endpoint #464

Merged
merged 1 commit into from
Jan 15, 2025
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
@@ -0,0 +1,23 @@
package rs.wordpress.api.kotlin

import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.Test
import uniffi.wp_api.TagListParams
import uniffi.wp_api.wpAuthenticationFromUsernameAndPassword

class TagsEndpointTest {
private val testCredentials = TestCredentials.INSTANCE
private val siteUrl = testCredentials.parsedSiteUrl
private val authentication = wpAuthenticationFromUsernameAndPassword(
username = testCredentials.adminUsername, password = testCredentials.adminPassword
)
private val client = WpApiClient(siteUrl, authentication)

@Test
fun testTagListRequest() = runTest {
val tagList = client.request { requestBuilder ->
requestBuilder.tags().listWithEditContext(params = TagListParams())
}.assertSuccessAndRetrieveData().data
assert(tagList.isNotEmpty())
}
}
8 changes: 7 additions & 1 deletion wp_api/src/api_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use crate::request::{
post_types_endpoint::{PostTypesRequestBuilder, PostTypesRequestExecutor},
posts_endpoint::{PostsRequestBuilder, PostsRequestExecutor},
site_settings_endpoint::{SiteSettingsRequestBuilder, SiteSettingsRequestExecutor},
tags_endpoint::{TagsRequestBuilder, TagsRequestExecutor},
taxonomies_endpoint::{TaxonomiesRequestBuilder, TaxonomiesRequestExecutor},
users_endpoint::{UsersRequestBuilder, UsersRequestExecutor},
wp_site_health_tests_endpoint::{
Expand Down Expand Up @@ -48,6 +49,7 @@ pub struct WpApiRequestBuilder {
post_types: Arc<PostTypesRequestBuilder>,
posts: Arc<PostsRequestBuilder>,
site_settings: Arc<SiteSettingsRequestBuilder>,
tags: Arc<TagsRequestBuilder>,
taxonomies: Arc<TaxonomiesRequestBuilder>,
users: Arc<UsersRequestBuilder>,
wp_site_health_tests: Arc<WpSiteHealthTestsRequestBuilder>,
Expand All @@ -65,9 +67,10 @@ impl WpApiRequestBuilder {
plugins,
post_types,
posts,
site_settings,
tags,
taxonomies,
users,
site_settings,
wp_site_health_tests
)
}
Expand Down Expand Up @@ -101,6 +104,7 @@ pub struct WpApiClient {
post_types: Arc<PostTypesRequestExecutor>,
posts: Arc<PostsRequestExecutor>,
site_settings: Arc<SiteSettingsRequestExecutor>,
tags: Arc<TagsRequestExecutor>,
taxonomies: Arc<TaxonomiesRequestExecutor>,
users: Arc<UsersRequestExecutor>,
wp_site_health_tests: Arc<WpSiteHealthTestsRequestExecutor>,
Expand All @@ -125,6 +129,7 @@ impl WpApiClient {
post_types,
posts,
site_settings,
tags,
taxonomies,
users,
wp_site_health_tests
Expand All @@ -139,6 +144,7 @@ api_client_generate_endpoint_impl!(WpApi, plugins);
api_client_generate_endpoint_impl!(WpApi, post_types);
api_client_generate_endpoint_impl!(WpApi, posts);
api_client_generate_endpoint_impl!(WpApi, site_settings);
api_client_generate_endpoint_impl!(WpApi, tags);
api_client_generate_endpoint_impl!(WpApi, taxonomies);
api_client_generate_endpoint_impl!(WpApi, users);
api_client_generate_endpoint_impl!(WpApi, wp_site_health_tests);
Expand Down
1 change: 1 addition & 0 deletions wp_api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ pub mod post_types;
pub mod posts;
pub mod request;
pub mod site_settings;
pub mod tags;
pub mod taxonomies;
pub mod url_query;
pub mod users;
Expand Down
14 changes: 1 addition & 13 deletions wp_api/src/posts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use wp_serde_helper::{deserialize_from_string_of_json_array, serialize_as_json_s
use crate::{
impl_as_query_value_for_new_type, impl_as_query_value_from_as_str,
media::MediaId,
tags::TagId,
url_query::{
AppendUrlQueryPairs, AsQueryValue, FromUrlQueryPairs, QueryPairs, QueryPairsExtension,
UrlQueryPairsMap,
Expand Down Expand Up @@ -536,19 +537,6 @@ impl std::fmt::Display for PostId {
}
}

impl_as_query_value_for_new_type!(TagId);
uniffi::custom_newtype!(TagId, i64);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct TagId(pub i64);

impl FromStr for TagId {
type Err = ParseIntError;

fn from_str(s: &str) -> Result<Self, Self::Err> {
s.parse().map(Self)
}
}

impl_as_query_value_for_new_type!(CategoryId);
uniffi::custom_newtype!(CategoryId, i64);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
Expand Down
1 change: 1 addition & 0 deletions wp_api/src/request/endpoint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pub mod plugins_endpoint;
pub mod post_types_endpoint;
pub mod posts_endpoint;
pub mod site_settings_endpoint;
pub mod tags_endpoint;
pub mod taxonomies_endpoint;
pub mod users_endpoint;
pub mod wp_site_health_tests_endpoint;
Expand Down
3 changes: 2 additions & 1 deletion wp_api/src/request/endpoint/posts_endpoint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,14 @@ mod tests {
use crate::{
generate,
posts::{
CategoryId, PostRetrieveParams, PostStatus, TagId, WpApiParamPostsOrderBy,
CategoryId, PostRetrieveParams, PostStatus, WpApiParamPostsOrderBy,
WpApiParamPostsSearchColumn, WpApiParamPostsTaxRelation,
},
request::endpoint::{
tests::{fixture_api_base_url, validate_wp_v2_endpoint},
ApiBaseUrl,
},
tags::TagId,
UserId, WpApiParamOrder,
};
use rstest::*;
Expand Down
25 changes: 25 additions & 0 deletions wp_api/src/request/endpoint/tags_endpoint.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
use super::{AsNamespace, DerivedRequest, WpNamespace};
use crate::{
tags::{
SparseTagFieldWithEditContext, SparseTagFieldWithEmbedContext,
SparseTagFieldWithViewContext, TagListParams,
},
SparseField,
};
use wp_derive_request_builder::WpDerivedRequest;

#[derive(WpDerivedRequest)]
enum TagsRequest {
#[contextual_paged(url = "/tags", params = &TagListParams, output = Vec<crate::tags::SparseTag>, filter_by = crate::tags::SparseTagField)]
List,
}

impl DerivedRequest for TagsRequest {
fn namespace() -> impl AsNamespace {
WpNamespace::WpV2
}
}

super::macros::default_sparse_field_implementation_from_field_name!(SparseTagFieldWithEditContext);
super::macros::default_sparse_field_implementation_from_field_name!(SparseTagFieldWithEmbedContext);
super::macros::default_sparse_field_implementation_from_field_name!(SparseTagFieldWithViewContext);
206 changes: 206 additions & 0 deletions wp_api/src/tags.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
use std::{num::ParseIntError, str::FromStr};

use serde::{Deserialize, Serialize};
use strum_macros::IntoStaticStr;
use wp_contextual::WpContextual;

use crate::{
impl_as_query_value_for_new_type, impl_as_query_value_from_as_str,
posts::PostId,
taxonomies::TaxonomyType,
url_query::{
AppendUrlQueryPairs, AsQueryValue, FromUrlQueryPairs, QueryPairs, QueryPairsExtension,
UrlQueryPairsMap,
},
EnumFromStrParsingError, WpApiParamOrder,
};

impl_as_query_value_for_new_type!(TagId);
uniffi::custom_newtype!(TagId, i64);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct TagId(pub i64);

impl FromStr for TagId {
type Err = ParseIntError;

fn from_str(s: &str) -> Result<Self, Self::Err> {
s.parse().map(Self)
}
}

#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, uniffi::Enum)]
pub enum WpApiParamTagsOrderBy {
Id,
Include,
#[default]
Name,
Slug,
IncludeSlugs,
TermGroup,
Description,
Count,
}

impl_as_query_value_from_as_str!(WpApiParamTagsOrderBy);

impl WpApiParamTagsOrderBy {
fn as_str(&self) -> &str {
match self {
Self::Id => "id",
Self::Include => "include",
Self::Name => "name",
Self::Slug => "slug",
Self::IncludeSlugs => "include_slugs",
Self::TermGroup => "term_group",
Self::Description => "description",
Self::Count => "count",
}
}
}

impl FromStr for WpApiParamTagsOrderBy {
type Err = EnumFromStrParsingError;

fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"id" => Ok(Self::Id),
"include" => Ok(Self::Include),
"name" => Ok(Self::Name),
"slug" => Ok(Self::Slug),
"include_slugs" => Ok(Self::IncludeSlugs),
"term_group" => Ok(Self::TermGroup),
"description" => Ok(Self::Description),
"count" => Ok(Self::Count),
value => Err(EnumFromStrParsingError::UnknownVariant {
value: value.to_string(),
}),
}
}
}

#[derive(Debug, Default, PartialEq, Eq, uniffi::Record)]
pub struct TagListParams {
/// Current page of the collection.
/// Default: `1`
#[uniffi(default = None)]
pub page: Option<u32>,
/// Maximum number of items to be returned in result set.
/// Default: `10`
#[uniffi(default = None)]
pub per_page: Option<u32>,
/// Limit results to those matching a string.
#[uniffi(default = None)]
pub search: Option<String>,
/// Ensure result set excludes specific IDs.
#[uniffi(default = [])]
pub exclude: Vec<TagId>,
/// Limit result set to specific IDs.
#[uniffi(default = [])]
pub include: Vec<TagId>,
/// Offset the result set by a specific number of items.
#[uniffi(default = None)]
pub offset: Option<u32>,
/// Order sort attribute ascending or descending.
/// Default: `asc`
/// One of: `asc`, `desc`
#[uniffi(default = None)]
pub order: Option<WpApiParamOrder>,
/// Sort collection by user attribute.
/// Default: `name`
/// One of: `id`, `include`, `name`, `slug`, `include_slugs`, `term_group`, `description`, `count`
#[uniffi(default = None)]
pub orderby: Option<WpApiParamTagsOrderBy>,
/// Whether to hide terms not assigned to any posts.
#[uniffi(default = None)]
pub hide_empty: Option<bool>,
/// Limit result set to terms assigned to a specific post.
#[uniffi(default = None)]
pub post: Option<PostId>,
/// Limit result set to users with one or more specific slugs.
#[uniffi(default = [])]
pub slug: Vec<String>,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, IntoStaticStr)]
enum TagListParamsField {
#[strum(serialize = "page")]
Page,
#[strum(serialize = "per_page")]
PerPage,
#[strum(serialize = "search")]
Search,
#[strum(serialize = "exclude")]
Exclude,
#[strum(serialize = "include")]
Include,
#[strum(serialize = "offset")]
Offset,
#[strum(serialize = "order")]
Order,
#[strum(serialize = "orderby")]
Orderby,
#[strum(serialize = "hide_empty")]
HideEmpty,
#[strum(serialize = "post")]
Post,
#[strum(serialize = "slug")]
Slug,
}

impl AppendUrlQueryPairs for TagListParams {
fn append_query_pairs(&self, query_pairs_mut: &mut QueryPairs) {
query_pairs_mut
.append_option_query_value_pair(TagListParamsField::Page, self.page.as_ref())
.append_option_query_value_pair(TagListParamsField::PerPage, self.per_page.as_ref())
.append_option_query_value_pair(TagListParamsField::Search, self.search.as_ref())
.append_vec_query_value_pair(TagListParamsField::Exclude, &self.exclude)
.append_vec_query_value_pair(TagListParamsField::Include, &self.include)
.append_option_query_value_pair(TagListParamsField::Offset, self.offset.as_ref())
.append_option_query_value_pair(TagListParamsField::Order, self.order.as_ref())
.append_option_query_value_pair(TagListParamsField::Orderby, self.orderby.as_ref())
.append_option_query_value_pair(TagListParamsField::HideEmpty, self.hide_empty.as_ref())
.append_option_query_value_pair(TagListParamsField::Post, self.post.as_ref())
.append_vec_query_value_pair(TagListParamsField::Slug, &self.slug);
}
}

impl FromUrlQueryPairs for TagListParams {
fn from_url_query_pairs(query_pairs: UrlQueryPairsMap) -> Option<Self> {
Some(Self {
page: query_pairs.get(TagListParamsField::Page),
per_page: query_pairs.get(TagListParamsField::PerPage),
search: query_pairs.get(TagListParamsField::Search),
exclude: query_pairs.get_csv(TagListParamsField::Exclude),
include: query_pairs.get_csv(TagListParamsField::Include),
offset: query_pairs.get(TagListParamsField::Offset),
order: query_pairs.get(TagListParamsField::Order),
orderby: query_pairs.get(TagListParamsField::Orderby),
hide_empty: query_pairs.get(TagListParamsField::HideEmpty),
post: query_pairs.get(TagListParamsField::Post),
slug: query_pairs.get_csv(TagListParamsField::Slug),
})
}

fn supports_pagination() -> bool {
true
}
}

#[derive(Debug, Serialize, Deserialize, uniffi::Record, WpContextual)]
pub struct SparseTag {
#[WpContext(edit, embed, view)]
pub id: Option<TagId>,
#[WpContext(edit, view)]
pub count: Option<i64>,
#[WpContext(edit, view)]
pub description: Option<String>,
#[WpContext(edit, embed, view)]
pub link: Option<String>,
#[WpContext(edit, embed, view)]
pub name: Option<String>,
#[WpContext(edit, embed, view)]
pub slug: Option<String>,
#[WpContext(edit, embed, view)]
pub taxonomy: Option<TaxonomyType>,
// meta field is omitted for now: https://github.com/Automattic/wordpress-rs/issues/463
}
3 changes: 2 additions & 1 deletion wp_api_integration_tests/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ use std::sync::Arc;
use wp_api::{
comments::CommentId,
media::MediaId,
posts::{CategoryId, PostId, TagId},
posts::{CategoryId, PostId},
request::{
endpoint::media_endpoint::MediaUploadRequest, RequestExecutor, RequestMethod,
WpNetworkHeaderMap, WpNetworkRequest, WpNetworkResponse,
},
tags::TagId,
users::UserId,
MediaUploadRequestExecutionError, ParsedUrl, RequestExecutionError, WpApiClient, WpApiError,
WpAuthentication, WpErrorCode,
Expand Down
3 changes: 2 additions & 1 deletion wp_api_integration_tests/tests/test_posts_immut.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ use serial_test::parallel;
use wp_api::posts::{
CategoryId, PostId, PostListParams, PostRetrieveParams, PostStatus,
SparsePostFieldWithEditContext, SparsePostFieldWithEmbedContext,
SparsePostFieldWithViewContext, TagId, WpApiParamPostsOrderBy, WpApiParamPostsSearchColumn,
SparsePostFieldWithViewContext, WpApiParamPostsOrderBy, WpApiParamPostsSearchColumn,
WpApiParamPostsTaxRelation,
};
use wp_api::tags::TagId;
use wp_api::{generate, WpApiParamOrder};
use wp_api_integration_tests::{
api_client, AssertResponse, TestCredentials, FIRST_POST_ID, FIRST_USER_ID, SECOND_USER_ID,
Expand Down
Loading
Loading