greentic_setup/webhook/
instructions.rs1use serde_json::Value;
7
8#[derive(Debug, Clone, serde::Serialize)]
10pub struct ProviderInstruction {
11 pub provider_name: String,
12 pub steps: Vec<String>,
13}
14
15pub fn collect_post_setup_instructions(
19 providers: &[(String, Value)],
20 tenant: &str,
21 team: &str,
22) -> Vec<ProviderInstruction> {
23 let mut instructions: Vec<(&str, Vec<String>)> = Vec::new();
24
25 for (provider_id, config) in providers {
26 let provider_short = provider_id
27 .strip_prefix("messaging-")
28 .unwrap_or(provider_id);
29
30 let public_base_url = config
31 .get("public_base_url")
32 .and_then(Value::as_str)
33 .unwrap_or("<your-public-url>");
34
35 match provider_short {
36 "teams" => {
37 let webhook_url = format!(
38 "{}/v1/messaging/ingress/{}/{}/{}",
39 public_base_url.trim_end_matches('/'),
40 provider_id,
41 tenant,
42 team,
43 );
44 instructions.push(("Microsoft Teams", vec![
45 "1. Go to Azure Portal → Bot Services → your bot".into(),
46 format!("2. Set Messaging Endpoint to: {webhook_url}"),
47 "3. Ensure the App ID and Password match your answers file".into(),
48 "4. Grant API permissions (delegated): Channel.ReadBasic.All, ChannelMessage.Send, Team.ReadBasic.All, ChatMessage.Send".into(),
49 "5. If using Graph API: complete OAuth flow to obtain a refresh token".into(),
50 " → See: docs/guides/providers/guide-teams-setup.md".into(),
51 ]));
52 }
53 "whatsapp" => {
54 let webhook_url = format!(
55 "{}/v1/messaging/ingress/{}/{}/{}",
56 public_base_url.trim_end_matches('/'),
57 provider_id,
58 tenant,
59 team,
60 );
61 instructions.push((
62 "WhatsApp",
63 vec![
64 "1. Go to Meta Developer Portal → WhatsApp → Configuration".into(),
65 format!("2. Set Webhook URL to: {webhook_url}"),
66 "3. Set Verify Token to match your config (if configured)".into(),
67 "4. Subscribe to webhook fields: messages".into(),
68 ],
69 ));
70 }
71 "webex" => {
72 let webex_token = config.get("webex_bot_token");
75 let bot_token = config.get("bot_token");
76 eprintln!(
77 " [debug] webex instruction check: webex_bot_token={:?} bot_token={:?}",
78 webex_token.map(|v| if v.as_str().map(|s| s.len()).unwrap_or(0) > 10 {
79 "***"
80 } else {
81 "empty"
82 }),
83 bot_token.map(|v| if v.as_str().map(|s| s.len()).unwrap_or(0) > 10 {
84 "***"
85 } else {
86 "empty"
87 })
88 );
89 let has_token = webex_token
90 .or(bot_token)
91 .and_then(Value::as_str)
92 .is_some_and(|s| !s.is_empty());
93 if !has_token {
94 instructions.push((
95 "Webex",
96 vec![
97 "1. Create a Webex Bot at: https://developer.webex.com/my-apps/new/bot"
98 .into(),
99 "2. Copy the bot access token into your answers file as 'webex_bot_token'"
100 .into(),
101 "3. Re-run setup to register webhooks automatically".into(),
102 ],
103 ));
104 }
105 }
106 "slack" => {
107 let has_app_id = config
109 .get("slack_app_id")
110 .and_then(Value::as_str)
111 .is_some_and(|s| !s.is_empty());
112 if !has_app_id {
113 instructions.push(("Slack", vec![
114 "1. Create a Slack App at: https://api.slack.com/apps".into(),
115 "2. Add 'slack_app_id' and 'slack_configuration_token' to your answers file".into(),
116 "3. Re-run setup to update the app manifest automatically".into(),
117 ]));
118 }
119 }
120 _ => {}
121 }
122 }
123
124 instructions
125 .into_iter()
126 .map(|(name, steps)| ProviderInstruction {
127 provider_name: name.to_string(),
128 steps,
129 })
130 .collect()
131}
132
133pub fn print_post_setup_instructions(providers: &[(String, Value)], tenant: &str, team: &str) {
138 let instructions = collect_post_setup_instructions(providers, tenant, team);
139
140 if instructions.is_empty() {
141 return;
142 }
143
144 println!();
145 println!("──────────────────────────────────────────────────────────");
146 println!(" Manual steps required:");
147 println!("──────────────────────────────────────────────────────────");
148 for instr in &instructions {
149 println!();
150 println!(" [{}]", instr.provider_name);
151 for step in &instr.steps {
152 println!(" {step}");
153 }
154 }
155 println!();
156 println!("──────────────────────────────────────────────────────────");
157}