Skip to content

Commit eccc3db

Browse files
committed
fix(desktop): add missing Tauri commands for delete/update server, invites, leave, transfer
1 parent 460729f commit eccc3db

2 files changed

Lines changed: 216 additions & 0 deletions

File tree

crates/nexus-desktop/src-tauri/src/commands/servers.rs

Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,3 +262,212 @@ pub async fn delete_role(
262262
}
263263
Ok(())
264264
}
265+
266+
// ─── Server management commands ─────────────────────────────────────────────
267+
268+
/// Update server settings (name, description, public flag, etc.).
269+
#[tauri::command]
270+
pub async fn update_server(
271+
state: State<'_, AppState>,
272+
server_id: Uuid,
273+
name: Option<String>,
274+
description: Option<String>,
275+
is_public: Option<bool>,
276+
region: Option<String>,
277+
require_2fa: Option<bool>,
278+
spam_window_secs: Option<i32>,
279+
spam_max_messages: Option<i32>,
280+
) -> Result<ServerClient, String> {
281+
let session = state.session_snapshot();
282+
let (client, base) = api_client(&session).map_err(|e| e.to_string())?;
283+
let body = serde_json::json!({
284+
"name": name,
285+
"description": description,
286+
"is_public": is_public,
287+
"region": region,
288+
"require_2fa": require_2fa,
289+
"spam_window_secs": spam_window_secs,
290+
"spam_max_messages": spam_max_messages,
291+
});
292+
let resp = client
293+
.patch(format!("{base}/api/v1/servers/{server_id}"))
294+
.json(&body)
295+
.send()
296+
.await
297+
.map_err(|e| e.to_string())?;
298+
if !resp.status().is_success() {
299+
let text = resp.text().await.unwrap_or_default();
300+
return Err(text);
301+
}
302+
let raw: RawServer = resp.json().await.map_err(|e| e.to_string())?;
303+
Ok(ServerClient::from(raw))
304+
}
305+
306+
/// Delete a server permanently.
307+
#[tauri::command]
308+
pub async fn delete_server(
309+
state: State<'_, AppState>,
310+
server_id: Uuid,
311+
) -> Result<(), String> {
312+
let session = state.session_snapshot();
313+
let (client, base) = api_client(&session).map_err(|e| e.to_string())?;
314+
let resp = client
315+
.delete(format!("{base}/api/v1/servers/{server_id}"))
316+
.send()
317+
.await
318+
.map_err(|e| e.to_string())?;
319+
if !resp.status().is_success() {
320+
let text = resp.text().await.unwrap_or_default();
321+
return Err(text);
322+
}
323+
Ok(())
324+
}
325+
326+
/// Transfer server ownership to another member.
327+
#[tauri::command]
328+
pub async fn transfer_server_ownership(
329+
state: State<'_, AppState>,
330+
server_id: Uuid,
331+
new_owner_id: String,
332+
) -> Result<(), String> {
333+
let session = state.session_snapshot();
334+
let (client, base) = api_client(&session).map_err(|e| e.to_string())?;
335+
let body = serde_json::json!({ "new_owner_id": new_owner_id });
336+
let resp = client
337+
.post(format!("{base}/api/v1/servers/{server_id}/transfer-ownership"))
338+
.json(&body)
339+
.send()
340+
.await
341+
.map_err(|e| e.to_string())?;
342+
if !resp.status().is_success() {
343+
let text = resp.text().await.unwrap_or_default();
344+
return Err(text);
345+
}
346+
Ok(())
347+
}
348+
349+
/// Leave a server (non-owner members only).
350+
#[tauri::command]
351+
pub async fn leave_server(
352+
state: State<'_, AppState>,
353+
server_id: Uuid,
354+
) -> Result<(), String> {
355+
let session = state.session_snapshot();
356+
let (client, base) = api_client(&session).map_err(|e| e.to_string())?;
357+
let resp = client
358+
.post(format!("{base}/api/v1/servers/{server_id}/leave"))
359+
.send()
360+
.await
361+
.map_err(|e| e.to_string())?;
362+
if !resp.status().is_success() {
363+
let text = resp.text().await.unwrap_or_default();
364+
return Err(text);
365+
}
366+
Ok(())
367+
}
368+
369+
// ─── Invite commands ─────────────────────────────────────────────────────────
370+
371+
#[derive(Serialize, Debug, Clone)]
372+
#[serde(rename_all = "camelCase")]
373+
pub struct InviteClient {
374+
pub code: String,
375+
pub server_id: String,
376+
pub max_uses: Option<i64>,
377+
pub uses: i64,
378+
pub expires_at: Option<String>,
379+
pub created_at: String,
380+
}
381+
382+
#[derive(Deserialize, Debug, Clone)]
383+
struct RawInvite {
384+
pub code: String,
385+
pub server_id: serde_json::Value,
386+
pub max_uses: Option<i64>,
387+
pub uses: i64,
388+
pub expires_at: Option<String>,
389+
pub created_at: String,
390+
}
391+
392+
impl From<RawInvite> for InviteClient {
393+
fn from(r: RawInvite) -> Self {
394+
Self {
395+
code: r.code,
396+
server_id: r.server_id.to_string().trim_matches('"').to_string(),
397+
max_uses: r.max_uses,
398+
uses: r.uses,
399+
expires_at: r.expires_at,
400+
created_at: r.created_at,
401+
}
402+
}
403+
}
404+
405+
/// List all active invites for a server.
406+
#[tauri::command]
407+
pub async fn list_server_invites(
408+
state: State<'_, AppState>,
409+
server_id: Uuid,
410+
) -> Result<Vec<InviteClient>, String> {
411+
let session = state.session_snapshot();
412+
let (client, base) = api_client(&session).map_err(|e| e.to_string())?;
413+
let resp = client
414+
.get(format!("{base}/api/v1/servers/{server_id}/invites"))
415+
.send()
416+
.await
417+
.map_err(|e| e.to_string())?;
418+
if !resp.status().is_success() {
419+
let text = resp.text().await.unwrap_or_default();
420+
return Err(text);
421+
}
422+
let raw: Vec<RawInvite> = resp.json().await.map_err(|e| e.to_string())?;
423+
Ok(raw.into_iter().map(InviteClient::from).collect())
424+
}
425+
426+
/// Create a new invite for a server.
427+
#[tauri::command]
428+
pub async fn create_invite(
429+
state: State<'_, AppState>,
430+
server_id: Uuid,
431+
max_uses: Option<i64>,
432+
max_age_secs: Option<i64>,
433+
) -> Result<InviteClient, String> {
434+
let session = state.session_snapshot();
435+
let (client, base) = api_client(&session).map_err(|e| e.to_string())?;
436+
let body = serde_json::json!({
437+
"max_uses": max_uses,
438+
"max_age_secs": max_age_secs,
439+
});
440+
let resp = client
441+
.post(format!("{base}/api/v1/servers/{server_id}/invites"))
442+
.json(&body)
443+
.send()
444+
.await
445+
.map_err(|e| e.to_string())?;
446+
if !resp.status().is_success() {
447+
let text = resp.text().await.unwrap_or_default();
448+
return Err(text);
449+
}
450+
let raw: RawInvite = resp.json().await.map_err(|e| e.to_string())?;
451+
Ok(InviteClient::from(raw))
452+
}
453+
454+
/// Delete (revoke) a server invite by code.
455+
#[tauri::command]
456+
pub async fn delete_invite(
457+
state: State<'_, AppState>,
458+
server_id: Uuid,
459+
code: String,
460+
) -> Result<(), String> {
461+
let session = state.session_snapshot();
462+
let (client, base) = api_client(&session).map_err(|e| e.to_string())?;
463+
let resp = client
464+
.delete(format!("{base}/api/v1/servers/{server_id}/invites/{code}"))
465+
.send()
466+
.await
467+
.map_err(|e| e.to_string())?;
468+
if !resp.status().is_success() {
469+
let text = resp.text().await.unwrap_or_default();
470+
return Err(text);
471+
}
472+
Ok(())
473+
}

crates/nexus-desktop/src-tauri/src/lib.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,17 @@ pub fn run() {
6464
commands::servers::list_servers,
6565
commands::servers::get_server,
6666
commands::servers::create_server,
67+
commands::servers::update_server,
68+
commands::servers::delete_server,
69+
commands::servers::transfer_server_ownership,
70+
commands::servers::leave_server,
6771
commands::servers::list_roles,
6872
commands::servers::create_role,
6973
commands::servers::update_role,
7074
commands::servers::delete_role,
75+
commands::servers::list_server_invites,
76+
commands::servers::create_invite,
77+
commands::servers::delete_invite,
7178
// Emoji management
7279
commands::emojis::list_emoji,
7380
commands::emojis::upload_emoji,

0 commit comments

Comments
 (0)