Files
windmill/backend/windmill-common/src/scripts.rs
T
Ruben Fiszel 751dca0d28 feat: add favorite/star + remove flows/scripts page in favor of unified home page (#968)
* favorites

* favorites

* favorites

* feat(frontend): add favorite + refactor homepage
2022-11-30 00:15:43 +01:00

283 lines
7.2 KiB
Rust

/*
* Author: Ruben Fiszel
* Copyright: Windmill Labs, Inc 2022
* This file and its contents are licensed under the AGPLv3 License.
* Please see the included NOTICE for copyright information and
* LICENSE-AGPL for a copy of the license.
*/
use std::{
fmt::Display,
hash::{Hash, Hasher},
};
use serde::de::Error as _;
use serde::{ser::SerializeSeq, Deserialize, Deserializer, Serialize};
use serde_json::to_string_pretty;
use crate::utils::StripPath;
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Hash)]
#[cfg_attr(feature = "sqlx", derive(sqlx::Type))]
#[cfg_attr(
feature = "sqlx",
sqlx(type_name = "SCRIPT_LANG", rename_all = "lowercase")
)]
#[serde(rename_all(serialize = "lowercase", deserialize = "lowercase"))]
pub enum ScriptLang {
Deno,
Python3,
Go,
Bash,
}
impl ScriptLang {
pub fn as_str(&self) -> &'static str {
match self {
ScriptLang::Deno => "deno",
ScriptLang::Python3 => "python3",
ScriptLang::Go => "go",
ScriptLang::Bash => "bash",
}
}
}
#[derive(PartialEq, Debug, Hash, Clone, Copy)]
#[cfg_attr(feature = "sqlx", derive(sqlx::Type))]
#[cfg_attr(feature = "sqlx", sqlx(transparent))]
pub struct ScriptHash(pub i64);
#[derive(PartialEq)]
#[cfg_attr(feature = "sqlx", derive(sqlx::Type))]
#[cfg_attr(feature = "sqlx", sqlx(transparent))]
pub struct ScriptHashes(pub Vec<i64>);
impl Display for ScriptHash {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", to_hex_string(&self.0))
}
}
impl Serialize for ScriptHash {
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_str(to_hex_string(&self.0).as_str())
}
}
impl<'de> Deserialize<'de> for ScriptHash {
fn deserialize<D>(deserializer: D) -> std::result::Result<ScriptHash, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
let i = to_i64(&s).map_err(|e| D::Error::custom(format!("{}", e)))?;
Ok(ScriptHash(i))
}
}
impl Serialize for ScriptHashes {
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut seq = serializer.serialize_seq(Some(self.0.len()))?;
for element in &self.0 {
seq.serialize_element(&ScriptHash(*element))?;
}
seq.end()
}
}
#[derive(Serialize, Deserialize, Debug, Hash)]
#[cfg_attr(feature = "sqlx", derive(sqlx::Type))]
#[cfg_attr(
feature = "sqlx",
sqlx(type_name = "SCRIPT_KIND", rename_all = "lowercase")
)]
#[serde(rename_all = "lowercase")]
pub enum ScriptKind {
Trigger,
Failure,
Script,
Approval,
}
#[derive(Serialize)]
#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
pub struct Script {
pub workspace_id: String,
pub hash: ScriptHash,
pub path: String,
pub parent_hashes: Option<ScriptHashes>,
pub summary: String,
pub description: String,
pub content: String,
pub created_by: String,
pub created_at: chrono::DateTime<chrono::Utc>,
pub archived: bool,
pub schema: Option<Schema>,
pub deleted: bool,
pub is_template: bool,
pub extra_perms: serde_json::Value,
pub lock: Option<String>,
pub lock_error_logs: Option<String>,
pub language: ScriptLang,
pub kind: ScriptKind,
}
#[derive(Serialize)]
#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
pub struct ListableScript {
pub workspace_id: String,
pub hash: ScriptHash,
pub path: String,
pub parent_hashes: Option<ScriptHashes>,
pub summary: String,
pub description: String,
pub created_by: String,
pub created_at: chrono::DateTime<chrono::Utc>,
pub archived: bool,
pub deleted: bool,
pub is_template: bool,
pub extra_perms: serde_json::Value,
pub lock_error_logs: Option<String>,
pub language: ScriptLang,
pub kind: ScriptKind,
pub starred: bool,
}
#[derive(Serialize, Deserialize, Debug)]
#[cfg_attr(feature = "sqlx", derive(sqlx::Type))]
#[cfg_attr(feature = "sqlx", sqlx)]
#[cfg_attr(feature = "sqlx", sqlx(transparent))]
#[serde(transparent)]
pub struct Schema(pub serde_json::Value);
impl Hash for Schema {
fn hash<H: Hasher>(&self, state: &mut H) {
if let Ok(s) = to_string_pretty(&self.0) {
s.hash(state);
}
}
}
#[derive(Serialize, Deserialize, Hash)]
pub struct NewScript {
pub path: String,
pub parent_hash: Option<ScriptHash>,
pub summary: String,
pub description: String,
pub content: String,
pub schema: Option<Schema>,
pub is_template: Option<bool>,
pub lock: Option<Vec<String>>,
pub language: ScriptLang,
pub kind: Option<ScriptKind>,
}
#[derive(Deserialize)]
pub struct ListScriptQuery {
pub path_start: Option<String>,
pub path_exact: Option<String>,
pub created_by: Option<String>,
pub first_parent_hash: Option<ScriptHash>,
pub last_parent_hash: Option<ScriptHash>,
pub parent_hash: Option<ScriptHash>,
pub show_archived: Option<bool>,
pub order_by: Option<String>,
pub order_desc: Option<bool>,
pub is_template: Option<bool>,
pub kind: Option<String>,
pub starred_only: Option<bool>,
}
pub fn to_i64(s: &str) -> crate::error::Result<i64> {
let v = hex::decode(s)?;
let nb: u64 = u64::from_be_bytes(
v[0..8]
.try_into()
.map_err(|_| hex::FromHexError::InvalidStringLength)?,
);
Ok(nb as i64)
}
pub fn to_hex_string(i: &i64) -> String {
hex::encode(i.to_be_bytes())
}
#[cfg(feature = "reqwest")]
pub async fn get_hub_script_by_path(
email: Option<String>,
username: String,
path: StripPath,
http_client: reqwest::Client,
host: String,
) -> crate::error::Result<String> {
use crate::{
error::{to_anyhow, Error},
utils::http_get_from_hub,
};
let path = path
.to_path()
.strip_prefix("hub/")
.ok_or_else(|| Error::BadRequest("Impossible to remove prefix hex".to_string()))?;
let content = http_get_from_hub(
http_client,
&format!("https://hub.windmill.dev/raw/{path}.ts"),
email,
username,
host,
true,
)
.await?
.text()
.await
.map_err(to_anyhow)?;
Ok(content)
}
#[cfg(feature = "reqwest")]
pub async fn get_full_hub_script_by_path(
email: Option<String>,
username: String,
path: StripPath,
http_client: reqwest::Client,
host: String,
) -> crate::error::Result<HubScript> {
use crate::{
error::{to_anyhow, Error},
utils::http_get_from_hub,
};
let path = path
.to_path()
.strip_prefix("hub/")
.ok_or_else(|| Error::BadRequest("Impossible to remove prefix hex".to_string()))?;
let value = http_get_from_hub(
http_client,
&format!("https://hub.windmill.dev/raw2/{path}"),
email,
username,
host,
true,
)
.await?
.json::<HubScript>()
.await
.map_err(to_anyhow)?;
Ok(value)
}
#[derive(Deserialize, Serialize)]
pub struct HubScript {
pub content: String,
pub lockfile: Option<String>,
pub language: ScriptLang,
pub schema: serde_json::Value,
pub summary: Option<String>,
}