Server integrations / Paper and protocol tests (push) Failing after 20s
Server integrations / fabric / 1.20.1 (push) Failing after 11s
Server integrations / fabric / 1.21.1 (push) Failing after 14s
Server integrations / fabric / 26.1.2 (push) Failing after 17s
Server integrations / fabric / 26.2 (push) Failing after 12s
Server integrations / fabric / 26.3 (push) Failing after 6s
Server integrations / forge / 1.20.1 (push) Failing after 6s
Server integrations / forge / 1.21.1 (push) Failing after 8s
Server integrations / forge / 26.1.2 (push) Failing after 8s
Server integrations / forge / 26.2 (push) Failing after 8s
Server integrations / forge / 26.3 (push) Failing after 7s
CI / Web UIs (type-check + build) (panel/web) (push) Canceled after 0s
CI / Launcher (Windows build check) (push) Canceled after 2m53s
CI / Real installs (Mojang, Fabric, Quilt, Forge, NeoForge) (push) Canceled after 0s
CI / Docker image builds (push) Canceled after 0s
CI / Rust (fmt, clippy, tests) (push) Canceled after 1m22s
CI / Web UIs (type-check + build) (launcher) (push) Canceled after 1m27s
69 lines
3.9 KiB
Rust
69 lines
3.9 KiB
Rust
mod common;
|
|
use common::*;
|
|
|
|
#[tokio::test]
|
|
async fn discord_messages_are_customised_and_previewed_with_real_data() {
|
|
let t = setup().await;
|
|
let admin = t.login("admin", "supersecret").await;
|
|
let (s, all) = t.call("GET", "/api/admin/discord/studio", Some(&admin), None).await;
|
|
assert_eq!(s, StatusCode::OK, "{all}");
|
|
assert_eq!(all["templates"].as_object().unwrap().len(), 3);
|
|
assert_eq!(all["live"].as_object().unwrap().len(), 4);
|
|
assert!(all["placeholders"]["achievement"].as_array().unwrap().iter().any(|p| p == "achievement_description"));
|
|
|
|
// Edit the achievement message; bad image addresses are refused.
|
|
let mut tpl = all["templates"].clone();
|
|
tpl["achievement"]["title"] = json!("🎉 {player} did it!");
|
|
tpl["achievement"]["image"] = json!("javascript:evil");
|
|
let (s, _) = t.call("PUT", "/api/admin/discord/studio/templates", Some(&admin), Some(json!({"templates": tpl}))).await;
|
|
assert_eq!(s, StatusCode::BAD_REQUEST);
|
|
tpl["achievement"]["image"] = json!("https://cdn.example.com/banner.png");
|
|
let (s, _) = t.call("PUT", "/api/admin/discord/studio/templates", Some(&admin), Some(json!({"templates": tpl.clone()}))).await;
|
|
assert_eq!(s, StatusCode::OK);
|
|
let (s, p) = t
|
|
.call("POST", "/api/admin/discord/studio/preview", Some(&admin), Some(json!({"kind": "achievement", "style": tpl["achievement"]})))
|
|
.await;
|
|
assert_eq!(s, StatusCode::OK, "{p}");
|
|
let e = &p["embeds"][0];
|
|
assert_eq!(e["title"], "🎉 admin did it!");
|
|
assert_eq!(e["image"]["url"], "https://cdn.example.com/banner.png");
|
|
assert!(e["description"].as_str().unwrap().contains("Deep Diver"));
|
|
assert_eq!(e["fields"][0]["name"], "Reward");
|
|
|
|
// Live embeds show real data: a server, a guild and a rich player.
|
|
t.call("POST", "/api/admin/users", Some(&admin), Some(json!({"username": "Steve", "password": "password123"}))).await;
|
|
let steve_token = t.login("Steve", "password123").await;
|
|
let (_, srv) = t.call("POST", "/api/admin/servers", Some(&admin), Some(json!({"name": "Survival SMP", "instance_id": "smp"}))).await;
|
|
let sid = srv["server"]["id"].as_i64().unwrap();
|
|
t.call("POST", "/api/v1/guilds", Some(&steve_token), Some(json!({"instance_id": "smp", "name": "Iron Wolves", "tag": "IRON"}))).await;
|
|
sqlx::query("INSERT INTO server_economy (server_id, uuid, username, balance, updated_at) VALUES (?, ?, 'Steve', 123456, 'now')")
|
|
.bind(sid)
|
|
.bind(t.uuid("Steve").await)
|
|
.execute(&t.db)
|
|
.await
|
|
.unwrap();
|
|
for (kind, needle) in [("status", "Survival SMP"), ("guilds", "Iron Wolves"), ("baltop", "$123,456"), ("leaderboard", "Leaderboard")] {
|
|
let cfg = all["live"][kind].clone();
|
|
let (s, p) = t.call("POST", "/api/admin/discord/studio/preview", Some(&admin), Some(json!({"kind": kind, "live": cfg}))).await;
|
|
assert_eq!(s, StatusCode::OK, "{kind}: {p}");
|
|
assert!(p.to_string().contains(needle), "{kind} should mention {needle}: {p}");
|
|
}
|
|
|
|
// Interval and row limits are clamped; the webhook is write-only.
|
|
let mut live = all["live"].clone();
|
|
live["status"]["interval_secs"] = json!(5);
|
|
live["status"]["limit"] = json!(500);
|
|
live["status"]["webhook_url"] = json!("https://evil.example.com/hook");
|
|
assert_eq!(
|
|
t.call("PUT", "/api/admin/discord/studio/live", Some(&admin), Some(json!({"live": live.clone()}))).await.0,
|
|
StatusCode::BAD_REQUEST
|
|
);
|
|
live["status"]["webhook_url"] = json!("https://discord.com/api/webhooks/1/abc");
|
|
assert_eq!(t.call("PUT", "/api/admin/discord/studio/live", Some(&admin), Some(json!({"live": live}))).await.0, StatusCode::OK);
|
|
let (_, again) = t.call("GET", "/api/admin/discord/studio", Some(&admin), None).await;
|
|
assert_eq!(again["live"]["status"]["interval_secs"], 60);
|
|
assert_eq!(again["live"]["status"]["limit"], 25);
|
|
assert_eq!(again["live"]["status"]["webhook_set"], true);
|
|
assert_eq!(again["live"]["status"]["webhook_url"], "");
|
|
}
|