Skip to content

Commit e352c8d

Browse files
committed
Refactor to extract Auth params
To make things more generic for potential future subcommands that might need similar auth instead of making this too specific to FetchPost
1 parent a0a5e78 commit e352c8d

File tree

1 file changed

+59
-43
lines changed

1 file changed

+59
-43
lines changed

wp_rs_cli/src/bin/wp_rs_cli/main.rs

Lines changed: 59 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use anyhow::{Result, anyhow};
2-
use clap::{ArgGroup, Parser, Subcommand};
2+
use clap::{ArgGroup, Args, Parser, Subcommand};
33
use colored::Colorize;
44
use csv::Writer;
55
use futures::stream::StreamExt;
@@ -68,7 +68,7 @@ async fn resolve_post_id(client: &WpApiClient, args: &FetchPostArgs) -> Result<P
6868
if let Some(id) = args.post_id {
6969
return Ok(id);
7070
}
71-
let Some(post_url) = &args.post_url else {
71+
let Some(post_url) = &args.url else {
7272
return Err(anyhow!("Either --post-id or --post-url must be provided"));
7373
};
7474

@@ -179,40 +179,25 @@ fn build_login_client() -> WpLoginClient {
179179
#[derive(Debug, Parser)]
180180
#[command(group(
181181
ArgGroup::new("target")
182-
.args(["wpcom_site", "api_root"]),
182+
.args(["wpcom_site", "api_root", "url"]),
183183
), group(
184184
ArgGroup::new("post_ref")
185185
.required(true)
186-
.args(["post_id", "post_url"]),
186+
.args(["post_id", "url"]),
187187
))]
188188
struct FetchPostArgs {
189-
/// The post ID to fetch
190-
#[arg(long, value_parser = parse_post_id)]
191-
post_id: Option<PostId>,
189+
/// Common authentication and target parameters
190+
#[command(flatten)]
191+
auth: AuthArgs,
192192

193193
/// Full post URL (alternative to --post-id)
194+
/// When provided, this URL is used to infer the site (wp.com) or autodiscover the API root (wp.org/Jetpack).
194195
#[arg(long)]
195-
post_url: Option<String>,
196-
197-
/// For WordPress.com: site identifier (e.g. example.wordpress.com or numeric site id)
198-
#[arg(long)]
199-
wpcom_site: Option<String>,
200-
201-
/// For WordPress.org/Jetpack: full API root URL (must end with /wp-json)
202-
#[arg(long)]
203-
api_root: Option<String>,
204-
205-
/// Bearer token for WordPress.com (fallback env: WP_BEARER_TOKEN)
206-
#[arg(long)]
207-
bearer: Option<String>,
208-
209-
/// Application Password username for wp.org/Jetpack (fallback env: WP_USERNAME)
210-
#[arg(long)]
211-
username: Option<String>,
196+
url: Option<String>,
212197

213-
/// Application Password for wp.org/Jetpack (fallback env: WP_APP_PASSWORD)
214-
#[arg(long)]
215-
password: Option<String>,
198+
/// The post ID to fetch
199+
#[arg(long, value_parser = parse_post_id)]
200+
post_id: Option<PostId>,
216201

217202
/// Password for the post if it is password-protected
218203
#[arg(long)]
@@ -239,7 +224,30 @@ enum TargetSiteResolver {
239224
WpOrg { api_root: Arc<ParsedUrl> },
240225
}
241226

242-
async fn build_api_client(args: &FetchPostArgs) -> Result<WpApiClient> {
227+
#[derive(Debug, Args, Clone)]
228+
struct AuthArgs {
229+
/// WordPress.com site (e.g. example.wordpress.com or numeric ID)
230+
#[arg(long)]
231+
wpcom_site: Option<String>,
232+
233+
/// WordPress.org/Jetpack API root (must end with /wp-json)
234+
#[arg(long)]
235+
api_root: Option<String>,
236+
237+
/// Bearer token for WordPress.com (fallback env: WP_BEARER_TOKEN)
238+
#[arg(long)]
239+
bearer: Option<String>,
240+
241+
/// Application Password username for wp.org/Jetpack (fallback env: WP_USERNAME)
242+
#[arg(long)]
243+
username: Option<String>,
244+
245+
/// Application Password for wp.org/Jetpack (fallback env: WP_APP_PASSWORD)
246+
#[arg(long)]
247+
password: Option<String>,
248+
}
249+
250+
async fn build_api_client(args: &AuthArgs, url: &Option<String>) -> Result<WpApiClient> {
243251
let request_executor = Arc::new(ReqwestRequestExecutor::new(false, Duration::from_secs(60)));
244252
let middleware_pipeline = Arc::new(WpApiMiddlewarePipeline::default());
245253
// Determine target and auth
@@ -248,38 +256,46 @@ async fn build_api_client(args: &FetchPostArgs) -> Result<WpApiClient> {
248256
TargetSiteResolver::WpCom { site: site.clone() }
249257
} else if let Some(api_root) = &args.api_root {
250258
// Explicit api_root takes priority for wp.org/Jetpack
251-
let parsed = ParsedUrl::try_from(api_root.as_str())
252-
.map_err(|_| anyhow!("Invalid api_root URL: must be a valid URL ending with /wp-json"))?;
253-
TargetSiteResolver::WpOrg { api_root: Arc::new(parsed) }
254-
} else if let Some(post_url) = &args.post_url {
255-
// Derive from post_url if possible
256-
if let Ok(u) = Url::parse(post_url) {
259+
let parsed = ParsedUrl::try_from(api_root.as_str()).map_err(|_| {
260+
anyhow!("Invalid api_root URL: must be a valid URL ending with /wp-json")
261+
})?;
262+
TargetSiteResolver::WpOrg {
263+
api_root: Arc::new(parsed),
264+
}
265+
} else if let Some(url) = url {
266+
// Derive from URL if possible
267+
if let Ok(u) = Url::parse(url.as_str()) {
257268
let host = u.host_str().unwrap_or("");
258269
if host.ends_with(".wordpress.com") {
259-
TargetSiteResolver::WpCom { site: host.to_string() }
270+
TargetSiteResolver::WpCom {
271+
site: host.to_string(),
272+
}
260273
} else {
261-
// Attempt autodiscovery of API root from post URL
262-
let login_client = WpLoginClient::new_with_default_middleware_pipeline(request_executor.clone());
274+
// Attempt autodiscovery of API root from URL
275+
let login_client =
276+
WpLoginClient::new_with_default_middleware_pipeline(request_executor.clone());
263277
match login_client
264-
.api_discovery(post_url.clone())
278+
.api_discovery(url.clone())
265279
.await
266280
.combined_result()
267281
.cloned()
268282
{
269-
Ok(success) => TargetSiteResolver::WpOrg { api_root: success.api_root_url },
283+
Ok(success) => TargetSiteResolver::WpOrg {
284+
api_root: success.api_root_url,
285+
},
270286
Err(_) => {
271287
return Err(anyhow!(
272-
"Could not autodiscover API root from --post-url. Please provide --api-root explicitly."
288+
"Could not autodiscover API root from URL. Please provide --api-root explicitly."
273289
));
274290
}
275291
}
276292
}
277293
} else {
278-
return Err(anyhow!("Invalid --post-url; could not parse URL"));
294+
return Err(anyhow!("Invalid URL; could not parse"));
279295
}
280296
} else {
281297
return Err(anyhow!(
282-
"Provide either --wpcom-site, or --api-root, or a wordpress.com --post-url"
298+
"Provide either --wpcom-site, or --api-root, or a wordpress.com URL"
283299
));
284300
};
285301

@@ -339,7 +355,7 @@ async fn build_api_client(args: &FetchPostArgs) -> Result<WpApiClient> {
339355
}
340356

341357
async fn fetch_post_and_comments(args: FetchPostArgs) -> Result<()> {
342-
let client = build_api_client(&args).await?;
358+
let client = build_api_client(&args.auth, &args.url).await?;
343359

344360
let post_id = resolve_post_id(&client, &args).await?;
345361

0 commit comments

Comments
 (0)