diff --git a/wp_api/src/api_error.rs b/wp_api/src/api_error.rs index 005237c7..d23f82c9 100644 --- a/wp_api/src/api_error.rs +++ b/wp_api/src/api_error.rs @@ -274,6 +274,8 @@ pub enum WpErrorCode { TaxonomyInvalid, #[serde(rename = "rest_template_already_trashed")] TemplateAlreadyTrashed, + #[serde(rename = "rest_template_insert_error")] + TemplateInsertError, #[serde(rename = "rest_template_not_found")] TemplateNotFound, #[serde(rename = "rest_term_invalid")] diff --git a/wp_api/src/request/endpoint/templates_endpoint.rs b/wp_api/src/request/endpoint/templates_endpoint.rs index a1cb5e14..37fa5b14 100644 --- a/wp_api/src/request/endpoint/templates_endpoint.rs +++ b/wp_api/src/request/endpoint/templates_endpoint.rs @@ -12,6 +12,8 @@ enum TemplatesRequest { List, #[contextual_get(url = "/templates/", output = crate::templates::SparseTemplate, filter_by = crate::templates::SparseTemplateField)] Retrieve, + #[post(url = "/templates", params = &crate::templates::TemplateCreateParams, output = crate::templates::TemplateWithEditContext)] + Create, #[delete(url = "/templates/", output = crate::templates::TemplateDeleteResponse)] Delete, #[delete(url = "/templates/", output = crate::templates::TemplateWithEditContext)] @@ -78,6 +80,11 @@ mod tests { use rstest::*; use std::sync::Arc; + #[rstest] + fn create_template(endpoint: TemplatesRequestEndpoint) { + validate_wp_v2_endpoint(endpoint.create(), "/templates"); + } + #[rstest] #[case(TemplateListParams::default(), "")] #[case(generate!(TemplateListParams, (post_id, Some(PostId(2)))), "wp_id=2")] diff --git a/wp_api/src/templates.rs b/wp_api/src/templates.rs index bcad5777..48ba919c 100644 --- a/wp_api/src/templates.rs +++ b/wp_api/src/templates.rs @@ -1,5 +1,5 @@ use crate::{ - UserId, impl_as_query_value_from_to_string, + BoolOrString, UserId, impl_as_query_value_from_to_string, post_types::PostType, posts::PostId, url_query::{ @@ -160,7 +160,7 @@ pub struct SparseTemplate { #[WpContext(edit, embed, view)] pub author: Option, #[WpContext(edit, view)] - pub modified: Option, + pub modified: Option, #[WpContext(edit, view, embed)] pub is_custom: Option, #[WpContext(edit, view, embed)] @@ -239,3 +239,53 @@ pub struct TemplateUpdateParams { #[serde(skip_serializing_if = "Option::is_none")] pub author: Option, } + +#[derive(Debug, Serialize, uniffi::Record)] +pub struct TemplateCreateParams { + // Unique slug identifying the template. + pub slug: String, + // Theme identifier for the template. + #[uniffi(default = None)] + #[serde(skip_serializing_if = "Option::is_none")] + pub theme: Option, + // Type of template. + #[uniffi(default = None)] + #[serde(skip_serializing_if = "Option::is_none")] + pub template_type: Option, + // Content of template. + #[uniffi(default = None)] + #[serde(skip_serializing_if = "Option::is_none")] + pub content: Option, + // Title of template. + #[uniffi(default = None)] + #[serde(skip_serializing_if = "Option::is_none")] + pub title: Option, + // Description of template. + #[uniffi(default = None)] + #[serde(skip_serializing_if = "Option::is_none")] + pub description: Option, + // Status of template. + // One of: publish, future, draft, pending, private + #[uniffi(default = None)] + #[serde(skip_serializing_if = "Option::is_none")] + pub status: Option, + // The ID for the author of the template. + #[uniffi(default = None)] + #[serde(skip_serializing_if = "Option::is_none")] + pub author: Option, +} + +impl TemplateCreateParams { + pub fn new(slug: String) -> Self { + Self { + slug, + theme: None, + template_type: None, + content: None, + title: None, + description: None, + status: None, + author: None, + } + } +} diff --git a/wp_api_integration_tests/tests/test_templates_err.rs b/wp_api_integration_tests/tests/test_templates_err.rs index ed351689..0ff5ca82 100644 --- a/wp_api_integration_tests/tests/test_templates_err.rs +++ b/wp_api_integration_tests/tests/test_templates_err.rs @@ -1,10 +1,21 @@ use serial_test::parallel; use wp_api::{ WpErrorCode, - templates::{TemplateId, TemplateUpdateParams}, + templates::{TemplateCreateParams, TemplateId, TemplateUpdateParams}, }; use wp_api_integration_tests::{AssertWpError, TEMPLATE_TWENTY_TWENTY_FOUR_SINGLE, api_client}; +#[tokio::test] +#[parallel] +async fn create_template_err_empty_content() { + // Creating a template requires `title` or `content` + api_client() + .templates() + .create(&TemplateCreateParams::new("foo".to_string())) + .await + .assert_wp_error(WpErrorCode::EmptyContent) +} + #[tokio::test] #[parallel] async fn delete_template_err_invalid_template() { diff --git a/wp_api_integration_tests/tests/test_templates_mut.rs b/wp_api_integration_tests/tests/test_templates_mut.rs index fb6dbe94..cb1590fe 100644 --- a/wp_api_integration_tests/tests/test_templates_mut.rs +++ b/wp_api_integration_tests/tests/test_templates_mut.rs @@ -1,6 +1,6 @@ use macro_helper::generate_update_test; use serial_test::serial; -use wp_api::templates::{TemplateId, TemplateUpdateParams}; +use wp_api::templates::{TemplateCreateParams, TemplateId, TemplateStatus, TemplateUpdateParams}; use wp_api_integration_tests::{ AssertResponse, TEMPLATE_CUSTOM, api_client, backend::RestoreServer, }; @@ -22,8 +22,60 @@ async fn delete_template() { RestoreServer::db().await; } +#[tokio::test] +#[serial] +async fn create_template_with_slug_and_content() { + let mut params = TemplateCreateParams::new("foo".to_string()); + params.content = Some("foo template content".to_string()); + test_create_template(¶ms).await; +} + +#[tokio::test] +#[serial] +async fn create_template_with_slug_and_title() { + let mut params = TemplateCreateParams::new("foo".to_string()); + params.title = Some("foo template title".to_string()); + test_create_template(¶ms).await; +} + +#[tokio::test] +#[serial] +async fn create_template_with_slug_title_and_theme() { + let mut params = TemplateCreateParams::new("foo".to_string()); + params.title = Some("foo template title".to_string()); + params.theme = Some("foo template theme".to_string()); + test_create_template(¶ms).await; +} + +#[tokio::test] +#[serial] +async fn create_template_with_slug_title_and_template_type() { + let mut params = TemplateCreateParams::new("foo".to_string()); + params.title = Some("foo template title".to_string()); + params.template_type = Some("foo template type".to_string()); + test_create_template(¶ms).await; +} + +#[tokio::test] +#[serial] +async fn create_template_with_slug_title_and_template_status_pending() { + let mut params = TemplateCreateParams::new("foo".to_string()); + params.title = Some("foo template title".to_string()); + params.status = Some(TemplateStatus::Pending); + test_create_template(¶ms).await; +} + generate_update_test!(update_slug, slug, "new_slug".to_string()); +async fn test_create_template(params: &TemplateCreateParams) { + api_client() + .templates() + .create(params) + .await + .assert_response(); + RestoreServer::db().await; +} + async fn test_update_template(params: &TemplateUpdateParams) { api_client() .templates()