mirror of
https://github.com/coral/sipcord-bridge.git
synced 2026-06-29 09:23:14 -06:00
auto nickname based on phone call
This commit is contained in:
parent
c5ce9d7dac
commit
025d5ffd88
|
|
@ -47,7 +47,9 @@ Use this URL format, replacing `YOUR_CLIENT_ID`:
|
|||
```
|
||||
https://discord.com/oauth2/authorize?client_id=YOUR_CLIENT_ID&scope=bot&permissions=36700160
|
||||
```
|
||||
The bot needs Connect + Speak permissions in voice channels.
|
||||
The bot needs Connect + Speak permissions in voice channels. If you want the
|
||||
bot nickname to change to the phone/person being called, also grant Change
|
||||
Nickname.
|
||||
|
||||
### 2. Get Discord channel IDs
|
||||
|
||||
|
|
@ -263,6 +265,9 @@ Behavior:
|
|||
command was run.
|
||||
- `/directory` opens the configured phone directory as Discord buttons. Clicking
|
||||
a phone button behaves like `/call` for that extension.
|
||||
- When a Discord-originated call starts, the bot tries to set its server
|
||||
nickname to the matching phone directory label. If the extension is not in the
|
||||
directory, it uses the dialed extension.
|
||||
|
||||
Current scope:
|
||||
- `/call` is implemented for the static self-host backend.
|
||||
|
|
|
|||
|
|
@ -678,10 +678,13 @@ async fn handle_call_command(
|
|||
Ok(req) => {
|
||||
let extension = req.discord_username.clone();
|
||||
match cfg.request_tx.send(req) {
|
||||
Ok(()) => format!(
|
||||
Ok(()) => {
|
||||
set_call_nickname_for_extension(command.guild_id, cfg, &extension).await;
|
||||
format!(
|
||||
"Dialing extension `{}` from your current voice channel.",
|
||||
extension
|
||||
),
|
||||
)
|
||||
}
|
||||
Err(_) => "Outbound call queue is unavailable right now.".to_string(),
|
||||
}
|
||||
}
|
||||
|
|
@ -793,10 +796,13 @@ async fn handle_directory_button(
|
|||
"/directory",
|
||||
) {
|
||||
Ok(req) => match cfg.request_tx.send(req) {
|
||||
Ok(()) => format!(
|
||||
Ok(()) => {
|
||||
set_call_nickname(component.guild_id, cfg, &entry.label).await;
|
||||
format!(
|
||||
"Dialing `{}` (`{}`) from your current voice channel.",
|
||||
entry.label, entry.extension
|
||||
),
|
||||
)
|
||||
}
|
||||
Err(_) => "Outbound call queue is unavailable right now.".to_string(),
|
||||
},
|
||||
Err(msg) => msg,
|
||||
|
|
@ -805,6 +811,76 @@ async fn handle_directory_button(
|
|||
respond_to_component(ctx, component, &response).await;
|
||||
}
|
||||
|
||||
async fn set_call_nickname_for_extension(
|
||||
guild_id: Option<GuildId>,
|
||||
cfg: &DiscordOutboundCallConfig,
|
||||
extension: &str,
|
||||
) {
|
||||
let display_name = cfg
|
||||
.phone_directory
|
||||
.iter()
|
||||
.find(|entry| entry.extension == extension)
|
||||
.map(|entry| entry.label.as_str())
|
||||
.unwrap_or(extension);
|
||||
|
||||
set_call_nickname(guild_id, cfg, display_name).await;
|
||||
}
|
||||
|
||||
async fn set_call_nickname(
|
||||
guild_id: Option<GuildId>,
|
||||
cfg: &DiscordOutboundCallConfig,
|
||||
display_name: &str,
|
||||
) {
|
||||
let Some(guild_id) = guild_id else {
|
||||
return;
|
||||
};
|
||||
|
||||
let nickname = call_nickname(display_name);
|
||||
let url = format!(
|
||||
"https://discord.com/api/v10/guilds/{}/members/@me",
|
||||
guild_id.get()
|
||||
);
|
||||
|
||||
let result = reqwest::Client::new()
|
||||
.patch(url)
|
||||
.header("Authorization", format!("Bot {}", cfg.bot_token))
|
||||
.json(&serde_json::json!({ "nick": nickname }))
|
||||
.send()
|
||||
.await;
|
||||
|
||||
match result {
|
||||
Ok(response) if response.status().is_success() => {
|
||||
debug!(
|
||||
"Set bot nickname in guild {} while calling {}",
|
||||
guild_id, display_name
|
||||
);
|
||||
}
|
||||
Ok(response) => {
|
||||
warn!(
|
||||
"Failed to set bot nickname in guild {}: HTTP {}",
|
||||
guild_id,
|
||||
response.status()
|
||||
);
|
||||
}
|
||||
Err(e) => {
|
||||
warn!("Failed to set bot nickname in guild {}: {}", guild_id, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn call_nickname(display_name: &str) -> String {
|
||||
const MAX_NICKNAME_CHARS: usize = 32;
|
||||
let trimmed = display_name.trim();
|
||||
let name = if trimmed.is_empty() { "Unknown" } else { trimmed };
|
||||
if name.chars().count() <= MAX_NICKNAME_CHARS {
|
||||
return name.to_string();
|
||||
}
|
||||
|
||||
let mut out: String = name.chars().take(MAX_NICKNAME_CHARS - 3).collect();
|
||||
out.push_str("...");
|
||||
out
|
||||
}
|
||||
|
||||
fn build_directory_response(entries: &[PhoneDirectoryEntry]) -> CreateInteractionResponseMessage {
|
||||
let visible_entries: Vec<&PhoneDirectoryEntry> = entries
|
||||
.iter()
|
||||
|
|
@ -941,10 +1017,9 @@ fn build_hangup_request(
|
|||
let requested_by = command
|
||||
.member
|
||||
.as_ref()
|
||||
.and_then(|member| member.nick.clone())
|
||||
.or_else(|| command.user.global_name.clone())
|
||||
.unwrap_or_else(|| command.user.name.clone())
|
||||
.to_string();
|
||||
.and_then(|member| member.nick.as_ref().map(ToString::to_string))
|
||||
.or_else(|| command.user.global_name.as_ref().map(ToString::to_string))
|
||||
.unwrap_or_else(|| command.user.name.to_string());
|
||||
|
||||
Ok(HangupCallRequest {
|
||||
request_id: format!("hangup-{}", command.id),
|
||||
|
|
|
|||
Loading…
Reference in a new issue