Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
c83dfe0
Adds SparsePlugin
oguzkocer May 15, 2024
79ce094
Adds plugins list endpoint
oguzkocer May 15, 2024
5dde634
Implement list plugins request and its parsers
oguzkocer May 15, 2024
1cd6788
Replace plugin parsers with add_uniffi_exported_parser
oguzkocer May 15, 2024
c5f6046
Replace plugin_list_params! with generate! macro
oguzkocer May 15, 2024
b1214fb
Use extracted test helpers for plugins
oguzkocer May 16, 2024
fd951bb
Implement create plugin request
oguzkocer May 16, 2024
514ad74
Implement run_and_restore_wp_content_plugins
oguzkocer May 16, 2024
8461d81
Implements retrieve plugin
oguzkocer May 16, 2024
be2028e
Fix the retrieve plugin endpoint and its return type
oguzkocer May 16, 2024
887c458
A temporary helper bash script for fetching plugins
oguzkocer May 16, 2024
46b9a8a
Disable restoring wp-content plugins from plugins_mut tests
oguzkocer May 16, 2024
c2bd1c4
Add a separate parser for create plugin response
oguzkocer May 16, 2024
20af86f
Fix retrieve plugins endpoint
oguzkocer May 16, 2024
71d6f67
Implement update plugin request
oguzkocer May 16, 2024
6f51a73
Add an integration test for update plugin
oguzkocer May 16, 2024
259d009
Implement delete plugin request
oguzkocer May 16, 2024
817a088
Improve unit & immut integration tests for plugins
oguzkocer May 16, 2024
2afc5af
Fix backup/restoration of wp-content/plugins for integration tests
oguzkocer May 16, 2024
ef837fb
Remove temporary scripts used to test plugins
oguzkocer May 16, 2024
482d547
Ignore failures for delete-wp-plugins-backup make task
oguzkocer May 16, 2024
aa73608
Remove unused PluginAuthor
oguzkocer May 16, 2024
b189438
Add url encoding related unit tests for plugins endpoint
oguzkocer May 17, 2024
6103231
Merge remote-tracking branch 'origin/trunk' into plugins
oguzkocer May 20, 2024
4317929
Add an assertion for plugin author for retrieve plugin test
oguzkocer May 21, 2024
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
4 changes: 4 additions & 0 deletions .buildkite/setup-test-site.sh
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,7 @@ wp plugin delete wordpress-importer
## Create an Application password for a subscriber user, and store it where it can be used by the test suite
wp user application-password create themedemos test --porcelain
} >> /tmp/test_credentials

## Used for integration tests
wp plugin install hello-dolly --activate
wp plugin install classic-editor
11 changes: 10 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ test-server: stop-server
docker-compose up -d
docker-compose run wpcli

stop-server:
stop-server: delete-wp-plugins-backup
docker-compose down

dump-mysql:
Expand All @@ -201,6 +201,15 @@ dump-mysql:
restore-mysql:
docker exec -it wordpress-rs-mysql-1 /bin/bash -c "mysql --defaults-extra-file=mysql_config/config.cnf --database wordpress < dump.sql"

backup-wp-content-plugins:
docker exec -it wordpress /bin/bash -c "cp -R ./wp-content/plugins /tmp/backup_wp_plugins"

restore-wp-content-plugins:
docker exec -it wordpress /bin/bash -c "rm -rf ./wp-content/plugins && cp -R /tmp/backup_wp_plugins ./wp-content/plugins"

delete-wp-plugins-backup:
docker exec -it wordpress /bin/bash -c "rm -rf /tmp/backup_wp_plugins" || true

lint: lint-rust lint-swift

lint-rust:
Expand Down
4 changes: 4 additions & 0 deletions wp_api/src/endpoint.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use url::Url;

pub use plugins_endpoint::*;
pub use users_endpoint::*;

mod plugins_endpoint;
mod users_endpoint;

const WP_JSON_PATH_SEGMENTS: [&str; 3] = ["wp-json", "wp", "v2"];
Expand Down Expand Up @@ -47,13 +49,15 @@ impl ApiBaseUrl {
pub struct ApiEndpoint {
pub base_url: ApiBaseUrl,
pub users: UsersEndpoint,
pub plugins: PluginsEndpoint,
}

impl ApiEndpoint {
pub fn new(api_base_url: ApiBaseUrl) -> Self {
Self {
base_url: api_base_url.clone(),
users: UsersEndpoint::new(api_base_url.clone()),
plugins: PluginsEndpoint::new(api_base_url.clone()),
}
}

Expand Down
146 changes: 146 additions & 0 deletions wp_api/src/endpoint/plugins_endpoint.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
use url::Url;

use crate::{plugins::PluginListParams, ApiBaseUrl, WPContext};

pub struct PluginsEndpoint {
api_base_url: ApiBaseUrl,
}

impl PluginsEndpoint {
pub fn new(api_base_url: ApiBaseUrl) -> Self {
Self { api_base_url }
}

pub fn create(&self) -> Url {
self.plugins_base_url()
}

pub fn delete(&self, plugin: &str) -> Url {
self.plugins_url_with_slug(plugin)
}

pub fn list(&self, context: WPContext, params: Option<&PluginListParams>) -> Url {
let mut url = self.plugins_base_url();
url.query_pairs_mut()
.append_pair("context", context.as_str());
if let Some(params) = params {
url.query_pairs_mut().extend_pairs(params.query_pairs());
}
url
}

pub fn retrieve(&self, context: WPContext, plugin: &str) -> Url {
let mut url = self.plugins_url_with_slug(plugin);
url.query_pairs_mut()
.append_pair("context", context.as_str());
url
}

pub fn update(&self, plugin: &str) -> Url {
self.plugins_url_with_slug(plugin)
}

fn plugins_base_url(&self) -> Url {
self.api_base_url.by_appending("plugins")
}

fn plugins_url_with_slug(&self, plugin: &str) -> Url {
self.api_base_url
// The '/' character has to be preserved and not get encoded
.by_extending(["plugins"].into_iter().chain(plugin.split('/')))
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There was an issue in iOS app where the app crashed due to unexpected characters in plugin slug. See wordpress-mobile/WordPressKit-iOS#767.

I couldn't reproduce the crash, because I can't find a real-world plugin that has a non-ascii slug. However, I think it's still worthy adding some unit tests to ensure a correct URL is constructed for strange plugin slugs (i.e. has % or non-ascii charaectrs). What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added a few more tests for this in b189438. It'd be really good if we can find a real world case for it though.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe something like 4317929?

}

#[cfg(test)]
mod tests {
use super::*;
use crate::{
endpoint::tests::{fixture_api_base_url, validate_endpoint},
generate, ApiEndpoint, PluginStatus,
};
use rstest::*;

#[rstest]
fn create_plugin(plugins_endpoint: PluginsEndpoint) {
validate_endpoint(plugins_endpoint.create(), "/plugins");
}

#[rstest]
#[case("hello-dolly/hello", "/plugins/hello-dolly/hello")]
#[case(
"classic-editor/classic-editor",
"/plugins/classic-editor/classic-editor"
)]
#[case("foo/bar%baz", "/plugins/foo/bar%25baz")]
#[case("foo/です", "/plugins/foo/%E3%81%A7%E3%81%99")]
fn delete_plugin(
plugins_endpoint: PluginsEndpoint,
#[case] plugin_slug: &str,
#[case] expected_path: &str,
) {
validate_endpoint(plugins_endpoint.delete(plugin_slug), expected_path);
}

#[rstest]
#[case(WPContext::Edit, generate!(PluginListParams, (search, Some("foo".to_string()))), "/plugins?context=edit&search=foo")]
#[case(WPContext::Embed, generate!(PluginListParams, (status, Some(PluginStatus::Active))), "/plugins?context=embed&status=active")]
#[case(WPContext::View, generate!(PluginListParams, (search, Some("foo".to_string())), (status, Some(PluginStatus::Inactive))), "/plugins?context=view&search=foo&status=inactive")]
fn list_plugins_with_params(
plugins_endpoint: PluginsEndpoint,
#[case] context: WPContext,
#[case] params: PluginListParams,
#[case] expected_path: &str,
) {
validate_endpoint(plugins_endpoint.list(context, Some(&params)), expected_path);
}

#[rstest]
#[case(
"hello-dolly/hello",
WPContext::View,
"/plugins/hello-dolly/hello?context=view"
)]
#[case(
"classic-editor/classic-editor",
WPContext::Embed,
"/plugins/classic-editor/classic-editor?context=embed"
)]
#[case("foo/bar%baz", WPContext::Edit, "/plugins/foo/bar%25baz?context=edit")]
#[case(
"foo/です",
WPContext::View,
"/plugins/foo/%E3%81%A7%E3%81%99?context=view"
)]
fn retrieve_plugin(
plugins_endpoint: PluginsEndpoint,
#[case] plugin_slug: &str,
#[case] context: WPContext,
#[case] expected_path: &str,
) {
validate_endpoint(
plugins_endpoint.retrieve(context, plugin_slug),
expected_path,
);
}

#[rstest]
#[case("hello-dolly/hello", "/plugins/hello-dolly/hello")]
#[case(
"classic-editor/classic-editor",
"/plugins/classic-editor/classic-editor"
)]
#[case("foo/bar%baz", "/plugins/foo/bar%25baz")]
#[case("foo/です", "/plugins/foo/%E3%81%A7%E3%81%99")]
fn update_plugin(
plugins_endpoint: PluginsEndpoint,
#[case] plugin_slug: &str,
#[case] expected_path: &str,
) {
validate_endpoint(plugins_endpoint.update(plugin_slug), expected_path);
}

#[fixture]
fn plugins_endpoint(fixture_api_base_url: ApiBaseUrl) -> PluginsEndpoint {
ApiEndpoint::new(fixture_api_base_url).plugins
}
}
59 changes: 59 additions & 0 deletions wp_api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pub use api_error::*;
pub use endpoint::*;
pub use login::*;
pub use pages::*;
pub use plugins::*;
pub use posts::*;
pub use url::*;
pub use users::*;
Expand All @@ -15,6 +16,7 @@ pub mod api_error;
pub mod endpoint;
pub mod login;
pub mod pages;
pub mod plugins;
pub mod posts;
pub mod url;
pub mod users;
Expand Down Expand Up @@ -223,6 +225,63 @@ impl WPApiHelper {
}
}

pub fn list_plugins_request(
&self,
context: WPContext,
params: &Option<PluginListParams>, // UniFFI doesn't support Option<&T>
) -> WPNetworkRequest {
WPNetworkRequest {
method: RequestMethod::GET,
url: self
.api_endpoint
.plugins
.list(context, params.as_ref())
.into(),
header_map: self.header_map(),
body: None,
}
}

pub fn create_plugin_request(&self, params: &PluginCreateParams) -> WPNetworkRequest {
WPNetworkRequest {
method: RequestMethod::POST,
url: self.api_endpoint.plugins.create().into(),
header_map: self.header_map_for_post_request(),
body: serde_json::to_vec(&params).ok(),
}
}

pub fn retrieve_plugin_request(&self, context: WPContext, plugin: &str) -> WPNetworkRequest {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mentioned introducing PluginSlug & WpOrgPluginSlug types. Will the plugin: &str be replaced by one of those types?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeap, this is one of the cases where it's not clear which type of slug it should take. (It's the PluginSlug in this example, just as a reference)

WPNetworkRequest {
method: RequestMethod::GET,
url: self.api_endpoint.plugins.retrieve(context, plugin).into(),
header_map: self.header_map(),
body: None,
}
}

pub fn update_plugin_request(
&self,
plugin: &str,
params: PluginUpdateParams,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be:

Suggested change
params: PluginUpdateParams,
params: &PluginUpdateParams,

It's addressed in a later PR, but I won't include it here to avoid the extra merge conflict. (as I have multiple PRs building on one another)

) -> WPNetworkRequest {
WPNetworkRequest {
method: RequestMethod::POST,
url: self.api_endpoint.plugins.update(plugin).into(),
header_map: self.header_map_for_post_request(),
body: serde_json::to_vec(&params).ok(),
}
}

pub fn delete_plugin_request(&self, plugin: &str) -> WPNetworkRequest {
WPNetworkRequest {
method: RequestMethod::DELETE,
url: self.api_endpoint.plugins.delete(plugin).into(),
header_map: self.header_map(),
body: None,
}
}

fn header_map(&self) -> HashMap<String, String> {
let mut header_map = HashMap::new();
header_map.insert(
Expand Down
Loading