95 lines
3.2 KiB
Rust
95 lines
3.2 KiB
Rust
//! `subscription [--watch|--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).
|
|
//!
|
|
//! There is deliberately no `--ignore`: Forgejo's subscription endpoint
|
|
//! has no way to mark a repo ignored without also watching it (its PUT
|
|
//! takes no body), so a mute flag here can only ever be subscribe or
|
|
//! unsubscribe under the hood. Rather than keep a flag that refuses with
|
|
//! an error, this verb just exposes the two states Forgejo actually has.
|
|
|
|
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)]
|
|
pub struct Args {
|
|
/// Subscribe (watch the repo).
|
|
#[arg(long, group = "action")]
|
|
watch: bool,
|
|
/// Unsubscribe (stop watching).
|
|
#[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` / `--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 {
|
|
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()),
|
|
}
|
|
}
|