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
|
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
|
### 2. Get Discord channel IDs
|
||||||
|
|
||||||
|
|
@ -263,6 +265,9 @@ Behavior:
|
||||||
command was run.
|
command was run.
|
||||||
- `/directory` opens the configured phone directory as Discord buttons. Clicking
|
- `/directory` opens the configured phone directory as Discord buttons. Clicking
|
||||||
a phone button behaves like `/call` for that extension.
|
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:
|
Current scope:
|
||||||
- `/call` is implemented for the static self-host backend.
|
- `/call` is implemented for the static self-host backend.
|
||||||
|
|
|
||||||
|
|
@ -678,10 +678,13 @@ async fn handle_call_command(
|
||||||
Ok(req) => {
|
Ok(req) => {
|
||||||
let extension = req.discord_username.clone();
|
let extension = req.discord_username.clone();
|
||||||
match cfg.request_tx.send(req) {
|
match cfg.request_tx.send(req) {
|
||||||
Ok(()) => format!(
|
Ok(()) => {
|
||||||
"Dialing extension `{}` from your current voice channel.",
|
set_call_nickname_for_extension(command.guild_id, cfg, &extension).await;
|
||||||
extension
|
format!(
|
||||||
),
|
"Dialing extension `{}` from your current voice channel.",
|
||||||
|
extension
|
||||||
|
)
|
||||||
|
}
|
||||||
Err(_) => "Outbound call queue is unavailable right now.".to_string(),
|
Err(_) => "Outbound call queue is unavailable right now.".to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -793,10 +796,13 @@ async fn handle_directory_button(
|
||||||
"/directory",
|
"/directory",
|
||||||
) {
|
) {
|
||||||
Ok(req) => match cfg.request_tx.send(req) {
|
Ok(req) => match cfg.request_tx.send(req) {
|
||||||
Ok(()) => format!(
|
Ok(()) => {
|
||||||
"Dialing `{}` (`{}`) from your current voice channel.",
|
set_call_nickname(component.guild_id, cfg, &entry.label).await;
|
||||||
entry.label, entry.extension
|
format!(
|
||||||
),
|
"Dialing `{}` (`{}`) from your current voice channel.",
|
||||||
|
entry.label, entry.extension
|
||||||
|
)
|
||||||
|
}
|
||||||
Err(_) => "Outbound call queue is unavailable right now.".to_string(),
|
Err(_) => "Outbound call queue is unavailable right now.".to_string(),
|
||||||
},
|
},
|
||||||
Err(msg) => msg,
|
Err(msg) => msg,
|
||||||
|
|
@ -805,6 +811,76 @@ async fn handle_directory_button(
|
||||||
respond_to_component(ctx, component, &response).await;
|
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 {
|
fn build_directory_response(entries: &[PhoneDirectoryEntry]) -> CreateInteractionResponseMessage {
|
||||||
let visible_entries: Vec<&PhoneDirectoryEntry> = entries
|
let visible_entries: Vec<&PhoneDirectoryEntry> = entries
|
||||||
.iter()
|
.iter()
|
||||||
|
|
@ -941,10 +1017,9 @@ fn build_hangup_request(
|
||||||
let requested_by = command
|
let requested_by = command
|
||||||
.member
|
.member
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|member| member.nick.clone())
|
.and_then(|member| member.nick.as_ref().map(ToString::to_string))
|
||||||
.or_else(|| command.user.global_name.clone())
|
.or_else(|| command.user.global_name.as_ref().map(ToString::to_string))
|
||||||
.unwrap_or_else(|| command.user.name.clone())
|
.unwrap_or_else(|| command.user.name.to_string());
|
||||||
.to_string();
|
|
||||||
|
|
||||||
Ok(HangupCallRequest {
|
Ok(HangupCallRequest {
|
||||||
request_id: format!("hangup-{}", command.id),
|
request_id: format!("hangup-{}", command.id),
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue