use crate::{db_connectors::DbConversation, encrypt::encrypt_data, Client, EngineError};
use bson::{doc, Bson};
use chrono::SecondsFormat;
fn format_conversation_struct(
conversation: bson::ordered::OrderedDocument,
) -> Result<DbConversation, EngineError> {
Ok(DbConversation {
id: conversation.get_object_id("_id").unwrap().to_hex(), client: bson::from_bson(conversation.get("client").unwrap().to_owned())?,
flow_id: conversation.get_str("flow_id").unwrap().to_owned(), step_id: conversation.get_str("step_id").unwrap().to_owned(), metadata: bson::from_bson(conversation.get("metadata").unwrap().to_owned())?, status: conversation.get_str("status").unwrap().to_owned(), last_interaction_at: conversation
.get_utc_datetime("last_interaction_at")
.unwrap()
.to_rfc3339_opts(SecondsFormat::Millis, true),
updated_at: conversation
.get_utc_datetime("updated_at")
.unwrap()
.to_rfc3339_opts(SecondsFormat::Millis, true),
created_at: conversation
.get_utc_datetime("created_at")
.unwrap()
.to_rfc3339_opts(SecondsFormat::Millis, true),
})
}
pub fn create_conversation(
flow_id: &str,
step_id: &str,
client: &Client,
metadata: serde_json::Value,
db: &mongodb::Database,
) -> Result<String, EngineError> {
let collection = db.collection("conversation");
let time = Bson::UtcDatetime(chrono::Utc::now());
let metadata = encrypt_data(&metadata)?;
let conversation = doc! {
"client": bson::to_bson(&client)?,
"flow_id": flow_id,
"step_id": step_id,
"metadata": metadata, "status": "OPEN",
"last_interaction_at": &time,
"updated_at": &time,
"created_at": &time
};
let inserted = collection.insert_one(conversation.clone(), None)?;
let id = inserted.inserted_id.as_object_id().unwrap();
Ok(id.to_hex())
}
pub fn close_conversation(
id: &str,
client: &Client,
status: &str,
db: &mongodb::Database,
) -> Result<(), EngineError> {
let collection = db.collection("conversation");
let filter = doc! {
"_id": bson::oid::ObjectId::with_string(id).unwrap(),
"client": bson::to_bson(&client)?,
};
collection.update_one(
filter,
doc! {
"$set": { "status": status },
"$currentDate": { "last_interaction_at": true }
},
None,
)?;
Ok(())
}
pub fn close_all_conversations(client: &Client, db: &mongodb::Database) -> Result<(), EngineError> {
let collection = db.collection("conversation");
let filter = doc! {
"client": bson::to_bson(&client)?,
};
collection.update_many(
filter,
doc! {
"$set": { "status": "CLOSED" },
"$currentDate": { "test": true }
},
None,
)?;
Ok(())
}
pub fn get_latest_open(
client: &Client,
db: &mongodb::Database,
) -> Result<Option<DbConversation>, EngineError> {
let collection = db.collection("conversation");
let filter = doc! {
"status": "OPEN",
"client": bson::to_bson(&client)?,
};
let find_options = mongodb::options::FindOneOptions::builder()
.sort(doc! { "$natural": -1 })
.build();
let result = collection.find_one(filter, find_options)?;
match result {
Some(conv) => {
let conversation = format_conversation_struct(conv)?;
Ok(Some(conversation))
}
None => Ok(None),
}
}
pub fn update_conversation(
conversation_id: &str,
client: &Client,
flow_id: Option<String>,
step_id: Option<String>,
db: &mongodb::Database,
) -> Result<(), EngineError> {
let collection = db.collection("conversation");
let filter = doc! {
"_id": bson::oid::ObjectId::with_string(conversation_id).unwrap(),
"client": bson::to_bson(&client)?,
};
let doc = match (flow_id, step_id) {
(Some(flow_id), Some(step_id)) => doc! {
"flow_id": flow_id,
"step_id": step_id
},
(Some(flow_id), None) => doc! {
"flow_id": flow_id
},
(None, Some(step_id)) => doc! {
"step_id": step_id
},
(None, None) => doc! {},
};
let update = doc! {
"$set": doc,
"$currentDate": { "last_interaction_at": true }
};
collection.update_one(filter, update, None)?;
Ok(())
}