Repository: CSML-by-Clevy/csml-engine (rust)

Issue:
HTTP basic auth
**Is your feature request related to a problem? Please describe.**
Linked to #166 , it would be nice to be able to automatically perform HTTP basic auth with a specific header method, instead of having to do `HTTP().set({Authorization: "Basic base64(username:password)"}).get().send()`

**Describe the solution you'd like**
`HTTP().auth(username, password).get().send()`


Pull request:
add basic auth
Fixes #169 

## Proposed Changes

- add HTTP method  auth(user, pwd)


Patch:
diff --git a/csml_interpreter/CSML/examples/hello_world.csml b/csml_interpreter/CSML/examples/hello_world.csml
index 59150541..342051db 100644
--- a/csml_interpreter/CSML/examples/hello_world.csml
+++ b/csml_interpreter/CSML/examples/hello_world.csml
@@ -1,28 +1,5 @@
-// start:
-
-//     say "Hello World 😆"
-
-//     goto end
-
-
-
 start:
 
-    remember test = 0
-
-    goto toto
-
-
-toto:
-    do test = test + 1
-    // say "in toto test == {{test}}"
-
-    goto tata
-
-tata: 
-    // say "in tata"
-    if (test < 2) {
-        previous step
-    }
+    say "Hello World 😆"
 
-    goto end
\ No newline at end of file
+    goto end
diff --git a/csml_interpreter/src/data/primitive/object.rs b/csml_interpreter/src/data/primitive/object.rs
index 7ad6e1a4..9fc4ef8b 100644
--- a/csml_interpreter/src/data/primitive/object.rs
+++ b/csml_interpreter/src/data/primitive/object.rs
@@ -35,6 +35,10 @@ lazy_static! {
             "set",
             (PrimitiveObject::set as PrimitiveMethod, Right::Read),
         );
+        map.insert(
+            "auth",
+            (PrimitiveObject::auth as PrimitiveMethod, Right::Read),
+        );
         map.insert(
             "query",
             (PrimitiveObject::query as PrimitiveMethod, Right::Read),
@@ -350,6 +354,74 @@ impl PrimitiveObject {
         Ok(result)
     }
 
+    fn auth(
+        object: &mut PrimitiveObject,
+        args: &HashMap<String, Literal>,
+        data: &mut Data,
+        interval: Interval,
+        _content_type: &str,
+    ) -> Result<Literal, ErrorInfo> {
+        let usage = "auth(username, password) => http object";
+
+        if args.len() < 2 {
+            return Err(gen_error_info(
+                Position::new(interval, &data.context.flow,),
+                format!("usage: {}", usage),
+            ));
+        }
+
+        let username = match args.get("arg0") {
+            Some(lit) => Literal::get_value::<String>(
+                &lit.primitive,
+                &data.context.flow,
+                lit.interval,
+                format!("usage: {}", usage),
+            )?,
+            _ => {
+                return Err(gen_error_info(
+                    Position::new(interval, &data.context.flow,),
+                    format!("usage: {}", usage),
+                ));
+            }
+        };
+
+        let password = match args.get("arg1") {
+            Some(lit) => Literal::get_value::<String>(
+                &lit.primitive,
+                &data.context.flow,
+                lit.interval,
+                format!("usage: {}", usage),
+            )?,
+            _ => {
+                return Err(gen_error_info(
+                    Position::new(interval, &data.context.flow,),
+                    format!("usage: {}", usage),
+                ));
+            }
+        };
+
+        let user_password = format!("{}:{}", username, password);
+        let authorization = format!("Basic {}", base64::encode(user_password.as_bytes()));
+
+        let mut object = object.to_owned();
+
+        let mut header = HashMap::new();
+        header.insert(
+            "Authorization".to_owned(), 
+            PrimitiveString::get_literal(&authorization, interval)
+        );
+        let literal = PrimitiveObject::get_literal( &header, interval);
+
+        insert_to_object(&header, &mut object, "header", &data.context.flow, &literal);
+
+        let mut result = PrimitiveObject::get_literal(&object.value, interval);
+
+        result.set_content_type("http");
+
+        Ok(result)
+
+    }
+
     fn query(
         object: &mut PrimitiveObject,
         args: &HashMap<String, Literal>,
@@ -1796,8 +1868,6 @@ fn insert_to_object(
                 for (key, value) in src.iter() {
                     tmp.insert(key.to_owned(), value.to_owned());
                 }
-            } else {
-                unreachable!();
             }
         })
         .or_insert_with(|| literal.to_owned());


Test patch:
diff --git a/csml_interpreter/CSML/basic_test/stdlib/http.csml b/csml_interpreter/CSML/basic_test/stdlib/http.csml
index 2e309a10..8d530e54 100644
--- a/csml_interpreter/CSML/basic_test/stdlib/http.csml
+++ b/csml_interpreter/CSML/basic_test/stdlib/http.csml
@@ -102,4 +102,10 @@ post_1:
 		"userId":"1",
 	}).send()
 	goto end
-	
\ No newline at end of file
+	
+
+auth_0:
+	do http = HTTP("https://clevy.io")
+
+	say http.auth("user", "passwd").get()
+	goto end
\ No newline at end of file
diff --git a/csml_interpreter/tests/http.rs b/csml_interpreter/tests/http.rs
index 6802ce17..7b7f0a09 100644
--- a/csml_interpreter/tests/http.rs
+++ b/csml_interpreter/tests/http.rs
@@ -516,3 +516,37 @@ fn http_post_0() {
 
     assert_eq!(v1, v2)
 }
+
+
+
+#[test]
+fn http_auth_0() {
+    let data = r#"{
+        "memories":[],
+        "messages":[
+            {
+                "content":{
+                    "header":{
+                        "accept":"application/json,text/*",
+                        "content-type":"application/json",
+                        "User-Agent": "csml/v1",
+                        "Authorization": "Basic dXNlcjpwYXNzd2Q="
+                    },
+                    "method":"get",
+                    "query":{},
+                    "url":"https://clevy.io"
+                },
+                "content_type":"http"
+            }
+        ]}"#;
+    let msg = format_message(
+        Event::new("payload", "", serde_json::json!({})),
+        Context::new(HashMap::new(), HashMap::new(), None, None, "auth_0", "flow"),
+        "CSML/basic_test/stdlib/http.csml",
+    );
+
+    let v1: Value = message_to_json_value(msg);
+    let v2: Value = serde_json::from_str(data).unwrap();
+
+    assert_eq!(v1, v2)
+}