greentic_setup/webhook/
mod.rs1mod instructions;
12
13use serde_json::{Value, json};
14
15pub use instructions::{
17 ProviderInstruction, collect_post_setup_instructions, print_post_setup_instructions,
18};
19
20pub fn registration_result_from_declared_ops(config: &Value) -> Option<Value> {
25 let webhook_ops = config.get("webhook_ops")?.as_array()?;
26 if webhook_ops.is_empty() {
27 return None;
28 }
29 let subscription_ops = config
30 .get("subscription_ops")
31 .and_then(Value::as_array)
32 .cloned()
33 .unwrap_or_default();
34 let oauth_ops = config
35 .get("oauth_ops")
36 .and_then(Value::as_array)
37 .cloned()
38 .unwrap_or_default();
39
40 Some(json!({
41 "ok": true,
42 "mode": "declared_ops",
43 "webhook_ops": webhook_ops,
44 "subscription_ops": subscription_ops,
45 "oauth_ops": oauth_ops,
46 }))
47}
48
49pub fn has_webhook_url(answers: &Value) -> Option<&str> {
52 answers
53 .as_object()?
54 .get("public_base_url")?
55 .as_str()
56 .filter(|url| !url.is_empty() && url.starts_with("https://"))
57}
58
59pub fn register_webhook(
66 _provider_id: &str,
67 config: &Value,
68 _tenant: &str,
69 _team: Option<&str>,
70) -> Option<Value> {
71 registration_result_from_declared_ops(config)
73}
74
75pub fn build_webhook_url(
77 public_base_url: &str,
78 provider_id: &str,
79 tenant: &str,
80 team: &str,
81) -> String {
82 format!(
83 "{}/v1/messaging/ingress/{}/{}/{}",
84 public_base_url.trim_end_matches('/'),
85 provider_id,
86 tenant,
87 team,
88 )
89}
90
91#[cfg(test)]
92mod tests {
93 use super::*;
94
95 #[test]
96 fn has_webhook_url_valid() {
97 let config = json!({"public_base_url": "https://example.com"});
98 assert_eq!(has_webhook_url(&config), Some("https://example.com"));
99 }
100
101 #[test]
102 fn registration_result_from_declared_ops_uses_declared_ops() {
103 let config = json!({
104 "webhook_ops": [{"op": "register", "url": "https://example.com/webhook"}],
105 "subscription_ops": [{"op": "sync"}],
106 "oauth_ops": []
107 });
108 let result =
109 registration_result_from_declared_ops(&config).expect("declared ops registration");
110 assert_eq!(result["ok"], Value::Bool(true));
111 assert_eq!(result["mode"], Value::String("declared_ops".to_string()));
112 assert_eq!(
113 result["webhook_ops"][0]["op"],
114 Value::String("register".to_string())
115 );
116 }
117
118 #[test]
119 fn register_webhook_prefers_declared_ops() {
120 let config = json!({
121 "public_base_url": "http://example.com",
122 "webhook_ops": [{"op": "register", "url": "https://example.com/webhook"}]
123 });
124 let result = register_webhook("messaging-unknown", &config, "demo", None)
125 .expect("declared ops fallback");
126 assert_eq!(result["mode"], Value::String("declared_ops".to_string()));
127 }
128
129 #[test]
130 fn has_webhook_url_http_rejected() {
131 let config = json!({"public_base_url": "http://example.com"});
132 assert_eq!(has_webhook_url(&config), None);
133 }
134
135 #[test]
136 fn has_webhook_url_empty_rejected() {
137 let config = json!({"public_base_url": ""});
138 assert_eq!(has_webhook_url(&config), None);
139 }
140
141 #[test]
142 fn register_webhook_returns_none_without_declared_ops() {
143 let config = json!({"public_base_url": "https://example.com", "bot_token": "x"});
144 assert!(register_webhook("messaging-telegram", &config, "demo", None).is_none());
145 }
146
147 #[test]
148 fn register_webhook_returns_none_without_public_url() {
149 let config = json!({"bot_token": "x"});
150 assert!(register_webhook("messaging-telegram", &config, "demo", None).is_none());
151 }
152
153 #[test]
154 fn build_webhook_url_format() {
155 let url = build_webhook_url(
156 "https://example.com",
157 "messaging-telegram",
158 "demo",
159 "default",
160 );
161 assert_eq!(
162 url,
163 "https://example.com/v1/messaging/ingress/messaging-telegram/demo/default"
164 );
165 }
166
167 #[test]
168 fn build_webhook_url_trims_trailing_slash() {
169 let url = build_webhook_url(
170 "https://example.com/",
171 "messaging-telegram",
172 "demo",
173 "default",
174 );
175 assert_eq!(
176 url,
177 "https://example.com/v1/messaging/ingress/messaging-telegram/demo/default"
178 );
179 }
180}