//! `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 = 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()), } }