From 5b58a9f0e1220080b165dd68cd8a6f4ed39a211d Mon Sep 17 00:00:00 2001 From: = Date: Tue, 20 May 2025 18:40:36 -0400 Subject: [PATCH 01/11] Fixed rename by using put instead of post --- crates/cli/src/subcommands/dns.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/cli/src/subcommands/dns.rs b/crates/cli/src/subcommands/dns.rs index 03f4e96b3ea..fd434c5d3ff 100644 --- a/crates/cli/src/subcommands/dns.rs +++ b/crates/cli/src/subcommands/dns.rs @@ -37,11 +37,11 @@ pub async fn exec(mut config: Config, args: &ArgMatches) -> Result<(), anyhow::E let domain: DomainName = domain.parse()?; let builder = reqwest::Client::new() - .post(format!( + .put(format!( "{}/v1/database/{database_identity}/names", config.get_host_url(server)? )) - .body(String::from(domain)); + .body(format!("[{}]", String::from(domain))); let builder = add_auth_header_opt(builder, &auth_header); let result = builder.send().await?.json_or_error().await?; From 9278fced6b246323c1dd9251b4580aa6d51a4649 Mon Sep 17 00:00:00 2001 From: = Date: Tue, 20 May 2025 22:04:12 -0400 Subject: [PATCH 02/11] Quotes around the name --- crates/cli/src/subcommands/dns.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/cli/src/subcommands/dns.rs b/crates/cli/src/subcommands/dns.rs index fd434c5d3ff..be1432e84d3 100644 --- a/crates/cli/src/subcommands/dns.rs +++ b/crates/cli/src/subcommands/dns.rs @@ -41,7 +41,7 @@ pub async fn exec(mut config: Config, args: &ArgMatches) -> Result<(), anyhow::E "{}/v1/database/{database_identity}/names", config.get_host_url(server)? )) - .body(format!("[{}]", String::from(domain))); + .body(format!("[\"{}\"]", String::from(domain))); let builder = add_auth_header_opt(builder, &auth_header); let result = builder.send().await?.json_or_error().await?; From 2a0d61731e1ee96dd4d8932db47cc13cf0d9fb46 Mon Sep 17 00:00:00 2001 From: Zeke Foppa Date: Tue, 20 May 2025 22:18:43 -0700 Subject: [PATCH 03/11] [tyler/fix-rename]: fix? --- crates/cli/src/subcommands/dns.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/cli/src/subcommands/dns.rs b/crates/cli/src/subcommands/dns.rs index be1432e84d3..2d460648aca 100644 --- a/crates/cli/src/subcommands/dns.rs +++ b/crates/cli/src/subcommands/dns.rs @@ -41,7 +41,8 @@ pub async fn exec(mut config: Config, args: &ArgMatches) -> Result<(), anyhow::E "{}/v1/database/{database_identity}/names", config.get_host_url(server)? )) - .body(format!("[\"{}\"]", String::from(domain))); + .header(reqwest::header::CONTENT_TYPE, "application/json") + .body(serde_json::to_string(&[String::from(domain)])); let builder = add_auth_header_opt(builder, &auth_header); let result = builder.send().await?.json_or_error().await?; From b980b956c99763a604e35045ae5e98d49165c118 Mon Sep 17 00:00:00 2001 From: Zeke Foppa Date: Tue, 20 May 2025 22:22:15 -0700 Subject: [PATCH 04/11] [tyler/fix-rename]: fix build? --- crates/cli/src/subcommands/dns.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/cli/src/subcommands/dns.rs b/crates/cli/src/subcommands/dns.rs index 2d460648aca..f655fcbd9bc 100644 --- a/crates/cli/src/subcommands/dns.rs +++ b/crates/cli/src/subcommands/dns.rs @@ -42,7 +42,7 @@ pub async fn exec(mut config: Config, args: &ArgMatches) -> Result<(), anyhow::E config.get_host_url(server)? )) .header(reqwest::header::CONTENT_TYPE, "application/json") - .body(serde_json::to_string(&[String::from(domain)])); + .body(serde_json::to_string(&[String::from(domain)])?); let builder = add_auth_header_opt(builder, &auth_header); let result = builder.send().await?.json_or_error().await?; From ee77a9f6001d601eecd53ff5570dc53abdd1d435 Mon Sep 17 00:00:00 2001 From: Zeke Foppa Date: Wed, 21 May 2025 10:29:06 -0700 Subject: [PATCH 05/11] [tyler/fix-rename]: works? --- crates/cli/src/subcommands/dns.rs | 64 +++++-------------------------- 1 file changed, 10 insertions(+), 54 deletions(-) diff --git a/crates/cli/src/subcommands/dns.rs b/crates/cli/src/subcommands/dns.rs index f655fcbd9bc..d8219e12f37 100644 --- a/crates/cli/src/subcommands/dns.rs +++ b/crates/cli/src/subcommands/dns.rs @@ -1,10 +1,10 @@ use crate::common_args; use crate::config::Config; -use crate::util::{add_auth_header_opt, decode_identity, get_auth_header, get_login_token_or_log_in, ResponseExt}; +use crate::util::{add_auth_header_opt, get_auth_header}; use clap::ArgMatches; use clap::{Arg, Command}; -use spacetimedb_client_api_messages::name::{DomainName, InsertDomainResult}; +use spacetimedb_client_api_messages::name::DomainName; pub fn cli() -> Command { Command::new("rename") @@ -30,8 +30,6 @@ pub async fn exec(mut config: Config, args: &ArgMatches) -> Result<(), anyhow::E let database_identity = args.get_one::("database-identity").unwrap(); let server = args.get_one::("server").map(|s| s.as_ref()); let force = args.get_flag("force"); - let token = get_login_token_or_log_in(&mut config, server, !force).await?; - let identity = decode_identity(&token)?; let auth_header = get_auth_header(&mut config, false, server, !force).await?; let domain: DomainName = domain.parse()?; @@ -42,59 +40,17 @@ pub async fn exec(mut config: Config, args: &ArgMatches) -> Result<(), anyhow::E config.get_host_url(server)? )) .header(reqwest::header::CONTENT_TYPE, "application/json") - .body(serde_json::to_string(&[String::from(domain)])?); + .body(serde_json::to_string(&[&domain])?); let builder = add_auth_header_opt(builder, &auth_header); - let result = builder.send().await?.json_or_error().await?; - match result { - InsertDomainResult::Success { - domain, - database_identity, - } => { - println!("Domain set to {} for identity {}.", domain, database_identity); - } - InsertDomainResult::TldNotRegistered { domain } => { - return Err(anyhow::anyhow!( - "The top level domain that you provided is not registered.\n\ - This tld is not yet registered to any identity. You can register this domain with the following command:\n\ - \n\ - \tspacetime dns register-tld {}\n", - domain.tld() - )); - } - InsertDomainResult::PermissionDenied { domain } => { - //TODO(jdetter): Have a nice name generator here, instead of using some abstract characters - // we should perhaps generate fun names like 'green-fire-dragon' instead - let suggested_tld: String = identity.chars().take(12).collect(); - if let Some(sub_domain) = domain.sub_domain() { - return Err(anyhow::anyhow!( - "The top level domain {} is not registered to the identity you provided.\n\ - We suggest you register a new tld:\n\ - \tspacetime dns register-tld {}\n\ - \n\ - And then push to the domain that uses that tld:\n\ - \tspacetime publish {}/{}\n", - domain.tld(), - suggested_tld, - suggested_tld, - sub_domain - )); - } else { - return Err(anyhow::anyhow!( - "The top level domain {} is not registered to the identity you provided.\n\ - We suggest you register a new tld:\n\ - \tspacetime dns register-tld {}\n\ - \n\ - And then push to the domain that uses that tld:\n\ - \tspacetime publish {}\n", - domain.tld(), - suggested_tld, - suggested_tld - )); - } - } - InsertDomainResult::OtherError(e) => return Err(anyhow::anyhow!(e)), + let response = builder.send().await?; + let status = response.status(); + let response_body = response.text().await?; + if !status.is_success() { + anyhow::bail!("{response_body}"); } + println!("Domain set to {} for identity {}.", domain, database_identity); + Ok(()) } From 35c8d5d101ba46227b575304718da408ad4772fc Mon Sep 17 00:00:00 2001 From: Zeke Foppa Date: Wed, 21 May 2025 10:31:39 -0700 Subject: [PATCH 06/11] [tyler/fix-rename]: augment smoketest --- smoketests/tests/domains.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/smoketests/tests/domains.py b/smoketests/tests/domains.py index b4dfb0347c2..61fef422f2f 100644 --- a/smoketests/tests/domains.py +++ b/smoketests/tests/domains.py @@ -8,7 +8,8 @@ class Domains(Smoketest): def test_set_name(self): """Tests the functionality of the set-name command""" - self.publish_module() + orig_name = random_string() + self.publish_module(orig_name) rand_name = random_string() @@ -21,6 +22,10 @@ def test_set_name(self): # Now we're essentially just testing that it *doesn't* throw an exception self.spacetime("logs", rand_name) + # This should throw an exception because the original name shouldn't exist anymore + with self.assertRaises(Exception): + self.spacetime("logs", orig_name) + @unittest.expectedFailure def test_subdomain_behavior(self): """Test how we treat the / character in published names""" From 0dc8654539b752218439270d085ad5ba706bf76c Mon Sep 17 00:00:00 2001 From: Zeke Foppa Date: Wed, 21 May 2025 11:41:49 -0700 Subject: [PATCH 07/11] [tyler/fix-rename]: tweak error string --- crates/cli/src/subcommands/dns.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/cli/src/subcommands/dns.rs b/crates/cli/src/subcommands/dns.rs index d8219e12f37..27f3ec9117f 100644 --- a/crates/cli/src/subcommands/dns.rs +++ b/crates/cli/src/subcommands/dns.rs @@ -47,7 +47,7 @@ pub async fn exec(mut config: Config, args: &ArgMatches) -> Result<(), anyhow::E let status = response.status(); let response_body = response.text().await?; if !status.is_success() { - anyhow::bail!("{response_body}"); + anyhow::bail!("Error: {response_body}"); } println!("Domain set to {} for identity {}.", domain, database_identity); From ab139295505bfcd8056c6818a67daec422576d8d Mon Sep 17 00:00:00 2001 From: Zeke Foppa Date: Wed, 21 May 2025 11:42:31 -0700 Subject: [PATCH 08/11] [tyler/fix-rename]: tweak msg --- crates/cli/src/subcommands/dns.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/cli/src/subcommands/dns.rs b/crates/cli/src/subcommands/dns.rs index 27f3ec9117f..1e12eb5a697 100644 --- a/crates/cli/src/subcommands/dns.rs +++ b/crates/cli/src/subcommands/dns.rs @@ -50,7 +50,7 @@ pub async fn exec(mut config: Config, args: &ArgMatches) -> Result<(), anyhow::E anyhow::bail!("Error: {response_body}"); } - println!("Domain set to {} for identity {}.", domain, database_identity); + println!("Name set to {} for identity {}.", domain, database_identity); Ok(()) } From 728e83581e7eb294653609fc2d51d411ad94d47e Mon Sep 17 00:00:00 2001 From: John Detter <4099508+jdetter@users.noreply.github.com> Date: Thu, 5 Jun 2025 18:39:21 -0500 Subject: [PATCH 09/11] Add check to make sure that we're not renaming on top of an existing database. --- crates/client-api/src/routes/database.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/crates/client-api/src/routes/database.rs b/crates/client-api/src/routes/database.rs index e6e8091f27f..d6bdb475b90 100644 --- a/crates/client-api/src/routes/database.rs +++ b/crates/client-api/src/routes/database.rs @@ -704,6 +704,16 @@ pub async fn set_names( )); } + for name in validated_names { + if ctx.lookup_identity(name.as_str()).unwrap().is_some() { + return Ok(( + StatusCode::BAD_REQUEST, + axum::Json(name::SetDomainsResult::OtherError( + format!("Cannot rename to {} because it already is in use.", name.as_str()))), + )); + } + } + let response = ctx .replace_dns_records(&database_identity, &database.owner_identity, &validated_names) .await From 6e064dfb60d63be4077da9cda68a2b9c7a905441 Mon Sep 17 00:00:00 2001 From: John Detter <4099508+jdetter@users.noreply.github.com> Date: Thu, 5 Jun 2025 19:03:09 -0500 Subject: [PATCH 10/11] Improved error handling --- crates/cli/src/subcommands/dns.rs | 22 +++++++++++++++++----- crates/client-api/src/routes/database.rs | 5 ++--- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/crates/cli/src/subcommands/dns.rs b/crates/cli/src/subcommands/dns.rs index 1e12eb5a697..cbaa665c41b 100644 --- a/crates/cli/src/subcommands/dns.rs +++ b/crates/cli/src/subcommands/dns.rs @@ -1,10 +1,10 @@ use crate::common_args; use crate::config::Config; -use crate::util::{add_auth_header_opt, get_auth_header}; +use crate::util::{add_auth_header_opt, get_auth_header, ResponseExt}; use clap::ArgMatches; use clap::{Arg, Command}; -use spacetimedb_client_api_messages::name::DomainName; +use spacetimedb_client_api_messages::name::{DomainName, SetDomainsResult}; pub fn cli() -> Command { Command::new("rename") @@ -44,10 +44,22 @@ pub async fn exec(mut config: Config, args: &ArgMatches) -> Result<(), anyhow::E let builder = add_auth_header_opt(builder, &auth_header); let response = builder.send().await?; - let status = response.status(); - let response_body = response.text().await?; + let status = &response.status(); + let result : SetDomainsResult = response.json_or_error().await?; + if !status.is_success() { - anyhow::bail!("Error: {response_body}"); + anyhow::bail!(match result { + SetDomainsResult::Success => "".to_string(), + SetDomainsResult::PermissionDenied { domain } => + format!("Permission denied for domain: {}", domain), + SetDomainsResult::PermissionDeniedOnAny { domains } => + format!("Permission denied for domains: {:?}", domains), + SetDomainsResult::DatabaseNotFound => + format!("Database {} not found", database_identity), + SetDomainsResult::NotYourDatabase { .. } => + format!("You cannot rename {} because it is owned by another identity.", database_identity), + SetDomainsResult::OtherError(err) => err, + }); } println!("Name set to {} for identity {}.", domain, database_identity); diff --git a/crates/client-api/src/routes/database.rs b/crates/client-api/src/routes/database.rs index d6bdb475b90..3b2acda4073 100644 --- a/crates/client-api/src/routes/database.rs +++ b/crates/client-api/src/routes/database.rs @@ -704,13 +704,12 @@ pub async fn set_names( )); } - for name in validated_names { + for name in &validated_names { if ctx.lookup_identity(name.as_str()).unwrap().is_some() { return Ok(( StatusCode::BAD_REQUEST, axum::Json(name::SetDomainsResult::OtherError( - format!("Cannot rename to {} because it already is in use.", name.as_str()))), - )); + format!("Cannot rename to {} because it already is in use.", name.as_str()))))); } } From a1ec485347b75de459733fcc5b6f27c81686adb8 Mon Sep 17 00:00:00 2001 From: John Detter <4099508+jdetter@users.noreply.github.com> Date: Thu, 5 Jun 2025 19:06:20 -0500 Subject: [PATCH 11/11] Cargo fmt --- crates/cli/src/subcommands/dns.rs | 16 ++++++++-------- crates/client-api/src/routes/database.rs | 7 +++++-- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/crates/cli/src/subcommands/dns.rs b/crates/cli/src/subcommands/dns.rs index cbaa665c41b..ade5605f132 100644 --- a/crates/cli/src/subcommands/dns.rs +++ b/crates/cli/src/subcommands/dns.rs @@ -45,21 +45,21 @@ pub async fn exec(mut config: Config, args: &ArgMatches) -> Result<(), anyhow::E let response = builder.send().await?; let status = &response.status(); - let result : SetDomainsResult = response.json_or_error().await?; + let result: SetDomainsResult = response.json_or_error().await?; if !status.is_success() { anyhow::bail!(match result { SetDomainsResult::Success => "".to_string(), - SetDomainsResult::PermissionDenied { domain } => - format!("Permission denied for domain: {}", domain), + SetDomainsResult::PermissionDenied { domain } => format!("Permission denied for domain: {}", domain), SetDomainsResult::PermissionDeniedOnAny { domains } => format!("Permission denied for domains: {:?}", domains), - SetDomainsResult::DatabaseNotFound => - format!("Database {} not found", database_identity), - SetDomainsResult::NotYourDatabase { .. } => - format!("You cannot rename {} because it is owned by another identity.", database_identity), + SetDomainsResult::DatabaseNotFound => format!("Database {} not found", database_identity), + SetDomainsResult::NotYourDatabase { .. } => format!( + "You cannot rename {} because it is owned by another identity.", + database_identity + ), SetDomainsResult::OtherError(err) => err, - }); + }); } println!("Name set to {} for identity {}.", domain, database_identity); diff --git a/crates/client-api/src/routes/database.rs b/crates/client-api/src/routes/database.rs index 3b2acda4073..ea7e37627c4 100644 --- a/crates/client-api/src/routes/database.rs +++ b/crates/client-api/src/routes/database.rs @@ -708,8 +708,11 @@ pub async fn set_names( if ctx.lookup_identity(name.as_str()).unwrap().is_some() { return Ok(( StatusCode::BAD_REQUEST, - axum::Json(name::SetDomainsResult::OtherError( - format!("Cannot rename to {} because it already is in use.", name.as_str()))))); + axum::Json(name::SetDomainsResult::OtherError(format!( + "Cannot rename to {} because it already is in use.", + name.as_str() + ))), + )); } }