Variables under Environment, and render all props

This commit is contained in:
Gregory Schier
2023-10-28 11:29:29 -07:00
parent d0387bdf76
commit 3ad132d77d
17 changed files with 263 additions and 275 deletions

View File

@@ -16,7 +16,7 @@ use reqwest::redirect::Policy;
use serde::Serialize;
use sqlx::migrate::Migrator;
use sqlx::sqlite::SqlitePoolOptions;
use sqlx::types::{Json, JsonValue};
use sqlx::types::Json;
use sqlx::{Pool, Sqlite};
use std::collections::HashMap;
use std::env::current_dir;
@@ -81,14 +81,10 @@ async fn actually_send_ephemeral_request(
pool: &Pool<Sqlite>,
) -> Result<models::HttpResponse, String> {
let start = std::time::Instant::now();
let environment = models::get_environment(environment_id, pool).await.ok();
let environment_ref = environment.as_ref();
// TODO: Use active environment
let mut url_string = match environment {
Some(e) => render::render(&request.url, e.clone()),
None => request.url.to_string(),
};
let mut url_string = render::render(&request.url, environment.as_ref());
if !url_string.starts_with("http://") && !url_string.starts_with("https://") {
url_string = format!("http://{}", url_string);
@@ -110,57 +106,54 @@ async fn actually_send_ephemeral_request(
if h.name.is_empty() && h.value.is_empty() {
continue;
}
if !h.enabled {
continue;
}
let header_name = match HeaderName::from_bytes(h.name.as_bytes()) {
let name = render::render(&h.name, environment_ref);
let value = render::render(&h.value, environment_ref);
let header_name = match HeaderName::from_bytes(name.as_bytes()) {
Ok(n) => n,
Err(e) => {
eprintln!("Failed to create header name: {}", e);
continue;
}
};
let header_value = match HeaderValue::from_str(h.value.as_str()) {
let header_value = match HeaderValue::from_str(value.as_str()) {
Ok(n) => n,
Err(e) => {
eprintln!("Failed to create header value: {}", e);
continue;
}
};
headers.insert(header_name, header_value);
}
if let Some(b) = &request.authentication_type {
let empty_value = &serde_json::to_value("").unwrap();
let a = request.authentication.0;
if b == "basic" {
let a = request.authentication.0;
let auth = format!(
"{}:{}",
a.get("username")
.unwrap_or(empty_value)
.as_str()
.unwrap_or(""),
a.get("password")
.unwrap_or(empty_value)
.as_str()
.unwrap_or(""),
);
let raw_username = a.get("username").unwrap_or(empty_value).as_str().unwrap_or("");
let raw_password = a.get("password").unwrap_or(empty_value).as_str().unwrap_or("");
let username = render::render(raw_username, environment_ref);
let password = render::render(raw_password, environment_ref);
let auth = format!( "{username}:{password}");
let encoded = base64::engine::general_purpose::STANDARD_NO_PAD.encode(auth);
headers.insert(
"Authorization",
HeaderValue::from_str(&format!("Basic {}", encoded)).unwrap(),
);
} else if b == "bearer" {
let token = request
.authentication
.0
.get("token")
.unwrap_or(empty_value)
.as_str()
.unwrap_or("");
let raw_token = a.get("token").unwrap_or(empty_value).as_str().unwrap_or("");
let token = render::render(raw_token, environment_ref);
headers.insert(
"Authorization",
HeaderValue::from_str(&format!("Bearer {}", token)).unwrap(),
HeaderValue::from_str(&format!("Bearer {token}")).unwrap(),
);
}
}
@@ -170,7 +163,10 @@ async fn actually_send_ephemeral_request(
let builder = client.request(m, url_string.to_string()).headers(headers);
let sendable_req_result = match (request.body, request.body_type) {
(Some(b), Some(_)) => builder.body(b).build(),
(Some(raw_body), Some(_)) => {
let body = render::render(&raw_body, environment_ref);
builder.body(body).build()
},
_ => builder.build(),
};
@@ -341,8 +337,8 @@ async fn create_environment(
db_instance: State<'_, Mutex<Pool<Sqlite>>>,
) -> Result<models::Environment, String> {
let pool = &*db_instance.lock().await;
let data: HashMap<String, JsonValue> = HashMap::new();
let created_environment = models::create_environment(workspace_id, name, data, pool)
let variables = Vec::new();
let created_environment = models::create_environment(workspace_id, name, variables, pool)
.await
.expect("Failed to create environment");
@@ -418,7 +414,7 @@ async fn update_environment(
let updated_environment = models::update_environment(
environment.id.as_str(),
environment.name.as_str(),
environment.data.0,
environment.variables.0,
pool,
)
.await

View File

@@ -27,7 +27,30 @@ pub struct Environment {
pub created_at: NaiveDateTime,
pub updated_at: NaiveDateTime,
pub name: String,
pub data: Json<HashMap<String, JsonValue>>,
pub variables: Json<Vec<EnvironmentVariable>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct EnvironmentVariable {
#[serde(default)]
pub enabled: bool,
pub name: String,
pub value: String,
}
#[derive(sqlx::FromRow, Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Variable {
pub id: String,
pub workspace_id: String,
pub environment_id: String,
pub model: String,
pub created_at: NaiveDateTime,
pub updated_at: NaiveDateTime,
pub name: String,
pub value: String,
pub sort_priority: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
@@ -213,7 +236,7 @@ pub async fn find_environments(
Environment,
r#"
SELECT id, workspace_id, model, created_at, updated_at, name,
data AS "data!: Json<HashMap<String, JsonValue>>"
variables AS "variables!: sqlx::types::Json<Vec<EnvironmentVariable>>"
FROM environments
WHERE workspace_id = ?
"#,
@@ -226,26 +249,21 @@ pub async fn find_environments(
pub async fn create_environment(
workspace_id: &str,
name: &str,
data: HashMap<String, JsonValue>,
variables: Vec<EnvironmentVariable>,
pool: &Pool<Sqlite>,
) -> Result<Environment, sqlx::Error> {
let id = generate_id(Some("en"));
let data_json = Json(data);
let trimmed_name = name.trim();
let variables_json = Json(variables);
sqlx::query!(
r#"
INSERT INTO environments (
id,
workspace_id,
name,
data
)
INSERT INTO environments (id, workspace_id, name, variables)
VALUES (?, ?, ?, ?)
"#,
id,
workspace_id,
trimmed_name,
data_json,
variables_json,
)
.execute(pool)
.await?;
@@ -270,18 +288,18 @@ pub async fn delete_environment(id: &str, pool: &Pool<Sqlite>) -> Result<Environ
pub async fn update_environment(
id: &str,
name: &str,
data: HashMap<String, JsonValue>,
variables: Vec<EnvironmentVariable>,
pool: &Pool<Sqlite>,
) -> Result<Environment, sqlx::Error> {
let json_data = Json(data);
let variables_json = Json(variables);
sqlx::query!(
r#"
UPDATE environments
SET (name, data, updated_at) = (?, ?, CURRENT_TIMESTAMP)
SET (name, variables, updated_at) = (?, ?, CURRENT_TIMESTAMP)
WHERE id = ?;
"#,
name,
json_data,
variables_json,
id,
)
.execute(pool)
@@ -300,7 +318,7 @@ pub async fn get_environment(id: &str, pool: &Pool<Sqlite>) -> Result<Environmen
created_at,
updated_at,
name,
data AS "data!: Json<HashMap<String, JsonValue>>"
variables AS "variables!: sqlx::types::Json<Vec<EnvironmentVariable>>"
FROM environments
WHERE id = ?
"#,

View File

@@ -1,23 +1,26 @@
use crate::models::Environment;
use std::collections::HashMap;
use tauri::regex::Regex;
use crate::models::Environment;
pub fn render(template: &str, environment: Option<&Environment>) -> String {
match environment {
Some(environment) => render_with_environment(template, environment),
None => template.to_string(),
}
}
fn render_with_environment(template: &str, environment: &Environment) -> String {
let mut map = HashMap::new();
let variables = &environment.variables.0;
for variable in variables {
map.insert(variable.name.as_str(), variable.value.as_str());
}
pub fn render(template: &str, environment: Environment) -> String {
let variables = environment.data;
Regex::new(r"\$\{\[\s*([^]\s]+)\s*]}")
.expect("Failed to create regex")
.replace(template, |caps: &tauri::regex::Captures| {
let key = caps.get(1).unwrap().as_str();
match variables.get(key) {
Some(v) => {
if v.is_string() {
v.as_str().expect("Should be string").to_string()
} else {
v.to_string()
}
}
None => "".to_string(),
}
map.get(key).unwrap_or(&"")
})
.to_string()
}