Add container setup scripts for various services
All checks were successful
GBCI / build (push) Successful in 16m16s

- Implemented ALM container setup with Forgejo installation and systemd service configuration.
- Created Bot container setup with necessary dependencies and Node.js application installation.
- Developed Desktop container setup with XRDP and Brave browser installation.
- Established Directory container setup with Zitadel installation and service configuration.
- Added Doc Editor container setup for Collabora Online integration.
- Implemented Drive container setup with MinIO installation and service configuration.
- Created Email container setup with Stalwart Mail installation and service configuration.
- Developed Meeting container setup with LiveKit and TURN server configuration.
- Added Proxy container setup with Caddy installation and service configuration.
- Implemented System container setup for general bots with service configuration.
- Created Table Editor container setup with NocoDB installation and service configuration.
- Developed Tables container setup with PostgreSQL installation and configuration.
- Added Webmail container setup with Roundcube installation and service configuration.
- Included prompt guidelines for container setup scripts.
This commit is contained in:
Rodrigo Rodriguez (Pragmatismo) 2025-07-14 16:40:21 -03:00
parent d4697a6a93
commit 7131911313
2 changed files with 151 additions and 134 deletions

View file

@ -24,6 +24,8 @@ async fn main() -> std::io::Result<()> {
let json = FIND "users", "name=John" let json = FIND "users", "name=John"
let x=2 let x=2
let text = GET "example.com" let text = GET "example.com"
let nome = "table"
let d = FIND nome, "car=2"
"#; "#;
match script_service.compile(script) { match script_service.compile(script) {

View file

@ -20,140 +20,156 @@ impl ScriptService {
engine.set_allow_looping(true); engine.set_allow_looping(true);
// Register custom syntax for FOR EACH loop // Register custom syntax for FOR EACH loop
engine.register_custom_syntax( engine
&["FOR", "EACH", "$ident$", "in", "$expr$", "$block$"], .register_custom_syntax(
false, // Not a statement &["FOR", "EACH", "$ident$", "in", "$expr$", "$block$"],
|context, inputs| { false, // Not a statement
// Simple implementation - just return unit for now |context, inputs| {
Ok(Dynamic::UNIT) // Simple implementation - just return unit for now
}, Ok(Dynamic::UNIT)
).unwrap(); },
)
.unwrap();
// FIND command: FIND "table", "filter" // FIND command: FIND "table", "filter"
engine.register_custom_syntax( engine
&["FIND", "$expr$", ",", "$expr$"], .register_custom_syntax(
false, // Expression, not statement &["FIND", "$expr$", ",", "$expr$"],
|context, inputs| { false, // Expression, not statement
let table_name = context.eval_expression_tree(&inputs[0])?; |context, inputs| {
let filter = context.eval_expression_tree(&inputs[1])?; let table_name = context.eval_expression_tree(&inputs[0])?;
let filter = context.eval_expression_tree(&inputs[1])?;
let table_str = table_name.to_string(); let table_str = table_name.to_string();
let filter_str = filter.to_string(); let filter_str = filter.to_string();
let result = json!({ let result = json!({
"command": "find", "command": "find",
"table": table_str, "table": table_str,
"filter": filter_str, "filter": filter_str,
"results": [] "results": []
}); });
Ok(Dynamic::from(result.to_string())) println!("SET executed: {}", result.to_string());
}, Ok(Dynamic::from(result.to_string()))
).unwrap(); },
)
.unwrap();
// SET command: SET "table", "key", "value" // SET command: SET "table", "key", "value"
engine.register_custom_syntax( engine
&["SET", "$expr$", ",", "$expr$", ",", "$expr$"], .register_custom_syntax(
true, // Statement &["SET", "$expr$", ",", "$expr$", ",", "$expr$"],
|context, inputs| { true, // Statement
let table_name = context.eval_expression_tree(&inputs[0])?; |context, inputs| {
let key_value = context.eval_expression_tree(&inputs[1])?; let table_name = context.eval_expression_tree(&inputs[0])?;
let value = context.eval_expression_tree(&inputs[2])?; let key_value = context.eval_expression_tree(&inputs[1])?;
let value = context.eval_expression_tree(&inputs[2])?;
let table_str = table_name.to_string(); let table_str = table_name.to_string();
let key_str = key_value.to_string(); let key_str = key_value.to_string();
let value_str = value.to_string(); let value_str = value.to_string();
let result = json!({ let result = json!({
"command": "set", "command": "set",
"status": "success", "status": "success",
"table": table_str, "table": table_str,
"key": key_str, "key": key_str,
"value": value_str "value": value_str
}); });
println!("SET executed: {}", result.to_string()); println!("SET executed: {}", result.to_string());
Ok(Dynamic::UNIT) Ok(Dynamic::UNIT)
}, },
).unwrap(); )
.unwrap();
// GET command: GET "url" // GET command: GET "url"
engine.register_custom_syntax( engine
&["GET", "$expr$"], .register_custom_syntax(
false, // Expression, not statement &["GET", "$expr$"],
|context, inputs| { false, // Expression, not statement
let url = context.eval_expression_tree(&inputs[0])?; |context, inputs| {
let url_str = url.to_string(); let url = context.eval_expression_tree(&inputs[0])?;
let url_str = url.to_string();
Ok(format!("Content from {}", url_str).into())
}, Ok(format!("Content from {}", url_str).into())
).unwrap(); },
)
.unwrap();
// CREATE SITE command: CREATE SITE "name", "company", "website", "template", "prompt" // CREATE SITE command: CREATE SITE "name", "company", "website", "template", "prompt"
engine.register_custom_syntax( engine
&["CREATE", "SITE", "$expr$", ",", "$expr$", ",", "$expr$", ",", "$expr$", ",", "$expr$"], .register_custom_syntax(
true, // Statement &[
|context, inputs| { "CREATE", "SITE", "$expr$", ",", "$expr$", ",", "$expr$", ",", "$expr$", ",",
if inputs.len() < 5 { "$expr$",
return Err("Not enough arguments for CREATE SITE".into()); ],
} true, // Statement
|context, inputs| {
if inputs.len() < 5 {
return Err("Not enough arguments for CREATE SITE".into());
}
let name = context.eval_expression_tree(&inputs[0])?; let name = context.eval_expression_tree(&inputs[0])?;
let company = context.eval_expression_tree(&inputs[1])?; let company = context.eval_expression_tree(&inputs[1])?;
let website = context.eval_expression_tree(&inputs[2])?; let website = context.eval_expression_tree(&inputs[2])?;
let template = context.eval_expression_tree(&inputs[3])?; let template = context.eval_expression_tree(&inputs[3])?;
let prompt = context.eval_expression_tree(&inputs[4])?; let prompt = context.eval_expression_tree(&inputs[4])?;
let result = json!({ let result = json!({
"command": "create_site", "command": "create_site",
"name": name.to_string(), "name": name.to_string(),
"company": company.to_string(), "company": company.to_string(),
"website": website.to_string(), "website": website.to_string(),
"template": template.to_string(), "template": template.to_string(),
"prompt": prompt.to_string() "prompt": prompt.to_string()
}); });
println!("CREATE SITE executed: {}", result.to_string()); println!("CREATE SITE executed: {}", result.to_string());
Ok(Dynamic::UNIT) Ok(Dynamic::UNIT)
}, },
).unwrap(); )
.unwrap();
// CREATE DRAFT command: CREATE DRAFT "to", "subject", "body" // CREATE DRAFT command: CREATE DRAFT "to", "subject", "body"
engine.register_custom_syntax( engine
&["CREATE", "DRAFT", "$expr$", ",", "$expr$", ",", "$expr$"], .register_custom_syntax(
true, // Statement &["CREATE", "DRAFT", "$expr$", ",", "$expr$", ",", "$expr$"],
|context, inputs| { true, // Statement
if inputs.len() < 3 { |context, inputs| {
return Err("Not enough arguments for CREATE DRAFT".into()); if inputs.len() < 3 {
} return Err("Not enough arguments for CREATE DRAFT".into());
}
let to = context.eval_expression_tree(&inputs[0])?; let to = context.eval_expression_tree(&inputs[0])?;
let subject = context.eval_expression_tree(&inputs[1])?; let subject = context.eval_expression_tree(&inputs[1])?;
let body = context.eval_expression_tree(&inputs[2])?; let body = context.eval_expression_tree(&inputs[2])?;
let result = json!({ let result = json!({
"command": "create_draft", "command": "create_draft",
"to": to.to_string(), "to": to.to_string(),
"subject": subject.to_string(), "subject": subject.to_string(),
"body": body.to_string() "body": body.to_string()
}); });
println!("CREATE DRAFT executed: {}", result.to_string()); println!("CREATE DRAFT executed: {}", result.to_string());
Ok(Dynamic::UNIT) Ok(Dynamic::UNIT)
}, },
).unwrap(); )
.unwrap();
// PRINT command // PRINT command
engine.register_custom_syntax( engine
&["PRINT", "$expr$"], .register_custom_syntax(
true, // Statement &["PRINT", "$expr$"],
|context, inputs| { true, // Statement
let value = context.eval_expression_tree(&inputs[0])?; |context, inputs| {
println!("{}", value); let value = context.eval_expression_tree(&inputs[0])?;
Ok(Dynamic::UNIT) println!("{}", value);
}, Ok(Dynamic::UNIT)
).unwrap(); },
)
.unwrap();
// Register web service functions // Register web service functions
engine.register_fn("web_get", |url: &str| { engine.register_fn("web_get", |url: &str| format!("Response from {}", url));
format!("Response from {}", url)
});
ScriptService { ScriptService {
engine, engine,
@ -165,17 +181,17 @@ impl ScriptService {
fn preprocess_basic_script(&self, script: &str) -> String { fn preprocess_basic_script(&self, script: &str) -> String {
let mut result = String::new(); let mut result = String::new();
let mut in_block = false; let mut in_block = false;
for line in script.lines() { for line in script.lines() {
let trimmed = line.trim(); let trimmed = line.trim();
// Skip empty lines and comments // Skip empty lines and comments
if trimmed.is_empty() || trimmed.starts_with("//") || trimmed.starts_with("REM") { if trimmed.is_empty() || trimmed.starts_with("//") || trimmed.starts_with("REM") {
result.push_str(line); result.push_str(line);
result.push('\n'); result.push('\n');
continue; continue;
} }
// Track block state // Track block state
if trimmed.contains('{') { if trimmed.contains('{') {
in_block = true; in_block = true;
@ -183,11 +199,11 @@ impl ScriptService {
if trimmed.contains('}') { if trimmed.contains('}') {
in_block = false; in_block = false;
} }
// Check if line starts with our custom commands (these don't need semicolons) // Check if line starts with our custom commands (these don't need semicolons)
let custom_commands = ["SET", "CREATE", "PRINT", "FOR", "FIND", "GET"]; let custom_commands = ["SET", "CREATE", "PRINT", "FOR", "FIND", "GET"];
let is_custom_command = custom_commands.iter().any(|&cmd| trimmed.starts_with(cmd)); let is_custom_command = custom_commands.iter().any(|&cmd| trimmed.starts_with(cmd));
if is_custom_command || in_block { if is_custom_command || in_block {
// Custom commands and block content don't need semicolons // Custom commands and block content don't need semicolons
result.push_str(line); result.push_str(line);
@ -200,17 +216,16 @@ impl ScriptService {
} }
result.push('\n'); result.push('\n');
} }
result result
} }
pub fn compile(&self, script: &str) -> Result<rhai::AST, Box<EvalAltResult>> { pub fn compile(&self, script: &str) -> Result<rhai::AST, Box<EvalAltResult>> {
let processed_script = self.preprocess_basic_script(script); let processed_script = self.preprocess_basic_script(script);
match self.engine.compile(&processed_script) { match self.engine.compile(&processed_script) {
Ok(ast) => Ok(ast), Ok(ast) => Ok(ast),
Err(parse_error) => Err(Box::new(EvalAltResult::from(parse_error))), Err(parse_error) => Err(Box::new(EvalAltResult::from(parse_error))),
}
} }
}
pub fn run(&self, ast: &rhai::AST) -> Result<Dynamic, Box<EvalAltResult>> { pub fn run(&self, ast: &rhai::AST) -> Result<Dynamic, Box<EvalAltResult>> {
self.engine.eval_ast(ast) self.engine.eval_ast(ast)
@ -239,7 +254,7 @@ mod tests {
#[test] #[test]
fn test_basic_script_without_semicolons() { fn test_basic_script_without_semicolons() {
let service = ScriptService::new(); let service = ScriptService::new();
// Test BASIC-style script without semicolons // Test BASIC-style script without semicolons
let script = r#" let script = r#"
json = FIND "users", "name=John" json = FIND "users", "name=John"
@ -249,7 +264,7 @@ CREATE SITE "mysite", "My Company", "mycompany.com", "basic", "Create a professi
CREATE DRAFT "client@example.com", "Project Update", "Here's the latest update..." CREATE DRAFT "client@example.com", "Project Update", "Here's the latest update..."
PRINT "Script completed successfully" PRINT "Script completed successfully"
"#; "#;
let result = service.execute_basic_script(script); let result = service.execute_basic_script(script);
assert!(result.is_ok()); assert!(result.is_ok());
} }
@ -257,7 +272,7 @@ PRINT "Script completed successfully"
#[test] #[test]
fn test_preprocessing() { fn test_preprocessing() {
let service = ScriptService::new(); let service = ScriptService::new();
let script = r#" let script = r#"
json = FIND "users", "name=John" json = FIND "users", "name=John"
SET "users", "name=John", "age=30" SET "users", "name=John", "age=30"
@ -267,9 +282,9 @@ if x > 10 {
PRINT "Large number" PRINT "Large number"
} }
"#; "#;
let processed = service.preprocess_basic_script(script); let processed = service.preprocess_basic_script(script);
// Should add semicolons to regular statements but not custom commands // Should add semicolons to regular statements but not custom commands
assert!(processed.contains("let x = 42;")); assert!(processed.contains("let x = 42;"));
assert!(processed.contains("json = FIND")); assert!(processed.contains("json = FIND"));
@ -280,7 +295,7 @@ if x > 10 {
#[test] #[test]
fn test_individual_commands() { fn test_individual_commands() {
let service = ScriptService::new(); let service = ScriptService::new();
let commands = vec![ let commands = vec![
r#"SET "users", "name=John", "age=30""#, r#"SET "users", "name=John", "age=30""#,
r#"CREATE SITE "mysite", "My Company", "mycompany.com", "basic", "Create a professional site""#, r#"CREATE SITE "mysite", "My Company", "mycompany.com", "basic", "Create a professional site""#,
@ -297,15 +312,15 @@ if x > 10 {
#[test] #[test]
fn test_block_statements() { fn test_block_statements() {
let service = ScriptService::new(); let service = ScriptService::new();
let script = r#" let script = r#"
if true { if true {
PRINT "Inside block" PRINT "Inside block"
PRINT "Another statement" PRINT "Another statement"
} }
"#; "#;
let result = service.execute_basic_script(script); let result = service.execute_basic_script(script);
assert!(result.is_ok()); assert!(result.is_ok());
} }
} }