diff --git a/src-tauri/src/commands/config.rs b/src-tauri/src/commands/config.rs index 849bc9e..4e8c623 100644 --- a/src-tauri/src/commands/config.rs +++ b/src-tauri/src/commands/config.rs @@ -1626,6 +1626,8 @@ pub struct TelegramAccount { pub exclusive_topics: Option>, pub groups: Option, pub primary: Option, + #[serde(alias = "allowFrom", alias = "allow_from")] + pub allow_from: Option>, } /// Get all Telegram bot accounts @@ -1668,6 +1670,13 @@ pub async fn get_telegram_accounts() -> Result, String> { }, groups: acct_val.get("groups").cloned(), primary: None, // Will be set below + allow_from: acct_val.get("allowFrom") + .and_then(|v| v.as_array()) + .map(|arr| arr.iter().filter_map(|v| { + if let Some(s) = v.as_str() { Some(s.to_string()) } + else if let Some(n) = v.as_i64() { Some(n.to_string()) } + else { None } + }).collect()), }); } } @@ -1685,6 +1694,13 @@ pub async fn get_telegram_accounts() -> Result, String> { exclusive_topics: None, groups: config.pointer("/channels/telegram/groups").cloned(), primary: None, + allow_from: config.pointer("/channels/telegram/allowFrom") + .and_then(|v| v.as_array()) + .map(|arr| arr.iter().filter_map(|v| { + if let Some(s) = v.as_str() { Some(s.to_string()) } + else if let Some(n) = v.as_i64() { Some(n.to_string()) } + else { None } + }).collect()), }); } } @@ -1769,6 +1785,32 @@ pub async fn save_telegram_account(account: TelegramAccount) -> Result = af.iter().map(|id| { + if let Ok(n) = id.parse::() { json!(n) } else { json!(id) } + }).collect(); + acct_obj["allowFrom"] = json!(allow_vals); + } + } else { + // Auto-inherit from primary bot if no explicit allow_from provided + let primary_id = load_manager_config() + .unwrap_or(json!({})) + .pointer("/primaryBotAccount") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()); + if let Some(pid) = primary_id { + if pid != account.id { + // Read primary account's allowFrom + if let Some(primary_allow) = config.pointer(&format!("/channels/telegram/accounts/{}/allowFrom", pid)) + .and_then(|v| v.as_array()) { + if !primary_allow.is_empty() && primary_allow.iter().any(|v| v.as_str() != Some("*")) { + acct_obj["allowFrom"] = json!(primary_allow); + } + } + } + } } } if let Some(sm) = &account.stream_mode { diff --git a/src/components/Channels/index.tsx b/src/components/Channels/index.tsx index 42e6be9..660c7bc 100644 --- a/src/components/Channels/index.tsx +++ b/src/components/Channels/index.tsx @@ -252,6 +252,7 @@ export function Channels() { exclusive_topics?: string[]; groups?: Record; primary?: boolean; + allow_from?: string[]; } const [telegramAccounts, setTelegramAccounts] = useState([]); const [showAddAccountDialog, setShowAddAccountDialog] = useState(false); @@ -1350,6 +1351,69 @@ export function Channels() { ); })()} + {/* Per-account DM Allowed Users */} + {(acct.dm_policy === 'pairing' || acct.dm_policy === 'allowlist') && (() => { + const dmUsers = acct.allow_from || []; + const updateDmUsers = (newList: string[]) => { + const updated = telegramAccounts.map(a => a.id === acct.id ? { ...a, allow_from: newList } : a); + setTelegramAccounts(updated); + }; + return ( +
+ +
+ { + if (e.key === 'Enter') { + const val = (e.target as HTMLInputElement).value.trim(); + if (val && !dmUsers.includes(val)) { + updateDmUsers([...dmUsers, val]); + (e.target as HTMLInputElement).value = ''; + } + } + }} + /> + +
+
+ {dmUsers.map(id => ( +
+ {id} + +
+ ))} + {dmUsers.length === 0 && ( +

+ {acct.dm_policy === 'pairing' ? 'Users added via pairing flow. You can also add manually.' : 'No users allowed. Add user IDs above.'} +

+ )} +
+

Saved per-account as allowFrom. Inherited from primary bot if empty.

+
+ ); + })()} +
{ if (newAccountId && newAccountToken) { - await handleSaveAccount({ id: newAccountId, bot_token: newAccountToken }); + // Pre-populate allow_from from primary bot + const primaryBot = telegramAccounts.find(a => a.primary); + const inheritedAllowFrom = primaryBot?.allow_from?.filter(id => id !== '*'); + await handleSaveAccount({ id: newAccountId, bot_token: newAccountToken, allow_from: inheritedAllowFrom && inheritedAllowFrom.length > 0 ? inheritedAllowFrom : undefined }); setNewAccountId(''); setNewAccountToken(''); setShowAddAccountDialog(false);