-
Notifications
You must be signed in to change notification settings - Fork 3
Plugins endpoint #90
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Plugins endpoint #90
Changes from all commits
c83dfe0
79ce094
5dde634
1cd6788
c5f6046
b1214fb
fd951bb
514ad74
8461d81
be2028e
887c458
46b9a8a
c2bd1c4
20af86f
71d6f67
6f51a73
259d009
817a088
2afc5af
ef837fb
482d547
aa73608
b189438
6103231
4317929
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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('/'))) | ||
} | ||
} | ||
|
||
#[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(¶ms)), 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 | ||
} | ||
} |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -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::*; | ||||||
|
@@ -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; | ||||||
|
@@ -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(¶ms).ok(), | ||||||
} | ||||||
} | ||||||
|
||||||
pub fn retrieve_plugin_request(&self, context: WPContext, plugin: &str) -> WPNetworkRequest { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You mentioned introducing There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
||||||
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, | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be:
Suggested change
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(¶ms).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( | ||||||
|
There was a problem hiding this comment.
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?There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe something like 4317929?