feat: add /mod summon
This commit is contained in:
parent
864cfaec54
commit
45a7e44b3a
11 changed files with 598 additions and 5 deletions
|
|
@ -18,8 +18,8 @@ use tokio::sync::{broadcast, mpsc};
|
|||
use uuid::Uuid;
|
||||
|
||||
use chattyness_db::{
|
||||
models::{AvatarRenderData, ChannelMemberWithAvatar, EmotionState, User},
|
||||
queries::{avatars, channel_members, loose_props, realms, scenes},
|
||||
models::{ActionType, AvatarRenderData, ChannelMemberWithAvatar, EmotionState, User},
|
||||
queries::{avatars, channel_members, loose_props, memberships, moderation, realms, scenes},
|
||||
ws_messages::{close_codes, ClientMessage, DisconnectReason, ServerMessage, WsConfig},
|
||||
};
|
||||
use chattyness_error::AppError;
|
||||
|
|
@ -828,6 +828,169 @@ async fn handle_socket(
|
|||
scene_slug: scene.slug,
|
||||
}).await;
|
||||
}
|
||||
ClientMessage::ModCommand { subcommand, args } => {
|
||||
// Check if user is a moderator
|
||||
let is_mod = match memberships::is_moderator(&pool, user_id, realm_id).await {
|
||||
Ok(result) => result,
|
||||
Err(e) => {
|
||||
tracing::error!("[WS] Failed to check moderator status: {:?}", e);
|
||||
false
|
||||
}
|
||||
};
|
||||
|
||||
if !is_mod {
|
||||
let _ = direct_tx.send(ServerMessage::ModCommandResult {
|
||||
success: false,
|
||||
message: "You do not have moderator permissions".to_string(),
|
||||
}).await;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get moderator's current scene info and display name
|
||||
let mod_member = match channel_members::get_channel_member(
|
||||
&mut *recv_conn,
|
||||
channel_id,
|
||||
user_id,
|
||||
realm_id,
|
||||
).await {
|
||||
Ok(Some(m)) => m,
|
||||
Ok(None) | Err(_) => {
|
||||
let _ = direct_tx.send(ServerMessage::ModCommandResult {
|
||||
success: false,
|
||||
message: "Failed to get moderator info".to_string(),
|
||||
}).await;
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
// Get moderator's current scene details
|
||||
let mod_scene = match scenes::get_scene_by_id(&pool, channel_id).await {
|
||||
Ok(Some(s)) => s,
|
||||
Ok(None) | Err(_) => {
|
||||
let _ = direct_tx.send(ServerMessage::ModCommandResult {
|
||||
success: false,
|
||||
message: "Failed to get scene info".to_string(),
|
||||
}).await;
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
match subcommand.as_str() {
|
||||
"summon" => {
|
||||
if args.is_empty() {
|
||||
let _ = direct_tx.send(ServerMessage::ModCommandResult {
|
||||
success: false,
|
||||
message: "Usage: /mod summon [nick|*]".to_string(),
|
||||
}).await;
|
||||
continue;
|
||||
}
|
||||
|
||||
let target = &args[0];
|
||||
|
||||
if target == "*" {
|
||||
// Summon all users in the realm
|
||||
let mut summoned_count = 0;
|
||||
let mut target_ids = Vec::new();
|
||||
|
||||
// Iterate all connected users in this realm
|
||||
for entry in ws_state.users.iter() {
|
||||
let (target_user_id, target_conn) = entry.pair();
|
||||
if target_conn.realm_id == realm_id && *target_user_id != user_id {
|
||||
// Send Summoned message to each user
|
||||
let summon_msg = ServerMessage::Summoned {
|
||||
scene_id: mod_scene.id,
|
||||
scene_slug: mod_scene.slug.clone(),
|
||||
summoned_by: mod_member.display_name.clone(),
|
||||
};
|
||||
if target_conn.direct_tx.send(summon_msg).await.is_ok() {
|
||||
summoned_count += 1;
|
||||
target_ids.push(*target_user_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Log the action
|
||||
let metadata = serde_json::json!({
|
||||
"scene_id": mod_scene.id,
|
||||
"scene_slug": mod_scene.slug,
|
||||
"summoned_count": summoned_count,
|
||||
});
|
||||
let _ = moderation::log_moderation_action(
|
||||
&pool,
|
||||
realm_id,
|
||||
user_id,
|
||||
ActionType::SummonAll,
|
||||
None,
|
||||
&format!("Summoned {} users to scene {}", summoned_count, mod_scene.name),
|
||||
metadata,
|
||||
).await;
|
||||
|
||||
let _ = direct_tx.send(ServerMessage::ModCommandResult {
|
||||
success: true,
|
||||
message: format!("Summoned {} users to {}", summoned_count, mod_scene.name),
|
||||
}).await;
|
||||
} else {
|
||||
// Summon specific user by display name
|
||||
if let Some((target_user_id, target_conn)) = ws_state
|
||||
.find_user_by_display_name(realm_id, target)
|
||||
{
|
||||
if target_user_id == user_id {
|
||||
let _ = direct_tx.send(ServerMessage::ModCommandResult {
|
||||
success: false,
|
||||
message: "You cannot summon yourself".to_string(),
|
||||
}).await;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Send Summoned message to target
|
||||
let summon_msg = ServerMessage::Summoned {
|
||||
scene_id: mod_scene.id,
|
||||
scene_slug: mod_scene.slug.clone(),
|
||||
summoned_by: mod_member.display_name.clone(),
|
||||
};
|
||||
if target_conn.direct_tx.send(summon_msg).await.is_ok() {
|
||||
// Log the action
|
||||
let metadata = serde_json::json!({
|
||||
"scene_id": mod_scene.id,
|
||||
"scene_slug": mod_scene.slug,
|
||||
"target_display_name": target,
|
||||
});
|
||||
let _ = moderation::log_moderation_action(
|
||||
&pool,
|
||||
realm_id,
|
||||
user_id,
|
||||
ActionType::Summon,
|
||||
Some(target_user_id),
|
||||
&format!("Summoned {} to scene {}", target, mod_scene.name),
|
||||
metadata,
|
||||
).await;
|
||||
|
||||
let _ = direct_tx.send(ServerMessage::ModCommandResult {
|
||||
success: true,
|
||||
message: format!("Summoned {} to {}", target, mod_scene.name),
|
||||
}).await;
|
||||
} else {
|
||||
let _ = direct_tx.send(ServerMessage::ModCommandResult {
|
||||
success: false,
|
||||
message: format!("Failed to send summon to {}", target),
|
||||
}).await;
|
||||
}
|
||||
} else {
|
||||
let _ = direct_tx.send(ServerMessage::ModCommandResult {
|
||||
success: false,
|
||||
message: format!("User '{}' is not online in this realm", target),
|
||||
}).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
let _ = direct_tx.send(ServerMessage::ModCommandResult {
|
||||
success: false,
|
||||
message: format!("Unknown mod command: {}", subcommand),
|
||||
}).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Message::Close(close_frame) => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue