104 lines
3.6 KiB
Rust
104 lines
3.6 KiB
Rust
//! `subscription [--watch|--ignore|--unwatch|--list] [repo]` — get or
|
|
//! set the current user's watch subscription for a repo, or list every
|
|
//! repo the user watches (`--list`, for auditing the notification
|
|
//! firehose).
|
|
|
|
use anyhow::Result;
|
|
use clap::Args as ClapArgs;
|
|
use serde_json::json;
|
|
|
|
use crate::client::{Client, is_not_found};
|
|
use crate::verbs::print_json;
|
|
|
|
#[derive(ClapArgs)]
|
|
#[allow(
|
|
clippy::struct_excessive_bools,
|
|
reason = "mutually-exclusive clap action flags (group = \"action\"); an \
|
|
enum would drop the --watch/--ignore/--unwatch/--list flag \
|
|
ergonomics agents already use"
|
|
)]
|
|
pub struct Args {
|
|
/// Subscribe (watch the repo).
|
|
#[arg(long, group = "action")]
|
|
watch: bool,
|
|
/// Mute (mark ignored).
|
|
#[arg(long, group = "action")]
|
|
ignore: bool,
|
|
/// Unsubscribe (clear watch + ignore).
|
|
#[arg(long, group = "action")]
|
|
unwatch: bool,
|
|
/// List every repo the current user watches (ignores `[repo]`).
|
|
#[arg(long, group = "action")]
|
|
list: bool,
|
|
}
|
|
|
|
/// Run the `subscription` verb: `--list` all watched repos, set the
|
|
/// current repo's watch (`--watch` / `--ignore` / `--unwatch`), or get
|
|
/// its current state.
|
|
///
|
|
/// # Errors
|
|
/// Propagates transport / non-2xx errors from the Forgejo client calls
|
|
/// and from `print_json`.
|
|
pub fn run(client: &Client, args: Args) -> Result<()> {
|
|
if args.list {
|
|
// List every repo the authed user watches, so an agent can audit
|
|
// its notification firehose and decide what to `--unwatch`. Not
|
|
// repo-scoped. Paginated, with a generous page cap so a
|
|
// misbehaving server can't spin us forever.
|
|
const MAX_PAGES: u32 = 50;
|
|
const PAGE: u32 = 50;
|
|
let mut watching: Vec<String> = Vec::new();
|
|
for page in 1..=MAX_PAGES {
|
|
let (_, repos) = client
|
|
.api()
|
|
.user_current_list_subscriptions()
|
|
.page(page)
|
|
.page_size(PAGE)
|
|
.send()?;
|
|
let n = repos.len();
|
|
watching.extend(repos.into_iter().filter_map(|r| r.full_name));
|
|
if n < PAGE as usize {
|
|
break;
|
|
}
|
|
}
|
|
return print_json(&json!({ "watching": watching }));
|
|
}
|
|
let (owner, name) = client.owner_repo()?;
|
|
if args.unwatch {
|
|
client
|
|
.api()
|
|
.user_current_delete_subscription(owner, name)
|
|
.send()?;
|
|
println!("unsubscribed");
|
|
return Ok(());
|
|
}
|
|
if args.watch || args.ignore {
|
|
// Forgejo's PUT subscription endpoint takes no body — it always
|
|
// subscribes (watch). The old raw client sent a
|
|
// `{subscribed, ignored}` body which the server ignored, so
|
|
// `--ignore` has always behaved like `--watch` server-side; the
|
|
// typed call just makes that explicit.
|
|
let resp = client
|
|
.api()
|
|
.user_current_put_subscription(owner, name)
|
|
.send()?;
|
|
return print_json(&json!({
|
|
"subscribed": resp.subscribed,
|
|
"ignored": resp.ignored,
|
|
}));
|
|
}
|
|
// Forgejo returns 404 when the current user is not watching the repo
|
|
// (rather than a response with subscribed=false).
|
|
match client
|
|
.api()
|
|
.user_current_check_subscription(owner, name)
|
|
.send()
|
|
{
|
|
Ok(resp) => print_json(&json!({
|
|
"subscribed": resp.subscribed,
|
|
"ignored": resp.ignored,
|
|
})),
|
|
Err(e) if is_not_found(&e) => print_json(&json!({ "subscribed": false, "ignored": false })),
|
|
Err(e) => Err(e.into()),
|
|
}
|
|
}
|