Skip to content

Commit

Permalink
List /tags endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
oguzkocer committed Jan 15, 2025
1 parent f49258b commit 1a201e7
Show file tree
Hide file tree
Showing 11 changed files with 412 additions and 17 deletions.
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

0 comments on commit 1a201e7

Please sign in to comment.