Skip to content

Commit f011d9b

Browse files
committed
feat: add auth_keywords to HubItem and manager_update_hub_auth RPC
- HubItem: new auth_keywords field (serde default=[]) for UI autocomplete - hub_manager: add update_auth() to update in-memory + persist to DB - rpc/data: add RpcUpdateHubAuthRequest - rpc/server: add manager_update_hub_auth handler - Fix all HubItem struct literals to include auth_keywords field
1 parent a4a5f18 commit f011d9b

7 files changed

Lines changed: 104 additions & 0 deletions

File tree

src/database/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ mod tests {
210210
hub_icon_url: None,
211211
},
212212
api_keywords: vec!["owner".to_string(), "repo".to_string()],
213+
auth_keywords: vec![],
213214
app_url_templates: vec![],
214215
target_check_api: None,
215216
},

src/database/models/hub.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ mod tests {
5555
hub_icon_url: None,
5656
},
5757
api_keywords: vec!["owner".to_string(), "repo".to_string()],
58+
auth_keywords: vec![],
5859
app_url_templates: vec!["https://github.com/%owner/%repo/".to_string()],
5960
target_check_api: None,
6061
},

src/manager/cloud_config_getter.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,7 @@ mod tests {
285285
hub_icon_url: None,
286286
},
287287
api_keywords: vec!["owner".to_string(), "repo".to_string()],
288+
auth_keywords: vec![],
288289
app_url_templates: templates,
289290
target_check_api: None,
290291
}

src/manager/hub_manager.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,20 @@ impl HubManager {
5353
.any(|h| h.applications_mode_enabled())
5454
}
5555

56+
/// Update the auth map for a hub identified by UUID and persist the change.
57+
///
58+
/// Returns `false` if no hub with the given UUID exists.
59+
pub async fn update_auth(&self, uuid: &str, auth: HashMap<String, String>) -> Result<bool> {
60+
let mut hubs = self.hubs.write().await;
61+
let hub = match hubs.get_mut(uuid) {
62+
Some(h) => h,
63+
None => return Ok(false),
64+
};
65+
hub.auth = auth;
66+
get_db().upsert_hub(hub)?;
67+
Ok(true)
68+
}
69+
5670
/// Return hubs whose api_keywords contain any of the given app_id keys.
5771
pub async fn hubs_for_app(&self, app_id: &HashMap<String, Option<String>>) -> Vec<HubRecord> {
5872
let app_keys: Vec<&str> = app_id.keys().map(String::as_str).collect();
@@ -96,6 +110,7 @@ mod tests {
96110
hub_icon_url: None,
97111
},
98112
api_keywords: vec!["owner".to_string(), "repo".to_string()],
113+
auth_keywords: vec![],
99114
app_url_templates: vec![],
100115
target_check_api: None,
101116
},
@@ -125,4 +140,34 @@ mod tests {
125140
assert!(deleted);
126141
assert!(db.load_hubs().unwrap().is_empty());
127142
}
143+
144+
#[tokio::test]
145+
async fn test_update_auth() {
146+
let dir = tempfile::tempdir().unwrap();
147+
crate::database::init_db(dir.path()).ok();
148+
149+
// Insert the hub via HubManager so it is in both the global DB and in-memory state.
150+
let mgr = HubManager::load().unwrap();
151+
let hub = make_hub("uuid-auth");
152+
mgr.upsert_hub(hub).await.unwrap();
153+
154+
let new_auth: HashMap<String, String> =
155+
[("token".to_string(), "ghp_test123".to_string())].into();
156+
let ok = mgr
157+
.update_auth("uuid-auth", new_auth.clone())
158+
.await
159+
.unwrap();
160+
assert!(ok);
161+
162+
// Verify in-memory state updated.
163+
let updated = mgr.get_hub("uuid-auth").await.unwrap();
164+
assert_eq!(updated.auth, new_auth);
165+
166+
// Returns false for unknown UUID.
167+
let not_found = mgr
168+
.update_auth("no-such-uuid", HashMap::new())
169+
.await
170+
.unwrap();
171+
assert!(!not_found);
172+
}
128173
}

src/rpc/data.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,3 +396,16 @@ pub struct RpcCloudConfigApplyRequest {
396396
pub struct RpcCloudConfigInitRequest {
397397
pub api_url: String,
398398
}
399+
400+
/// Request to update the auth map for a hub.
401+
#[derive(Serialize, Deserialize, Debug)]
402+
pub struct RpcUpdateHubAuthRequest {
403+
pub hub_uuid: String,
404+
pub auth: HashMap<String, String>,
405+
}
406+
407+
impl ToRpcParams for RpcUpdateHubAuthRequest {
408+
fn to_rpc_params(self) -> Result<Option<Box<serde_json::value::RawValue>>, serde_json::Error> {
409+
to_raw_value(&self).map(Some)
410+
}
411+
}

src/rpc/server.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -592,6 +592,19 @@ pub async fn run_server(
592592
Ok::<bool, ErrorObjectOwned>(true)
593593
})?;
594594

595+
// manager_update_hub_auth: Replace the auth map for a hub and persist.
596+
module.register_async_method("manager_update_hub_auth", |params, _, _| async move {
597+
let request = params.parse::<RpcUpdateHubAuthRequest>()?;
598+
let mgr = get_hub_manager().ok_or_else(manager_not_init_err)?;
599+
let updated = mgr
600+
.read()
601+
.await
602+
.update_auth(&request.hub_uuid, request.auth)
603+
.await
604+
.map_err(map_manager_err)?;
605+
Ok::<bool, ErrorObjectOwned>(updated)
606+
})?;
607+
595608
// manager_delete_hub: Delete a hub by UUID
596609
module.register_async_method("manager_delete_hub", |params, _, _| async move {
597610
let request = params.parse::<RpcDeleteHubRequest>()?;

src/websdk/cloud_rules/data/hub_item.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use serde::{Deserialize, Serialize};
1414
/// }
1515
/// target_check_api: ""
1616
/// api_keywords: []
17+
/// auth_keywords: []
1718
/// app_url_templates": []
1819
/// }
1920
/// ```
@@ -35,6 +36,11 @@ pub struct HubItem {
3536
#[serde(rename = "api_keywords", default)]
3637
pub api_keywords: Vec<String>,
3738

39+
/// Auth parameter keys required by this hub (e.g. ["token"] for GitHub).
40+
/// Used by the UI to provide autocomplete suggestions when editing hub auth.
41+
#[serde(rename = "auth_keywords", default)]
42+
pub auth_keywords: Vec<String>,
43+
3844
#[serde(rename = "app_url_templates", default)]
3945
pub app_url_templates: Vec<String>,
4046

@@ -85,9 +91,33 @@ mod tests {
8591
assert_eq!(hub_item.info.hub_icon_url, Some("".to_string()));
8692
assert_eq!(hub_item.target_check_api, Some("".to_string()));
8793
assert_eq!(hub_item.api_keywords, ["owner", "repo"]);
94+
// Old config without auth_keywords deserializes to empty vec.
95+
assert_eq!(hub_item.auth_keywords, Vec::<String>::new());
8896
assert_eq!(
8997
hub_item.app_url_templates[0],
9098
"https://github.com/%owner/%repo/"
9199
);
92100
}
101+
102+
#[test]
103+
fn test_hub_item_auth_keywords() {
104+
let json = r#"
105+
{
106+
"base_version": 5,
107+
"config_version": 3,
108+
"uuid": "fd9b2602-62c5-4d55-bd1e-0d6537714ca0",
109+
"info": { "hub_name": "GitHub" },
110+
"api_keywords": ["owner", "repo"],
111+
"auth_keywords": ["token"],
112+
"app_url_templates": ["https://github.com/%owner/%repo/"]
113+
}
114+
"#;
115+
let hub_item: HubItem = serde_json::from_str(json).unwrap();
116+
assert_eq!(hub_item.auth_keywords, ["token"]);
117+
118+
// Round-trip serialization preserves auth_keywords.
119+
let serialized = serde_json::to_string(&hub_item).unwrap();
120+
let hub_item2: HubItem = serde_json::from_str(&serialized).unwrap();
121+
assert_eq!(hub_item2.auth_keywords, ["token"]);
122+
}
93123
}

0 commit comments

Comments
 (0)