From 12ee55bc7571047690c96b447da606e489785432 Mon Sep 17 00:00:00 2001 From: korvyashka Date: Thu, 7 Mar 2024 17:43:22 +0400 Subject: [PATCH] Adds: 4.1 API update for title and name for settings. --- src/commands/edge_app.rs | 304 +++++++++++++++++------------- src/commands/edge_app_manifest.rs | 40 ++-- src/commands/edge_app_settings.rs | 56 +++++- src/commands/edge_app_utils.rs | 42 +++-- src/commands/mod.rs | 6 +- 5 files changed, 279 insertions(+), 169 deletions(-) diff --git a/src/commands/edge_app.rs b/src/commands/edge_app.rs index 7d02668..38cacb8 100644 --- a/src/commands/edge_app.rs +++ b/src/commands/edge_app.rs @@ -1,7 +1,7 @@ use crate::authentication::Authentication; use crate::commands; use crate::commands::edge_app_manifest::EdgeAppManifest; -use crate::commands::edge_app_settings::{Setting, SettingType}; +use crate::commands::edge_app_settings::{deserialize_settings_from_array, Setting, SettingType}; use crate::commands::{CommandError, EdgeAppSecrets, EdgeAppSettings, EdgeAppVersions, EdgeApps}; use indicatif::ProgressBar; use log::debug; @@ -99,7 +99,8 @@ impl EdgeAppCommand { entrypoint: Some("index.html".to_string()), settings: vec![ Setting { - title: "secret_word".to_string(), + name: "secret_word".to_string(), + title: "secret title".to_string(), type_: SettingType::Secret, default_value: None, optional: true, @@ -108,7 +109,8 @@ impl EdgeAppCommand { .to_string(), }, Setting { - title: "greeting".to_string(), + name: "greeting".to_string(), + title: "greeting title".to_string(), type_: SettingType::String, default_value: Some("Unknown".to_string()), optional: true, @@ -189,38 +191,38 @@ impl EdgeAppCommand { let response = commands::get( &self.authentication, &format!( - "v4/edge-apps/settings/values?select=title,value&installation_id=eq.{}", + "v4.1/edge-apps/settings/values?select=name,value&installation_id=eq.{}", installation_id ), )?; #[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] struct SettingValue { - title: String, + name: String, value: String, } let settings: HashMap = serde_json::from_value::>(response)? .into_iter() - .map(|setting| (setting.title, setting.value)) + .map(|setting| (setting.name, setting.value)) .collect(); let mut app_settings: Vec> = serde_json::from_value(commands::get(&self.authentication, - &format!("v4/edge-apps/settings?select=type,default_value,optional,title,help_text&app_id=eq.{}&order=title.asc&type=eq.string", + &format!("v4.1/edge-apps/settings?select=name,type,default_value,optional,title,help_text&app_id=eq.{}&order=name.asc&type=eq.string", app_id, ))?)?; // Combine settings and values into one object for setting in app_settings.iter_mut() { - let title = setting - .get("title") + let name = setting + .get("name") .and_then(|t| t.as_str()) .ok_or_else(|| { - eprintln!("Title field not found in the setting."); + eprintln!("Name field not found in the setting."); CommandError::MissingField })?; - let value = match settings.get(title) { + let value = match settings.get(name) { Some(v) => v, None => continue, }; @@ -235,7 +237,7 @@ impl EdgeAppCommand { let app_secrets: Vec> = serde_json::from_value( commands::get( &self.authentication, - &format!("v4/edge-apps/settings?select=optional,title,help_text&app_id=eq.{}&order=title.asc&type=eq.secret", app_id,) + &format!("v4.1/edge-apps/settings?select=optional,name,help_text&app_id=eq.{}&order=name.asc&type=eq.secret", app_id,) )? )?; @@ -252,7 +254,7 @@ impl EdgeAppCommand { #[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] struct SettingValue { - title: String, + name: String, } let setting_url: String; @@ -261,35 +263,35 @@ impl EdgeAppCommand { if _is_setting_global { setting_url = format!( - "v4/edge-apps/settings/values?select=title&app_id=eq.{}&title=eq.{}", + "v4.1/edge-apps/settings/values?select=name&app_id=eq.{}&name=eq.{}", app_id, setting_key, ); settings_values_payload = json!( { "app_id": app_id, - "title": setting_key, + "name": setting_key, "value": setting_value, } ); settings_values_patch_url = format!( - "v4/edge-apps/settings/values?app_id=eq.{}&title=eq.{}", + "v4.1/edge-apps/settings/values?app_id=eq.{}&name=eq.{}", app_id, setting_key, ); } else { let installation_id = self.get_or_create_installation(app_id)?; setting_url = format!( - "v4/edge-apps/settings/values?select=title&installation_id=eq.{}&title=eq.{}", + "v4.1/edge-apps/settings/values?select=name&installation_id=eq.{}&name=eq.{}", installation_id, setting_key, ); settings_values_payload = json!( { "installation_id": installation_id, - "title": setting_key, + "name": setting_key, "value": setting_value, } ); settings_values_patch_url = format!( - "v4/edge-apps/settings/values?installation_id=eq.{}&title=eq.{}", + "v4.1/edge-apps/settings/values?installation_id=eq.{}&name=eq.{}", installation_id, setting_key, ); } @@ -300,7 +302,7 @@ impl EdgeAppCommand { if setting_values.is_empty() { commands::post( &self.authentication, - "v4/edge-apps/settings/values", + "v4.1/edge-apps/settings/values", &settings_values_payload, )?; } else { @@ -330,7 +332,7 @@ impl EdgeAppCommand { json!( { "app_id": app_id, - "title": secret_key, + "name": secret_key, "value": secret_value, } ) @@ -339,7 +341,7 @@ impl EdgeAppCommand { json!( { "installation_id": installation_id, - "title": secret_key, + "name": secret_key, "value": secret_value, } ) @@ -347,7 +349,7 @@ impl EdgeAppCommand { commands::post( &self.authentication, - "v4/edge-apps/secrets/values", + "v4.1/edge-apps/secrets/values", &payload, )?; @@ -419,10 +421,10 @@ impl EdgeAppCommand { let changed_files = detect_changed_files(&local_files, &remote_files)?; debug!("Changed files: {:?}", &changed_files); - let remote_settings = serde_json::from_value::>(commands::get( + let remote_settings = deserialize_settings_from_array(commands::get( &self.authentication, &format!( - "v4/edge-apps/settings?select=type,default_value,optional,title,help_text&app_id=eq.{}&order=title.asc", + "v4.1/edge-apps/settings?select=name,type,default_value,optional,title,help_text&app_id=eq.{}&order=name.asc", actual_app_id, ), )?)?; @@ -592,7 +594,7 @@ impl EdgeAppCommand { None => "".to_owned(), }; settings.insert( - setting.title.clone(), + setting.name.clone(), serde_yaml::Value::String(settings_default_value), ); } @@ -872,14 +874,15 @@ impl EdgeAppCommand { let value = serde_json::to_value(setting)?; let mut payload = serde_json::from_value::>(value)?; payload.insert("app_id".to_owned(), json!(app_id)); + payload.insert("name".to_owned(), json!(setting.name)); debug!("Creating setting: {:?}", &payload); - let response = commands::post(&self.authentication, "v4/edge-apps/settings", &payload); + let response = commands::post(&self.authentication, "v4.1/edge-apps/settings", &payload); if response.is_err() { let c = commands::get( &self.authentication, - &format!("v4/edge-apps/settings?app_id=eq.{}", app_id), + &format!("v4.1/edge-apps/settings?app_id=eq.{}", app_id), )?; debug!("Existing settings: {:?}", c); return Err(CommandError::NoChangesToUpload("".to_owned())); @@ -890,22 +893,23 @@ impl EdgeAppCommand { fn update_setting(&self, app_id: String, setting: &Setting) -> Result<(), CommandError> { let value = serde_json::to_value(setting)?; - let payload = serde_json::from_value::>(value)?; + let mut payload = serde_json::from_value::>(value)?; + payload.insert("name".to_owned(), json!(setting.name)); debug!("Updating setting: {:?}", &payload); let response = commands::patch( &self.authentication, &format!( - "v4/edge-apps/settings?app_id=eq.{id}&title=eq.{title}", + "v4.1/edge-apps/settings?app_id=eq.{id}&name=eq.{name}", id = app_id, - title = setting.title + name = setting.name ), &payload, ); if let Err(error) = response { - debug!("Failed to update setting: {}", setting.title); + debug!("Failed to update setting: {}", setting.name); return Err(error); } @@ -1042,7 +1046,7 @@ impl EdgeAppCommand { let response = commands::get( &self.authentication, &format!( - "v4/edge-apps/settings?select=is_global&app_id=eq.{}&title=eq.{}", + "v4.1/edge-apps/settings?select=is_global&app_id=eq.{}&name=eq.{}", app_id, setting_key, ), )?; @@ -1148,7 +1152,8 @@ mod tests { manifest.settings, vec![ Setting { - title: "greeting".to_string(), + name: "greeting".to_string(), + title: "greeting title".to_string(), type_: SettingType::String, default_value: Some("Unknown".to_string()), optional: true, @@ -1157,7 +1162,8 @@ mod tests { .to_string(), }, Setting { - title: "secret_word".to_string(), + name: "secret_word".to_string(), + title: "secret title".to_string(), type_: SettingType::Secret, default_value: None, optional: true, @@ -1438,36 +1444,39 @@ mod tests { let settings_mock = mock_server.mock(|when, then| { when.method(GET) - .path("/v4/edge-apps/settings") + .path("/v4.1/edge-apps/settings") .header("Authorization", "Token token") .header( "user-agent", format!("screenly-cli {}", env!("CARGO_PKG_VERSION")), ) - .query_param("select", "type,default_value,optional,title,help_text") + .query_param("select", "name,type,default_value,optional,title,help_text") .query_param("app_id", "eq.01H2QZ6Z8WXWNDC0KQ198XCZEW") - .query_param("order", "title.asc"); + .query_param("order", "name.asc"); then.status(200).json_body(json!([ { + "name": "Example setting1", "type": "string", "default_value": "stranger", "optional": true, - "title": "Example setting1", + "title": "Example title1", "help_text": "An example of a setting that is used in index.html" }, { + "name": "Example setting2", "type": "string", "default_value": "stranger", "optional": true, - "title": "Example setting2", + "title": "Example title2", "help_text": "An example of a setting that is used in index.html" }, { + "name": "Example setting3", "type": "string", "default_value": "stranger", "optional": true, - "title": "Example setting3", + "title": "Example title3", "help_text": "An example of a setting that is used in index.html" } ])); @@ -1475,22 +1484,22 @@ mod tests { let setting_values_mock = mock_server.mock(|when, then| { when.method(GET) - .path("/v4/edge-apps/settings/values") + .path("/v4.1/edge-apps/settings/values") .header("Authorization", "Token token") .header( "user-agent", format!("screenly-cli {}", env!("CARGO_PKG_VERSION")), ) - .query_param("select", "title,value") + .query_param("select", "name,value") .query_param("installation_id", "eq.01H2QZ6Z8WXWNDC0KQ198XCZEB"); then.status(200).json_body(json!([ { - "title": "Example setting1", + "name": "Example setting1", "value": "stranger" }, { - "title": "Example setting2", + "name": "Example setting2", "value": "stranger" } ])); @@ -1514,26 +1523,29 @@ mod tests { settings_json, json!([ { + "name": "Example setting1", "type": "string", "default_value": "stranger", "optional": true, - "title": "Example setting1", + "title": "Example title1", "help_text": "An example of a setting that is used in index.html", "value": "stranger", }, { + "name": "Example setting2", "type": "string", "default_value": "stranger", "optional": true, - "title": "Example setting2", + "title": "Example title2", "help_text": "An example of a setting that is used in index.html", "value": "stranger" }, { + "name": "Example setting3", "type": "string", "default_value": "stranger", "optional": true, - "title": "Example setting3", + "title": "Example title3", "help_text": "An example of a setting that is used in index.html" } ]) @@ -1546,7 +1558,7 @@ mod tests { let setting_get_mock = mock_server.mock(|when, then| { when.method(GET) - .path("/v4/edge-apps/settings") + .path("/v4.1/edge-apps/settings") .header("Authorization", "Token token") .header( "user-agent", @@ -1554,7 +1566,7 @@ mod tests { ) .query_param("select", "is_global") .query_param("app_id", "eq.01H2QZ6Z8WXWNDC0KQ198XCZEW") - .query_param("title", "eq.best_setting"); + .query_param("name", "eq.best_setting"); then.status(200).json_body(json!([ { @@ -1602,21 +1614,21 @@ mod tests { // "v4/edge-apps/settings/values?select=title&installation_id=eq.{}&title=eq.{}" let setting_values_mock_get = mock_server.mock(|when, then| { when.method(GET) - .path("/v4/edge-apps/settings/values") + .path("/v4.1/edge-apps/settings/values") .header("Authorization", "Token token") .header( "user-agent", format!("screenly-cli {}", env!("CARGO_PKG_VERSION")), ) - .query_param("title", "eq.best_setting") - .query_param("select", "title") + .query_param("name", "eq.best_setting") + .query_param("select", "name") .query_param("installation_id", "eq.01H2QZ6Z8WXWNDC0KQ198XCZEB"); then.status(200).json_body(json!([])); }); let setting_values_mock_post = mock_server.mock(|when, then| { when.method(POST) - .path("/v4/edge-apps/settings/values") + .path("/v4.1/edge-apps/settings/values") .header("Authorization", "Token token") .header( "user-agent", @@ -1624,7 +1636,7 @@ mod tests { ) .json_body(json!( { - "title": "best_setting", + "name": "best_setting", "value": "best_value", "installation_id": "01H2QZ6Z8WXWNDC0KQ198XCZEB" } @@ -1653,7 +1665,7 @@ mod tests { let setting_get_mock = mock_server.mock(|when, then| { when.method(GET) - .path("/v4/edge-apps/settings") + .path("/v4.1/edge-apps/settings") .header("Authorization", "Token token") .header( "user-agent", @@ -1661,7 +1673,7 @@ mod tests { ) .query_param("select", "is_global") .query_param("app_id", "eq.01H2QZ6Z8WXWNDC0KQ198XCZEW") - .query_param("title", "eq.best_setting"); + .query_param("name", "eq.best_setting"); then.status(200).json_body(json!([ { @@ -1692,18 +1704,18 @@ mod tests { // "v4/edge-apps/settings/values?select=title&installation_id=eq.{}&title=eq.{}" let setting_values_mock_get = mock_server.mock(|when, then| { when.method(GET) - .path("/v4/edge-apps/settings/values") + .path("/v4.1/edge-apps/settings/values") .header("Authorization", "Token token") .header( "user-agent", format!("screenly-cli {}", env!("CARGO_PKG_VERSION")), ) - .query_param("title", "eq.best_setting") - .query_param("select", "title") + .query_param("name", "eq.best_setting") + .query_param("select", "name") .query_param("installation_id", "eq.01H2QZ6Z8WXWNDC0KQ198XCZEB"); then.status(200).json_body(json!([ { - "title": "best_setting", + "name": "best_setting", "value": "best_value", } ])); @@ -1711,13 +1723,13 @@ mod tests { let setting_values_mock_patch = mock_server.mock(|when, then| { when.method(PATCH) - .path("/v4/edge-apps/settings/values") + .path("/v4.1/edge-apps/settings/values") .header("Authorization", "Token token") .header( "user-agent", format!("screenly-cli {}", env!("CARGO_PKG_VERSION")), ) - .query_param("title", "eq.best_setting") + .query_param("name", "eq.best_setting") .query_param("installation_id", "eq.01H2QZ6Z8WXWNDC0KQ198XCZEB") .json_body(json!( { @@ -1747,7 +1759,7 @@ mod tests { let setting_get_mock = mock_server.mock(|when, then| { when.method(GET) - .path("/v4/edge-apps/settings") + .path("/v4.1/edge-apps/settings") .header("Authorization", "Token token") .header( "user-agent", @@ -1755,7 +1767,7 @@ mod tests { ) .query_param("select", "is_global") .query_param("app_id", "eq.01H2QZ6Z8WXWNDC0KQ198XCZEW") - .query_param("title", "eq.best_setting"); + .query_param("name", "eq.best_setting"); then.status(200).json_body(json!([ { @@ -1767,18 +1779,18 @@ mod tests { // "v4/edge-apps/settings/values?select=title&installation_id=eq.{}&title=eq.{}" let setting_values_mock_get = mock_server.mock(|when, then| { when.method(GET) - .path("/v4/edge-apps/settings/values") + .path("/v4.1/edge-apps/settings/values") .header("Authorization", "Token token") .header( "user-agent", format!("screenly-cli {}", env!("CARGO_PKG_VERSION")), ) - .query_param("title", "eq.best_setting") - .query_param("select", "title") + .query_param("name", "eq.best_setting") + .query_param("select", "name") .query_param("app_id", "eq.01H2QZ6Z8WXWNDC0KQ198XCZEW"); then.status(200).json_body(json!([ { - "title": "best_setting", + "name": "best_setting", "value": "best_value", } ])); @@ -1786,13 +1798,13 @@ mod tests { let setting_values_mock_patch = mock_server.mock(|when, then| { when.method(PATCH) - .path("/v4/edge-apps/settings/values") + .path("/v4.1/edge-apps/settings/values") .header("Authorization", "Token token") .header( "user-agent", format!("screenly-cli {}", env!("CARGO_PKG_VERSION")), ) - .query_param("title", "eq.best_setting") + .query_param("name", "eq.best_setting") .query_param("app_id", "eq.01H2QZ6Z8WXWNDC0KQ198XCZEW") .json_body(json!( { @@ -1821,7 +1833,7 @@ mod tests { let setting_get_mock = mock_server.mock(|when, then| { when.method(GET) - .path("/v4/edge-apps/settings") + .path("/v4.1/edge-apps/settings") .header("Authorization", "Token token") .header( "user-agent", @@ -1829,7 +1841,7 @@ mod tests { ) .query_param("select", "is_global") .query_param("app_id", "eq.01H2QZ6Z8WXWNDC0KQ198XCZEW") - .query_param("title", "eq.best_setting"); + .query_param("name", "eq.best_setting"); then.status(200).json_body(json!([ { @@ -1841,21 +1853,21 @@ mod tests { // "v4/edge-apps/settings/values?select=title&installation_id=eq.{}&title=eq.{}" let setting_values_mock_get = mock_server.mock(|when, then| { when.method(GET) - .path("/v4/edge-apps/settings/values") + .path("/v4.1/edge-apps/settings/values") .header("Authorization", "Token token") .header( "user-agent", format!("screenly-cli {}", env!("CARGO_PKG_VERSION")), ) - .query_param("title", "eq.best_setting") - .query_param("select", "title") + .query_param("name", "eq.best_setting") + .query_param("select", "name") .query_param("app_id", "eq.01H2QZ6Z8WXWNDC0KQ198XCZEW"); then.status(200).json_body(json!([])); }); let setting_values_mock_post = mock_server.mock(|when, then| { when.method(POST) - .path("/v4/edge-apps/settings/values") + .path("/v4.1/edge-apps/settings/values") .header("Authorization", "Token token") .header( "user-agent", @@ -1864,7 +1876,7 @@ mod tests { .json_body(json!( { "value": "best_value1", - "title": "best_setting", + "name": "best_setting", "app_id": "01H2QZ6Z8WXWNDC0KQ198XCZEW", } )); @@ -1890,7 +1902,7 @@ mod tests { let setting_get_mock = mock_server.mock(|when, then| { when.method(GET) - .path("/v4/edge-apps/settings") + .path("/v4.1/edge-apps/settings") .header("Authorization", "Token token") .header( "user-agent", @@ -1898,7 +1910,7 @@ mod tests { ) .query_param("select", "is_global") .query_param("app_id", "eq.01H2QZ6Z8WXWNDC0KQ198XCZEW") - .query_param("title", "eq.best_setting"); + .query_param("name", "eq.best_setting"); then.status(200).json_body(json!([])); }); @@ -1925,7 +1937,7 @@ mod tests { let setting_get_mock = mock_server.mock(|when, then| { when.method(GET) - .path("/v4/edge-apps/settings") + .path("/v4.1/edge-apps/settings") .header("Authorization", "Token token") .header( "user-agent", @@ -1933,7 +1945,7 @@ mod tests { ) .query_param("select", "is_global") .query_param("app_id", "eq.01H2QZ6Z8WXWNDC0KQ198XCZEW") - .query_param("title", "eq.best_secret_setting"); + .query_param("name", "eq.best_secret_setting"); then.status(200).json_body(json!([ { @@ -1982,7 +1994,7 @@ mod tests { let secrets_values_mock_post = mock_server.mock(|when, then| { when.method(POST) - .path("/v4/edge-apps/secrets/values") + .path("/v4.1/edge-apps/secrets/values") .header("Authorization", "Token token") .header( "user-agent", @@ -1990,7 +2002,7 @@ mod tests { ) .json_body(json!( { - "title": "best_secret_setting", + "name": "best_secret_setting", "value": "best_secret_value", "installation_id": "01H2QZ6Z8WXWNDC0KQ198XCZEB" } @@ -2023,7 +2035,7 @@ mod tests { let setting_get_mock = mock_server.mock(|when, then| { when.method(GET) - .path("/v4/edge-apps/settings") + .path("/v4.1/edge-apps/settings") .header("Authorization", "Token token") .header( "user-agent", @@ -2031,7 +2043,7 @@ mod tests { ) .query_param("select", "is_global") .query_param("app_id", "eq.01H2QZ6Z8WXWNDC0KQ198XCZEW") - .query_param("title", "eq.best_secret_setting"); + .query_param("name", "eq.best_secret_setting"); then.status(200).json_body(json!([ { @@ -2044,7 +2056,7 @@ mod tests { let secrets_values_mock_post = mock_server.mock(|when, then| { when.method(POST) - .path("/v4/edge-apps/secrets/values") + .path("/v4.1/edge-apps/secrets/values") .header("Authorization", "Token token") .header( "user-agent", @@ -2052,7 +2064,7 @@ mod tests { ) .json_body(json!( { - "title": "best_secret_setting", + "name": "best_secret_setting", "value": "best_secret_value", "app_id": "01H2QZ6Z8WXWNDC0KQ198XCZEW" } @@ -2081,16 +2093,18 @@ mod tests { fn test_upload_should_send_correct_requests() { let mut manifest = create_edge_app_manifest_for_test(vec![ Setting { + name: "asetting".to_string(), type_: SettingType::String, - title: "asetting".to_string(), + title: "atitle".to_string(), optional: false, default_value: Some("".to_string()), is_global: false, help_text: "help text".to_string(), }, Setting { + name: "nsetting".to_string(), type_: SettingType::String, - title: "nsetting".to_string(), + title: "ntitle".to_string(), optional: false, default_value: Some("".to_string()), is_global: false, @@ -2167,19 +2181,20 @@ mod tests { // v4/edge-apps/settings?select=type,default_value,optional,title,help_text&app_id=eq.{}&order=title.asc let settings_mock = mock_server.mock(|when, then| { when.method(GET) - .path("/v4/edge-apps/settings") + .path("/v4.1/edge-apps/settings") .header("Authorization", "Token token") .header( "user-agent", format!("screenly-cli {}", env!("CARGO_PKG_VERSION")), ) .query_param("app_id", "eq.01H2QZ6Z8WXWNDC0KQ198XCZEW") - .query_param("select", "type,default_value,optional,title,help_text") - .query_param("order", "title.asc"); + .query_param("select", "name,type,default_value,optional,title,help_text") + .query_param("order", "name.asc"); then.status(200).json_body(json!([{ + "name": "nsetting".to_string(), "type": SettingType::String, "default_value": "5".to_string(), - "title": "nsetting".to_string(), + "title": "ntitle".to_string(), "optional": true, "help_text": "For how long to display the map overlay every time the rover has moved to a new position.".to_string(), "is_global": false, @@ -2209,26 +2224,28 @@ mod tests { // v4/edge-apps/settings?app_id=eq.{} let settings_mock_create = mock_server.mock(|when, then| { when.method(POST) - .path("/v4/edge-apps/settings") + .path("/v4.1/edge-apps/settings") .header("Authorization", "Token token") .header( "user-agent", format!("screenly-cli {}", env!("CARGO_PKG_VERSION")), ) .json_body(json!({ + "name": "asetting", "app_id": "01H2QZ6Z8WXWNDC0KQ198XCZEW", "type": "string", "default_value": "", - "title": "asetting", + "title": "atitle", "optional": false, "help_text": "help text", })); then.status(201).json_body(json!( [{ + "name": "asetting", "app_id": "01H2QZ6Z8WXWNDC0KQ198XCZEW", "type": "string", "default_value": "", - "title": "asetting", + "title": "atitle", "optional": false, "help_text": "help text", }])); @@ -2236,27 +2253,29 @@ mod tests { let settings_mock_patch = mock_server.mock(|when, then| { when.method(PATCH) - .path("/v4/edge-apps/settings") + .path("/v4.1/edge-apps/settings") .header("Authorization", "Token token") .header( "user-agent", format!("screenly-cli {}", env!("CARGO_PKG_VERSION")), ) .query_param("app_id", "eq.01H2QZ6Z8WXWNDC0KQ198XCZEW") - .query_param("title", "eq.nsetting") + .query_param("name", "eq.nsetting") .json_body(json!({ + "name": "nsetting", "type": "string", "default_value": "", - "title": "nsetting", + "title": "ntitle", "optional": false, "help_text": "help text", })); then.status(200).json_body(json!( [{ + "name": "nsetting", "app_id": "01H2QZ6Z8WXWNDC0KQ198XCZEW", "type": "string", "default_value": "", - "title": "nsetting", + "title": "ntitle", "optional": false, "help_text": "help text", }])); @@ -2379,16 +2398,18 @@ mod tests { fn test_detect_version_metadata_changes_when_no_changes_should_return_false() { let manifest = create_edge_app_manifest_for_test(vec![ Setting { + name: "asetting".to_string(), type_: SettingType::String, - title: "asetting".to_string(), + title: "atitle".to_string(), optional: false, default_value: Some("".to_string()), is_global: false, help_text: "help text".to_string(), }, Setting { + name: "nsetting".to_string(), type_: SettingType::String, - title: "nsetting".to_string(), + title: "ntitle".to_string(), optional: false, default_value: Some("".to_string()), is_global: false, @@ -2450,16 +2471,18 @@ mod tests { fn test_detect_version_metadata_changes_when_has_changes_should_return_true() { let manifest = create_edge_app_manifest_for_test(vec![ Setting { + name: "asetting".to_string(), type_: SettingType::String, - title: "asetting".to_string(), + title: "atitle".to_string(), optional: false, default_value: Some("".to_string()), is_global: false, help_text: "help text".to_string(), }, Setting { + name: "nsetting".to_string(), type_: SettingType::String, - title: "nsetting".to_string(), + title: "ntitle".to_string(), optional: false, default_value: Some("".to_string()), is_global: false, @@ -2521,16 +2544,18 @@ mod tests { fn test_detect_version_metadata_changes_when_no_version_exist_should_return_false() { let manifest = create_edge_app_manifest_for_test(vec![ Setting { + name: "asetting".to_string(), type_: SettingType::String, - title: "asetting".to_string(), + title: "atitle".to_string(), optional: false, default_value: Some("".to_string()), is_global: false, help_text: "help text".to_string(), }, Setting { + name: "nsetting".to_string(), type_: SettingType::String, - title: "nsetting".to_string(), + title: "ntitle".to_string(), optional: false, default_value: Some("".to_string()), is_global: false, @@ -2696,16 +2721,18 @@ mod tests { // The EdgeAppManifest structure from your example let manifest = create_edge_app_manifest_for_test(vec![ Setting { + name: "asetting".to_string(), type_: SettingType::String, - title: "asetting".to_string(), + title: "atitle".to_string(), optional: false, default_value: Some("yes".to_string()), is_global: false, help_text: "help text".to_string(), }, Setting { + name: "nsetting".to_string(), type_: SettingType::String, - title: "nsetting".to_string(), + title: "ntitle".to_string(), optional: false, default_value: Some("".to_string()), is_global: false, @@ -2745,16 +2772,18 @@ settings: let manifest = create_edge_app_manifest_for_test(vec![ Setting { + name: "excluded_setting".to_string(), type_: SettingType::Secret, - title: "excluded_setting".to_string(), + title: "excluded title".to_string(), optional: false, default_value: None, is_global: false, help_text: "help text".to_string(), }, Setting { + name: "included_setting".to_string(), type_: SettingType::String, - title: "included_setting".to_string(), + title: "included title".to_string(), optional: false, default_value: Some("".to_string()), is_global: false, @@ -2779,16 +2808,18 @@ settings: fn test_ensure_assets_processing_finished_when_processing_failed_should_return_error() { let manifest = create_edge_app_manifest_for_test(vec![ Setting { + name: "asetting".to_string(), type_: SettingType::String, - title: "asetting".to_string(), + title: "atitle".to_string(), optional: false, default_value: Some("".to_string()), is_global: false, help_text: "help text".to_string(), }, Setting { + name: "nsetting".to_string(), type_: SettingType::String, - title: "nsetting".to_string(), + title: "atitle".to_string(), optional: false, default_value: Some("".to_string()), is_global: false, @@ -2844,31 +2875,31 @@ settings: let secrets_mock = mock_server.mock(|when, then| { when.method(GET) - .path("/v4/edge-apps/settings") + .path("/v4.1/edge-apps/settings") .header("Authorization", "Token token") .header( "user-agent", format!("screenly-cli {}", env!("CARGO_PKG_VERSION")), ) - .query_param("select", "optional,title,help_text") + .query_param("select", "optional,name,help_text") .query_param("app_id", "eq.01H2QZ6Z8WXWNDC0KQ198XCZEW") .query_param("type", "eq.secret") - .query_param("order", "title.asc"); + .query_param("order", "name.asc"); then.status(200).json_body(json!([ { "optional": true, - "title": "Example secret1", + "name": "Example secret1", "help_text": "An example of a secret that is used in index.html" }, { "optional": true, - "title": "Example secret2", + "name": "Example secret2", "help_text": "An example of a secret that is used in index.html" }, { "optional": false, - "title": "Example secret3", + "name": "Example secret3", "help_text": "An example of a secret that is used in index.html" } ])); @@ -2891,17 +2922,17 @@ settings: json!([ { "optional": true, - "title": "Example secret1", + "name": "Example secret1", "help_text": "An example of a secret that is used in index.html", }, { "optional": true, - "title": "Example secret2", + "name": "Example secret2", "help_text": "An example of a secret that is used in index.html", }, { "optional": false, - "title": "Example secret3", + "name": "Example secret3", "help_text": "An example of a secret that is used in index.html" } ]) @@ -3203,16 +3234,18 @@ settings: let mut manifest = create_edge_app_manifest_for_test(vec![ Setting { + name: "asetting".to_string(), type_: SettingType::String, - title: "asetting".to_string(), + title: "atitle".to_string(), optional: false, default_value: Some("".to_string()), is_global: false, help_text: "help text".to_string(), }, Setting { + name: "nsetting".to_string(), type_: SettingType::String, - title: "nsetting".to_string(), + title: "ntitle".to_string(), optional: false, default_value: Some("".to_string()), is_global: false, @@ -3255,16 +3288,18 @@ settings: entrypoint: None, settings: vec![ Setting { + name: "asetting".to_string(), type_: SettingType::String, - title: "asetting".to_string(), + title: "atitle".to_string(), optional: false, default_value: Some("".to_string()), is_global: false, help_text: "asdf".to_string(), }, Setting { + name: "nsetting".to_string(), type_: SettingType::String, - title: "nsetting".to_string(), + title: "ntitle".to_string(), optional: false, default_value: Some("".to_string()), is_global: false, @@ -3371,16 +3406,18 @@ settings: entrypoint: None, settings: vec![ Setting { + name: "asetting".to_string(), type_: SettingType::String, - title: "asetting".to_string(), + title: "atitle".to_string(), optional: false, default_value: Some("".to_string()), is_global: false, help_text: "sdfg".to_string(), }, Setting { + name: "nsetting".to_string(), type_: SettingType::String, - title: "nsetting".to_string(), + title: "ntitle".to_string(), optional: false, default_value: Some("".to_string()), is_global: false, @@ -3477,27 +3514,29 @@ settings: // v4/edge-apps/settings?app_id=eq.{} let settings_mock_create = mock_server.mock(|when, then| { when.method(POST) - .path("/v4/edge-apps/settings") + .path("/v4.1/edge-apps/settings") .header("Authorization", "Token token") .header( "user-agent", format!("screenly-cli {}", env!("CARGO_PKG_VERSION")), ) .json_body(json!({ + "name": "ssetting", "app_id": "01H2QZ6Z8WXWNDC0KQ198XCZEW", "type": "secret", "default_value": "", - "title": "ssetting", + "title": "stitle", "optional": false, "help_text": "help text", "is_global": true })); then.status(201).json_body(json!( [{ + "name": "ssetting", "app_id": "01H2QZ6Z8WXWNDC0KQ198XCZEW", "type": "secret", "default_value": "", - "title": "ssetting", + "title": "stitle", "optional": false, "help_text": "help text", "is_global": true, @@ -3505,8 +3544,9 @@ settings: }); let setting = Setting { + name: "ssetting".to_string(), type_: SettingType::Secret, - title: "ssetting".to_string(), + title: "stitle".to_string(), optional: false, default_value: Some("".to_string()), is_global: true, diff --git a/src/commands/edge_app_manifest.rs b/src/commands/edge_app_manifest.rs index 1471104..4733c56 100644 --- a/src/commands/edge_app_manifest.rs +++ b/src/commands/edge_app_manifest.rs @@ -225,7 +225,8 @@ mod tests { homepage_url: Some("test_url".to_string()), entrypoint: Some("entrypoint.html".to_owned()), settings: vec![Setting { - title: "username".to_string(), + name: "username".to_string(), + title: "username title".to_string(), type_: SettingType::String, default_value: Some("stranger".to_string()), optional: true, @@ -250,7 +251,7 @@ settings: username: type: string default_value: stranger - title: username + title: username title optional: true help_text: An example of a setting that is used in index.html "#; @@ -272,7 +273,8 @@ settings: homepage_url: Some("test_url".to_string()), entrypoint: Some("entrypoint.html".to_owned()), settings: vec![Setting { - title: "username".to_string(), + name: "username".to_string(), + title: "username title".to_string(), type_: SettingType::String, default_value: Some("stranger".to_string()), optional: true, @@ -295,7 +297,7 @@ settings: username: type: string default_value: stranger - title: username + title: username title optional: true help_text: An example of a setting that is used in index.html "#; @@ -317,7 +319,8 @@ settings: homepage_url: Some("test_url".to_string()), entrypoint: Some("entrypoint.html".to_owned()), settings: vec![Setting { - title: "username".to_string(), + name: "username".to_string(), + title: "username title".to_string(), type_: SettingType::String, default_value: Some("stranger".to_string()), optional: true, @@ -340,7 +343,7 @@ settings: username: type: string default_value: stranger - title: username + title: username title optional: true help_text: An example of a setting that is used in index.html "#; @@ -356,7 +359,8 @@ settings: let manifest = EdgeAppManifest { app_id: Some("test_app".to_string()), settings: vec![Setting { - title: "username".to_string(), + name: "username".to_string(), + title: "username title".to_string(), type_: SettingType::String, default_value: Some("stranger".to_string()), optional: true, @@ -376,7 +380,7 @@ settings: username: type: string default_value: stranger - title: username + title: username title optional: true help_text: An example of a setting that is used in index.html "#; @@ -392,7 +396,8 @@ settings: let manifest = EdgeAppManifest { app_id: Some("test_app".to_string()), settings: vec![Setting { - title: "username".to_string(), + name: "username".to_string(), + title: "username title".to_string(), type_: SettingType::String, default_value: Some("stranger".to_string()), optional: true, @@ -416,7 +421,8 @@ settings: homepage_url: Some("test_url".to_string()), entrypoint: Some("entrypoint.html".to_owned()), settings: vec![Setting { - title: "username".to_string(), + name: "username".to_string(), + title: "username title".to_string(), type_: SettingType::String, default_value: Some("stranger".to_string()), optional: true, @@ -441,7 +447,8 @@ settings: homepage_url: Some("test_url".to_string()), entrypoint: Some("entrypoint.html".to_owned()), settings: vec![Setting { - title: "username".to_string(), + name: "username".to_string(), + title: "username title".to_string(), type_: SettingType::String, default_value: Some("stranger".to_string()), optional: true, @@ -466,7 +473,8 @@ settings: homepage_url: None, entrypoint: Some("entrypoint.html".to_owned()), settings: vec![Setting { - title: "username".to_string(), + name: "username".to_string(), + title: "username title".to_string(), type_: SettingType::String, default_value: Some("stranger".to_string()), optional: true, @@ -672,7 +680,8 @@ settings: homepage_url: Some("test_url".to_string()), entrypoint: Some("entrypoint.html".to_owned()), settings: vec![Setting { - title: "username".to_string(), + name: "username".to_string(), + title: "username title".to_string(), type_: SettingType::String, default_value: Some("stranger".to_string()), optional: true, @@ -697,7 +706,7 @@ settings: username: type: string default_value: stranger - title: username + title: username title optional: true help_text: An example of a setting that is used in index.html is_global: true @@ -717,7 +726,8 @@ settings: homepage_url: Some("test_url".to_string()), entrypoint: Some("entrypoint.html".to_owned()), settings: vec![Setting { - title: "username".to_string(), + name: "username".to_string(), + title: "username title".to_string(), type_: SettingType::String, default_value: Some("stranger".to_string()), optional: true, diff --git a/src/commands/edge_app_settings.rs b/src/commands/edge_app_settings.rs index d5bf466..23395b0 100644 --- a/src/commands/edge_app_settings.rs +++ b/src/commands/edge_app_settings.rs @@ -4,6 +4,7 @@ use std::ops::Not; use std::str::FromStr; use serde::{Deserialize, Deserializer, Serialize}; +use serde_json::Value; use strum::IntoEnumIterator; use strum_macros::{Display, EnumIter, EnumString}; @@ -32,6 +33,8 @@ pub struct Setting { pub default_value: Option, #[serde(default)] pub title: String, + #[serde(skip)] + pub name: String, pub optional: bool, #[serde( serialize_with = "serialize_help_text", @@ -50,7 +53,7 @@ where let mut map = serializer.serialize_map(Some(settings.len()))?; for setting in settings { - map.serialize_entry(&setting.title, &setting)?; + map.serialize_entry(&setting.name, &setting)?; } map.end() } @@ -62,8 +65,8 @@ where let map: HashMap = serde::Deserialize::deserialize(deserializer)?; let mut settings: Vec = map .into_iter() - .map(|(title, mut setting)| { - setting.title = title; + .map(|(name, mut setting)| { + setting.name = name; setting }) .collect(); @@ -72,12 +75,55 @@ where if setting.type_ == SettingType::Secret && setting.default_value.is_some() { return Err(serde::de::Error::custom(format!( "Setting \"{}\" is of type \"secret\" and cannot have a default value", - setting.title + setting.name ))); } } - settings.sort_by_key(|s| s.title.clone()); + settings.sort_by_key(|s| s.name.clone()); + Ok(settings) +} + +pub fn deserialize_settings_from_array<'de, D>(deserializer: D) -> Result, D::Error> +where + D: Deserializer<'de>, +{ + let map: Vec> = serde::Deserialize::deserialize(deserializer)?; + let mut settings: Vec = map + .into_iter() + .map(|setting_data| { + let mut setting = Setting::default(); + for (key, value) in setting_data { + match key.as_str() { + "type" => { + setting.type_ = deserialize_setting_type(value).unwrap(); + } + "default_value" => { + setting.default_value = value.as_str().map(|s| s.to_string()); + } + "title" => { + setting.title = value.as_str().unwrap().to_string(); + } + "optional" => { + setting.optional = value.as_bool().unwrap(); + } + "help_text" => { + setting.help_text = value.as_str().unwrap().to_string(); + } + "is_global" => { + setting.is_global = value.as_bool().unwrap(); + } + "name" => { + setting.name = value.as_str().unwrap().to_string(); + } + _ => {} + } + } + setting + }) + .collect(); + + settings.sort_by_key(|s| s.name.clone()); Ok(settings) } diff --git a/src/commands/edge_app_utils.rs b/src/commands/edge_app_utils.rs index 3289d7a..e0e075b 100644 --- a/src/commands/edge_app_utils.rs +++ b/src/commands/edge_app_utils.rs @@ -136,7 +136,7 @@ pub fn detect_changed_settings( let mut new_iter = new_settings.iter().peekable(); while let (Some(&remote_setting), Some(&new_setting)) = (remote_iter.peek(), new_iter.peek()) { - match remote_setting.title.cmp(&new_setting.title) { + match remote_setting.name.cmp(&new_setting.name) { std::cmp::Ordering::Equal => { if remote_setting != new_setting { updates.push(new_setting.clone()); @@ -191,17 +191,19 @@ mod tests { entrypoint: Some("entrypoint.html".to_owned()), settings: vec![ Setting { + name: "display_time".to_string(), type_: SettingType::String, default_value: Some("5".to_string()), - title: "display_time".to_string(), + title: "display time title".to_string(), optional: true, is_global: false, help_text: "For how long to display the map overlay every time the rover has moved to a new position.".to_string(), }, Setting { + name: "google_maps_api_key".to_string(), type_: SettingType::String, default_value: Some("6".to_string()), - title: "google_maps_api_key".to_string(), + title: "Google maps title".to_string(), optional: true, is_global: false, help_text: "Specify a commercial Google Maps API key. Required due to the app's map feature.".to_string(), @@ -217,17 +219,19 @@ mod tests { let remote_settings = vec![ Setting { + name: "display_time".to_string(), type_: SettingType::String, default_value: Some("5".to_string()), - title: "display_time".to_string(), + title: "display time title".to_string(), optional: true, is_global: false, help_text: "For how long to display the map overlay every time the rover has moved to a new position.".to_string(), }, Setting { + name: "google_maps_api_key".to_string(), type_: SettingType::String, default_value: Some("6".to_string()), - title: "google_maps_api_key".to_string(), + title: "Google maps title".to_string(), optional: true, is_global: false, help_text: "Specify a commercial Google Maps API key. Required due to the app's map feature.".to_string(), @@ -250,25 +254,28 @@ mod tests { let remote_settings = vec![ Setting { + name: "display_time".to_string(), type_: SettingType::String, default_value: Some("5".to_string()), - title: "display_time".to_string(), + title: "display time title".to_string(), optional: true, is_global: false, help_text: "For how long to display the map overlay every time the rover has moved to a new position.".to_string(), }, Setting { + name: "google_maps_api_key".to_string(), type_: SettingType::String, default_value: Some("6".to_string()), - title: "google_maps_api_key".to_string(), + title: "Google maps title".to_string(), optional: true, is_global: false, help_text: "Specify a commercial Google Maps API key. Required due to the app's map feature.".to_string(), }, Setting { + name: "new_setting".to_string(), type_: SettingType::String, default_value: Some("10".to_string()), - title: "new_setting".to_string(), + title: "new setting title".to_string(), optional: false, is_global: false, help_text: "New setting description".to_string(), @@ -291,9 +298,10 @@ mod tests { let remote_settings = vec![ Setting { + name: "display_time".to_string(), type_: SettingType::String, default_value: Some("5".to_string()), - title: "display_time".to_string(), + title: "display time title".to_string(), optional: true, is_global: false, help_text: "For how long to display the map overlay every time the rover has moved to a new position.".to_string(), @@ -307,7 +315,7 @@ mod tests { assert!(result.is_ok()); let changes = result.unwrap(); assert_eq!(changes.creates.len(), 1); - assert_eq!(changes.creates[0].title, "google_maps_api_key"); + assert_eq!(changes.creates[0].name, "google_maps_api_key"); } // TODO: Update test, when patching is implemented @@ -318,17 +326,19 @@ mod tests { let remote_settings = vec![ Setting { + name: "display_time".to_string(), type_: SettingType::String, default_value: Some("5".to_string()), - title: "display_time".to_string(), + title: "display time title".to_string(), optional: true, is_global: false, help_text: "For how long to display the map overlay every time the rover has moved to a new position.".to_string(), }, Setting { + name: "google_maps_api_key".to_string(), type_: SettingType::String, default_value: Some("7".to_string()), // Modified default value - title: "google_maps_api_key".to_string(), + title: "Google maps title".to_string(), optional: true, is_global: false, help_text: "Specify a commercial Google Maps API key. Required due to the app's map feature.".to_string(), @@ -343,7 +353,7 @@ mod tests { let changes = result.unwrap(); assert_eq!(changes.creates.len(), 0); assert_eq!(changes.updates.len(), 1); - assert_eq!(changes.updates[0].title, "google_maps_api_key"); + assert_eq!(changes.updates[0].name, "google_maps_api_key"); assert_eq!(changes.updates[0].default_value, Some("6".to_owned())); } @@ -376,9 +386,10 @@ mod tests { entrypoint: Some("entrypoint.html".to_owned()), settings: vec![ Setting { + name: "display_time".to_string(), type_: SettingType::String, default_value: Some("5".to_string()), - title: "display_time".to_string(), + title: "display time title".to_string(), optional: true, is_global: true, help_text: "For how long to display the map overlay every time the rover has moved to a new position.".to_string(), @@ -388,9 +399,10 @@ mod tests { let remote_settings = vec![ Setting { + name: "display_time".to_string(), type_: SettingType::String, default_value: Some("5".to_string()), - title: "display_time".to_string(), + title: "display time title".to_string(), optional: true, is_global: false, help_text: "For how long to display the map overlay every time the rover has moved to a new position.".to_string(), diff --git a/src/commands/mod.rs b/src/commands/mod.rs index 7f21dba..ed4f686 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -367,6 +367,7 @@ impl Formatter for EdgeAppSettings { format_value( output_type, vec![ + "Name", "Title", "Value", "Default value", @@ -375,6 +376,7 @@ impl Formatter for EdgeAppSettings { "Help text", ], vec![ + "name", "title", "value", "default_value", @@ -417,8 +419,8 @@ impl Formatter for EdgeAppSecrets { fn format(&self, output_type: OutputType) -> String { format_value( output_type, - vec!["Title", "Optional", "Help text"], - vec!["title", "optional", "help_text"], + vec!["Name", "Optional", "Help text"], + vec!["name", "optional", "help_text"], self, Some( |field_name: &str, field_value: &serde_json::Value| -> Cell {