Rework BlueMap claiming and expand ranks guilds chat and warps
This commit is contained in:
1 parent
434ed5338a
commit
6a2944a88e
68 files changed
+1453
-2500
No files matched your search
@@ -39,9 +39,6 @@ pub async fn setup_with(tweak: impl FnOnce(&mut Config, &std::path::Path)) -> Te
|
||||
max_upload_mb: 64,
|
||||
public_url: Some("https://panel.test".into()),
|
||||
trusted_proxies: vec!["127.0.0.1".parse().unwrap()],
|
||||
vantage_bin: None,
|
||||
vantage_assets: None,
|
||||
vantage_args: vec![],
|
||||
};
|
||||
tweak(&mut cfg, dir.path());
|
||||
let pool = db::connect_memory().await.unwrap();
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
mod common;
|
||||
use common::*;
|
||||
|
||||
#[tokio::test]
|
||||
async fn leader_approves_join_request_and_role_controls_claims() {
|
||||
let t = setup().await;
|
||||
let admin = t.login("admin", "supersecret").await;
|
||||
for name in ["Leader", "Applicant"] {
|
||||
let (status, body) = t.call("POST", "/api/admin/users", Some(&admin), Some(json!({"username":name,"password":"password123"}))).await;
|
||||
assert_eq!(status, StatusCode::OK, "{body}");
|
||||
}
|
||||
let leader = t.login("Leader", "password123").await;
|
||||
let applicant = t.login("Applicant", "password123").await;
|
||||
let applicant_uuid = t.uuid("Applicant").await;
|
||||
let (_, server) = t.call("POST", "/api/admin/servers", Some(&admin), Some(json!({"name":"SMP","instance_id":"smp"}))).await;
|
||||
let server_id = server["server"]["id"].as_i64().unwrap();
|
||||
let (status, guild) = t.call("POST", "/api/v1/guilds", Some(&leader), Some(json!({"instance_id":"smp","name":"Pimps","tag":"PIMP"}))).await;
|
||||
assert_eq!(status, StatusCode::OK, "{guild}");
|
||||
let id = guild["id"].as_str().unwrap();
|
||||
let path = format!("/api/v1/guilds/{id}");
|
||||
|
||||
assert_eq!(t.call("POST", &format!("{path}/requests"), Some(&applicant), Some(json!({"message":"Let me in"}))).await.0, StatusCode::OK);
|
||||
assert_eq!(t.call("GET", &format!("{path}/requests"), Some(&applicant), None).await.0, StatusCode::FORBIDDEN);
|
||||
let (_, requests) = t.call("GET", &format!("{path}/requests"), Some(&leader), None).await;
|
||||
assert_eq!(requests[0]["message"], "Let me in");
|
||||
assert_eq!(t.call("POST", &format!("{path}/requests/{applicant_uuid}/respond"), Some(&leader), Some(json!({"accept":true}))).await.0, StatusCode::OK);
|
||||
|
||||
let (status, role) = t.call("POST", &format!("{path}/roles"), Some(&leader), Some(json!({"name":"Builder","can_claim":false,"can_post":true}))).await;
|
||||
assert_eq!(status, StatusCode::OK, "{role}");
|
||||
assert_eq!(t.call("PUT", &format!("{path}/members/{applicant_uuid}/role"), Some(&leader), Some(json!({"role":"Builder"}))).await.0, StatusCode::OK);
|
||||
let claim = json!({"server_id":server_id,"dimension":"minecraft:overworld","chunk_x":1,"chunk_z":1});
|
||||
assert_eq!(t.call("POST", &format!("{path}/claim"), Some(&applicant), Some(claim)).await.0, StatusCode::FORBIDDEN);
|
||||
let role_id = role["id"].as_i64().unwrap();
|
||||
assert_eq!(t.call("DELETE", &format!("{path}/roles/{role_id}"), Some(&leader), None).await.0, StatusCode::OK);
|
||||
let (_, members) = t.call("GET", &format!("{path}/members"), Some(&leader), None).await;
|
||||
assert_eq!(members.as_array().unwrap().iter().find(|m| m["uuid"] == applicant_uuid).unwrap()["role"], "member");
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
//! Central live map: ingest from game servers, status for admins, viewer proxy.
|
||||
//! Live position and world-mirror ingest from game servers.
|
||||
|
||||
mod common;
|
||||
use common::*;
|
||||
@@ -20,7 +20,7 @@ async fn post_bytes(t: &TestApp, uri: &str, token: &str, body: Vec<u8>) -> (Stat
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn live_map_ingest_status_and_proxy() {
|
||||
async fn live_map_ingest_and_player_positions() {
|
||||
let t = setup().await;
|
||||
let admin = t.login("admin", "supersecret").await;
|
||||
let (_, v) = t.call("POST", "/api/admin/servers", Some(&admin), Some(json!({"name": "Survival"}))).await;
|
||||
@@ -82,29 +82,12 @@ async fn live_map_ingest_status_and_proxy() {
|
||||
assert_eq!(s, StatusCode::OK);
|
||||
assert_eq!(info["enabled"], true);
|
||||
assert_eq!(info["players"], 1);
|
||||
assert_eq!(info["base"], format!("/api/livemap/{id}"));
|
||||
assert!(info["dimensions"][0]["available"].as_bool().unwrap());
|
||||
// No generator is installed in the test environment.
|
||||
assert_eq!(info["ready"], false);
|
||||
|
||||
let (_, pj) = t.call("GET", &format!("/api/livemap/{id}/the_nether/v1/worlds/default/players.json"), Some(&admin), None).await;
|
||||
assert_eq!(pj["players"][0]["name"], "Notch");
|
||||
assert_eq!(pj["players"][0]["foreign"], false);
|
||||
let (_, pj) = t.call("GET", &format!("/api/livemap/{id}/overworld/v1/worlds/default/players.json"), Some(&admin), None).await;
|
||||
assert_eq!(pj["players"][0]["foreign"], true);
|
||||
|
||||
let (s, e) = t.call("GET", &format!("/api/livemap/{id}/overworld/v1/worlds/default/manifest.json"), Some(&admin), None).await;
|
||||
assert_eq!(s, StatusCode::SERVICE_UNAVAILABLE);
|
||||
assert!(e["error"].as_str().unwrap().contains("generator"));
|
||||
let (s, _) = t.call("GET", &format!("/api/livemap/{id}/overworld/v1/openapi.json"), Some(&admin), None).await;
|
||||
assert_eq!(s, StatusCode::NOT_FOUND);
|
||||
let (s, _) = t.call("GET", &format!("/api/livemap/{id}/overworld/v1/worlds/default/manifest.json"), None, None).await;
|
||||
assert_eq!(s, StatusCode::UNAUTHORIZED);
|
||||
assert_eq!(info["ready"], true);
|
||||
|
||||
let (s, st) = t.call("GET", &format!("/api/admin/servers/{id}/livemap"), Some(&admin), None).await;
|
||||
assert_eq!(s, StatusCode::OK);
|
||||
assert_eq!(st["stats"]["chunks_received"], 2);
|
||||
assert_eq!(st["generator"]["installed"], false);
|
||||
|
||||
// Public list advertises the map; reset wipes it.
|
||||
let (_, list) = t.call("GET", "/api/v1/servers/public", None, None).await;
|
||||
@@ -114,70 +97,3 @@ async fn live_map_ingest_status_and_proxy() {
|
||||
let (_, m) = t.call("GET", "/api/server/v1/livemap/manifest?dim=overworld", Some(&token), None).await;
|
||||
assert!(m["regions"].as_array().unwrap().is_empty());
|
||||
}
|
||||
|
||||
/// A stand-in for `vantage server` that answers health checks and serves a
|
||||
/// manifest, to exercise the supervisor and proxy end to end.
|
||||
#[cfg(unix)]
|
||||
#[tokio::test]
|
||||
async fn proxy_starts_and_reaches_the_generator() {
|
||||
if std::process::Command::new("python3").arg("--version").output().is_err() {
|
||||
return;
|
||||
}
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
let t = setup_with(|cfg, dir| {
|
||||
let bin = dir.join("fake-vantage");
|
||||
std::fs::write(
|
||||
&bin,
|
||||
r#"#!/usr/bin/env python3
|
||||
import sys, os, http.server
|
||||
a = sys.argv
|
||||
port = int(a[a.index('--port') + 1])
|
||||
assert a[1] == 'server' and '--assets' in a and '--players-file' in a
|
||||
token = os.environ['VANTAGE_SERVER_TOKEN']
|
||||
class H(http.server.BaseHTTPRequestHandler):
|
||||
def do_GET(self):
|
||||
if self.path == '/v1/health':
|
||||
body = b'ok'
|
||||
elif self.headers.get('Authorization') != 'Bearer ' + token:
|
||||
self.send_response(401); self.end_headers(); return
|
||||
else:
|
||||
body = b'{"fake":true,"path":"' + self.path.encode() + b'"}'
|
||||
self.send_response(200); self.send_header('ETag', '"v1"'); self.send_header('Content-Type', 'application/json'); self.end_headers(); self.wfile.write(body)
|
||||
def log_message(self, *a): pass
|
||||
http.server.ThreadingHTTPServer(('127.0.0.1', port), H).serve_forever()
|
||||
"#,
|
||||
)
|
||||
.unwrap();
|
||||
std::fs::set_permissions(&bin, std::fs::Permissions::from_mode(0o755)).unwrap();
|
||||
std::fs::create_dir_all(dir.join("assets")).unwrap();
|
||||
cfg.vantage_bin = Some(bin);
|
||||
cfg.vantage_assets = Some(dir.join("assets"));
|
||||
})
|
||||
.await;
|
||||
let admin = t.login("admin", "supersecret").await;
|
||||
let (_, v) = t.call("POST", "/api/admin/servers", Some(&admin), Some(json!({"name": "S", "live_map_enabled": true}))).await;
|
||||
let id = v["server"]["id"].as_i64().unwrap();
|
||||
let token = v["token"].as_str().unwrap().to_string();
|
||||
|
||||
let uri = format!("/api/livemap/{id}/overworld/v1/worlds/default/manifest.json");
|
||||
let (s, _) = t.call("GET", &uri, Some(&admin), None).await;
|
||||
assert_eq!(s, StatusCode::SERVICE_UNAVAILABLE, "no world uploaded yet");
|
||||
|
||||
post_bytes(&t, &format!("/api/server/v1/livemap/chunks?dim=overworld"), &token, record(0, 0, 5, b"abc")).await;
|
||||
let mut gz = vec![0x1f, 0x8b];
|
||||
gz.extend([0u8; 30]);
|
||||
post_bytes(&t, "/api/server/v1/livemap/level", &token, gz).await;
|
||||
|
||||
let (_, info) = t.call("GET", &format!("/api/v1/servers/{id}/livemap"), Some(&admin), None).await;
|
||||
assert_eq!(info["ready"], true, "{info}");
|
||||
let (s, body) = t.call("GET", &uri, Some(&admin), None).await;
|
||||
assert_eq!(s, StatusCode::OK, "{body}");
|
||||
assert_eq!(body["fake"], true);
|
||||
assert_eq!(body["path"], "/v1/worlds/default/manifest.json");
|
||||
let (_, st) = t.call("GET", &format!("/api/admin/servers/{id}/livemap"), Some(&admin), None).await;
|
||||
assert_eq!(st["running"][0], "overworld");
|
||||
// Reset stops the generator and deletes the mirror.
|
||||
t.call("DELETE", &format!("/api/admin/servers/{id}/livemap"), Some(&admin), None).await;
|
||||
let (_, st) = t.call("GET", &format!("/api/admin/servers/{id}/livemap"), Some(&admin), None).await;
|
||||
assert!(st["running"].as_array().unwrap().is_empty());
|
||||
}
|
||||
Reference in new issue
Block a user