sharepoint_cli/commands/
sites.rs1use crate::auth::AuthContext;
4use crate::cli::{Runtime, SitesCmd};
5use crate::config;
6use crate::error::{CliError, Result};
7use crate::graph::{GraphClient, sites};
8
9pub async fn run(rt: &Runtime, cmd: SitesCmd) -> Result<()> {
10 match cmd {
11 SitesCmd::List {
12 query,
13 limit,
14 all,
15 page,
16 } => list(rt, query.as_deref(), limit, all, page.as_deref()).await,
17 SitesCmd::Use { site } => use_site(rt, &site).await,
18 }
19}
20
21async fn list(
22 rt: &Runtime,
23 query: Option<&str>,
24 limit: usize,
25 all: bool,
26 page: Option<&str>,
27) -> Result<()> {
28 let auth = AuthContext::new(rt.cfg.clone(), rt.cache_path.clone());
29 let graph = GraphClient::new(auth);
30
31 let mut items = Vec::new();
32 let mut next_token: Option<String> = page.map(String::from);
33 let mut source_label;
34 loop {
35 let res = sites::list(&graph, query, next_token.as_deref()).await?;
36 source_label = match res.source {
37 sites::SiteListSource::Followed => "followed",
38 sites::SiteListSource::Search => "search",
39 };
40 for s in res.items {
41 items.push(s);
42 if !all && items.len() >= limit {
43 break;
44 }
45 }
46 if !all || res.next.is_none() {
47 next_token = if all { None } else { res.next };
48 break;
49 }
50 next_token = res.next;
51 }
52
53 let total = items.len();
54 if rt.out.json {
55 let json_items: Vec<_> = items
56 .iter()
57 .map(|s| {
58 serde_json::json!({
59 "id": s.id,
60 "name": s.display_name,
61 "url": s.web_url,
62 })
63 })
64 .collect();
65 rt.out.print_json(&serde_json::json!({
66 "total": total,
67 "next": next_token,
68 "source": source_label,
69 "items": json_items,
70 }));
71 } else {
72 for s in &items {
73 rt.out
74 .print_data(&format!("{:40} {}", s.display_name, s.web_url));
75 }
76 rt.out
77 .print_message(&format!("({total} site(s), source={source_label})"));
78 }
79 Ok(())
80}
81
82async fn use_site(rt: &Runtime, value: &str) -> Result<()> {
83 if rt.cfg.read_only {
84 return Err(CliError::ReadOnly(
85 "sites use modifies the config file; not allowed in read-only mode".into(),
86 ));
87 }
88 let mut file = rt.config_file.clone();
89 let entry = file.profile.entry(rt.cfg.profile_name.clone()).or_default();
90 entry.default_site = Some(value.to_string());
91 config::save_file(&rt.config_path, &file)?;
92 rt.out.print_message(&format!(
93 "Set default_site for profile '{}' to '{}'",
94 rt.cfg.profile_name, value
95 ));
96 if rt.out.json {
97 rt.out.print_json(&serde_json::json!({
98 "profile": rt.cfg.profile_name,
99 "default_site": value,
100 }));
101 }
102 Ok(())
103}