seaplane_cli/ops/
restrict.rs1use std::{collections::BTreeSet, fmt::Display, io::Write};
2
3use seaplane::api::restrict::v1::{RestrictedDirectory as RestrictedDirectoryModel, Restriction};
4use serde::Serialize;
5use tabwriter::TabWriter;
6
7use super::EncodedString;
8use crate::{
9 context::Ctx,
10 error::{CliError, Result},
11 printer::{printer, Output},
12};
13
14#[derive(Debug, Clone, Serialize)]
20pub struct RestrictedDirectory {
21 pub directory: EncodedString,
22}
23
24impl RestrictedDirectory {
25 pub fn new<S: Into<String>>(directory: S) -> Self {
28 Self { directory: EncodedString::new(directory.into()) }
29 }
30
31 pub fn to_model(&self) -> RestrictedDirectoryModel {
33 RestrictedDirectoryModel::from_encoded(self.directory.to_string())
34 }
35}
36
37impl Output for Restriction {
38 fn print_json(&self, _ctx: &Ctx) -> Result<()> {
39 cli_println!("{}", serde_json::to_string(self)?);
40 Ok(())
41 }
42
43 fn print_table(&self, ctx: &Ctx) -> Result<()> {
44 let restrict_ctx = ctx.restrict_ctx.get_or_init();
45 let restrictions = Restrictions::from_model(vec![self.clone()]);
46 restrictions.impl_print_table(!restrict_ctx.no_header, restrict_ctx.decode)?;
47 Ok(())
48 }
49}
50
51#[derive(Debug, Default, Clone, Serialize)]
52#[serde(transparent)]
53pub struct Restrictions {
54 inner: Vec<Restriction>,
55}
56
57impl Restrictions {
58 pub fn from_model(model: Vec<Restriction>) -> Self { Self { inner: model } }
59
60 pub fn iter(&self) -> impl Iterator<Item = &Restriction> { self.inner.iter() }
61
62 fn impl_print_table(&self, headers: bool, decode: bool) -> Result<()> {
64 let mut tw = TabWriter::new(Vec::new());
65
66 fn join_set<S: Display>(set: BTreeSet<S>) -> String {
68 let mut vec = set.iter().map(|s| s.to_string()).collect::<Vec<String>>();
69 vec.sort();
70 vec.join(",")
71 }
72
73 if headers {
74 writeln!(tw, "API\tDIRECTORY\tSTATE\tREGIONS ALLOWED\tREGIONS DENIED\tPROVIDERS ALLOWED\tPROVIDERS DENIED")?;
75 }
76
77 for restriction in self.iter() {
78 let rd = RestrictedDirectory::new(restriction.directory.encoded());
79 write!(tw, "{}\t", restriction.api)?;
80
81 if decode {
82 tw.write_all(&rd.directory.decoded()?)?;
83 } else {
84 write!(tw, "{}", rd.directory)?;
85 }
86
87 writeln!(
88 tw,
89 "\t{}\t[{}]\t[{}]\t[{}]\t[{}]",
90 restriction.state,
91 join_set(restriction.details.regions_allowed.clone()),
92 join_set(restriction.details.regions_denied.clone()),
93 join_set(restriction.details.providers_allowed.clone()),
94 join_set(restriction.details.providers_denied.clone())
95 )?;
96 }
97 tw.flush()?;
98
99 let mut ptr = printer();
100 let page = tw
101 .into_inner()
102 .map_err(|_| CliError::bail("IO flush error writing restrictions"))?;
103 ptr.write_all(&page)?;
104 ptr.flush()?;
105
106 Ok(())
107 }
108}
109
110impl Output for Restrictions {
111 fn print_json(&self, _ctx: &Ctx) -> Result<()> {
112 cli_println!("{}", serde_json::to_string(self)?);
113 Ok(())
114 }
115
116 fn print_table(&self, ctx: &Ctx) -> Result<()> {
117 let restrict_ctx = ctx.restrict_ctx.get_or_init();
118 self.impl_print_table(!restrict_ctx.no_header, restrict_ctx.decode)
119 }
120}