Skip to content

Commit

Permalink
fix: api validation with new types
Browse files Browse the repository at this point in the history
  • Loading branch information
Pratik Mishra authored and Pratik Mishra committed Aug 1, 2024
1 parent f3f4535 commit 8edfa52
Show file tree
Hide file tree
Showing 19 changed files with 692 additions and 226 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion crates/cac_client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ strum_macros = { workspace = true }
strum = { workspace = true }
tokio = {version = "1.29.1", features = ["full"]}
service_utils = { path = "../service_utils" }
superposition_types = {path = "../superposition_types"}
superposition_types = {path = "../superposition_types" }
anyhow = { workspace = true }
superposition_macros = { path = "../superposition_macros" }
[lib]
Expand Down
4 changes: 4 additions & 0 deletions crates/context_aware_config/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -65,5 +65,9 @@ jsonlogic = { workspace = true }
superposition_types = { path = "../superposition_types" }
superposition_macros = { path = "../superposition_macros" }


[features]
disable_db_data_validation = ["superposition_types/disable_db_data_validation"]

[lints]
workspace = true
109 changes: 76 additions & 33 deletions crates/context_aware_config/src/api/config/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use diesel::{
};
use serde_json::{json, Map, Value};
use superposition_macros::{bad_argument, db_error, unexpected_error};
use superposition_types::{result as superposition, User};
use superposition_types::{result as superposition, Cac, Condition, Overrides, User};

use itertools::Itertools;
use jsonschema::JSONSchema;
Expand Down Expand Up @@ -313,31 +313,58 @@ fn get_contextids_from_overrideid(
Ok(res)
}

fn construct_new_payload(req_payload: &Map<String, Value>) -> web::Json<PutReq> {
fn construct_new_payload(
req_payload: &Map<String, Value>,
) -> superposition::Result<web::Json<PutReq>> {
let mut res = req_payload.clone();
res.remove("to_be_deleted");
res.remove("override_id");
res.remove("id");
if let Some(Value::Object(res_context)) = res.get("context") {
if let Some(Value::Object(res_override)) = res.get("override") {
return web::Json(PutReq {
context: res_context.to_owned(),
r#override: res_override.to_owned(),
});
}
}
web::Json(PutReq {
context: Map::new(),
r#override: Map::new(),
})

let context = res
.get("context")
.and_then(|val| val.as_object())
.map_or_else(
|| {
log::error!("construct new payload: Context not present");
Err(bad_argument!("Context not present"))
},
|val| {
Cac::<Condition>::try_from(val.to_owned()).map_err(|err| {
log::error!("failed to decode condition with error : {}", err);
bad_argument!(err)
})
},
)?;

let override_ = res
.get("override")
.and_then(|val| val.as_object())
.map_or_else(
|| {
log::error!("construct new payload Override not present");
Err(bad_argument!("Override not present"))
},
|val| {
Cac::<Overrides>::try_from(val.to_owned()).map_err(|err| {
log::error!("failed to decode override with error : {}", err);
bad_argument!(err)
})
},
)?;

return Ok(web::Json(PutReq {
context: context,
r#override: override_,
}));
}

#[allow(clippy::too_many_arguments)]
async fn reduce_config_key(
user: User,
conn: &mut PooledConnection<ConnectionManager<PgConnection>>,
mut og_contexts: Vec<Context>,
mut og_overrides: Map<String, Value>,
mut og_overrides: HashMap<String, Overrides>,
check_key: &str,
dimension_schema_map: &HashMap<String, (JSONSchema, i32)>,
default_config: Map<String, Value>,
Expand All @@ -352,17 +379,15 @@ async fn reduce_config_key(
)))?;
let mut contexts_overrides_values = Vec::new();

for (override_id, override_value) in og_overrides.clone() {
if let Value::Object(mut override_obj) = override_value {
if let Some(value_of_check_key) = override_obj.remove(check_key) {
let context_arr = get_contextids_from_overrideid(
og_contexts.clone(),
override_obj,
value_of_check_key.clone(),
&override_id,
)?;
contexts_overrides_values.extend(context_arr);
}
for (override_id, mut override_value) in og_overrides.clone() {
if let Some(value_of_check_key) = override_value.remove(check_key) {
let context_arr = get_contextids_from_overrideid(
og_contexts.clone(),
override_value.into(),
value_of_check_key.clone(),
&override_id,
)?;
contexts_overrides_values.extend(context_arr);
}
}

Expand All @@ -371,7 +396,7 @@ async fn reduce_config_key(
for (index, ctx) in contexts_overrides_values.iter().enumerate() {
let priority = validate_dimensions_and_calculate_priority(
"context",
&(ctx.0).condition,
&json!((ctx.0).condition),
dimension_schema_map,
)?;
priorities.push((index, priority))
Expand Down Expand Up @@ -404,6 +429,18 @@ async fn reduce_config_key(
Some(Value::Bool(to_be_deleted)),
Some(override_val),
) => {
let override_val = Cac::<Overrides>::try_from_db(
override_val.as_object().unwrap_or(&Map::new()).clone(),
)
.map_err(|err| {
log::error!(
"reduce_config_key: failed to decode overrides from db {}",
err
);
unexpected_error!(err)
})?
.into_inner();

if *to_be_deleted {
if is_approve {
let _ = delete_context_api(cid.clone(), user.clone(), conn);
Expand All @@ -412,11 +449,12 @@ async fn reduce_config_key(
} else {
if is_approve {
let _ = delete_context_api(cid.clone(), user.clone(), conn);
let put_req = construct_new_payload(request_payload);
let _ = put(put_req, conn, false, &user);
if let Ok(put_req) = construct_new_payload(request_payload) {
let _ = put(put_req, conn, false, &user);
}
}

let new_id = hash(override_val);
let new_id = hash(&json!(override_val));
og_overrides.insert(new_id.clone(), override_val.clone());

let mut ctx_index = 0;
Expand Down Expand Up @@ -560,7 +598,7 @@ async fn get_resolved_config(
.contexts
.into_iter()
.map(|val| cac_client::Context {
condition: val.condition,
condition: json!(val.condition),
override_with_keys: val.override_with_keys,
})
.collect::<Vec<_>>();
Expand All @@ -572,12 +610,17 @@ async fn get_resolved_config(
.and_then(|val| MergeStrategy::from_str(val).ok())
.unwrap_or_default();

let mut override_map = Map::new();
for (key, val) in config.overrides.iter() {
override_map.insert(key.to_owned(), json!(val));
}

let response = if let Some(Value::String(_)) = query_params_map.get("show_reasoning")
{
eval_cac_with_reasoning(
config.default_configs,
&cac_client_contexts,
&config.overrides,
&override_map,
&query_params_map,
merge_strategy,
)
Expand All @@ -589,7 +632,7 @@ async fn get_resolved_config(
eval_cac(
config.default_configs,
&cac_client_contexts,
&config.overrides,
&override_map,
&query_params_map,
merge_strategy,
)
Expand Down
36 changes: 19 additions & 17 deletions crates/context_aware_config/src/api/config/helpers.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
use std::collections::HashMap;

use super::types::{Config, Context};

use actix_web::web::Query;
use serde_json::{json, Map, Value};
use std::collections::HashMap;
use superposition_macros::{bad_argument, unexpected_error};
use superposition_types::result as superposition;
use superposition_types::{result as superposition, Cac, Overrides};

pub fn filter_context(
contexts: &[Context],
Expand All @@ -14,7 +12,10 @@ pub fn filter_context(
contexts
.iter()
.filter_map(|context| {
match jsonlogic::partial_apply(&context.condition, &json!(dimension_data)) {
match jsonlogic::partial_apply(
&json!(context.condition),
&json!(dimension_data),
) {
Ok(jsonlogic::PartialApplyOutcome::Resolved(Value::Bool(true)))
| Ok(jsonlogic::PartialApplyOutcome::Ambiguous) => Some(context.clone()),
_ => None,
Expand All @@ -27,7 +28,7 @@ pub fn filter_config_by_prefix(
config: &Config,
prefix_list: &Vec<String>,
) -> superposition::Result<Config> {
let mut filtered_overrides: Map<String, Value> = Map::new();
let mut filtered_overrides: HashMap<String, Overrides> = HashMap::new();

let filtered_default_config: Map<String, Value> = config
.default_configs
Expand All @@ -41,21 +42,22 @@ pub fn filter_config_by_prefix(
.collect();

for (key, overrides) in &config.overrides {
let overrides_map = overrides
.as_object()
.ok_or_else(|| {
log::error!("failed to decode overrides.");
unexpected_error!("failed to decode overrides.")
})?
.clone();

let filtered_overrides_map: Map<String, Value> = overrides_map
let override_map: Map<String, Value> = overrides.to_owned().into();
let filtered_overrides_map: Map<String, Value> = override_map
.into_iter()
.filter(|(key, _)| filtered_default_config.contains_key(key))
.collect();

if !filtered_overrides_map.is_empty() {
filtered_overrides.insert(key.clone(), Value::Object(filtered_overrides_map));
filtered_overrides.insert(
key.clone(),
Cac::<Overrides>::try_from_db(filtered_overrides_map)
.map_err(|err| {
log::error!("filter_config_by_prefix : failed to decode overrides from db with error {}", err);
unexpected_error!(err)
})?
.into_inner(),
);
}
}

Expand All @@ -80,7 +82,7 @@ pub fn filter_config_by_dimensions(
dimension_data: &Map<String, Value>,
) -> superposition::Result<Config> {
let filtered_context = filter_context(&config.contexts, dimension_data);
let filtered_overrides: Map<String, Value> = filtered_context
let filtered_overrides: HashMap<String, Overrides> = filtered_context
.iter()
.flat_map(|ele| {
let override_with_key = &ele.override_with_keys[0];
Expand Down
7 changes: 5 additions & 2 deletions crates/context_aware_config/src/api/config/types.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
use std::collections::HashMap;

use serde::{Deserialize, Serialize};
use serde_json::{Map, Value};
use superposition_types::{Condition, Overrides};

#[derive(Serialize, Deserialize)]
pub struct Config {
pub contexts: Vec<Context>,
pub overrides: Map<String, Value>,
pub overrides: HashMap<String, Overrides>,
pub default_configs: Map<String, Value>,
}

#[derive(Serialize, Clone, Deserialize)]
pub struct Context {
pub id: String,
pub condition: Value,
pub condition: Condition,
pub priority: i32,
pub override_with_keys: [String; 1],
}
18 changes: 10 additions & 8 deletions crates/context_aware_config/src/api/context/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,29 +193,31 @@ fn create_ctx_from_put_req(
conn: &mut DBConnection,
user: &User,
) -> superposition::Result<Context> {
let ctx_condition = Value::Object(req.context.to_owned());
let ctx_override: Value = req.r#override.to_owned().into();
validate_override_with_default_configs(conn, &req.r#override)?;
let ctx_condition = req.context.to_owned().into_inner();
let condition_val = json!(ctx_condition);
let r_override = req.r#override.clone().into_inner();
let ctx_override = json!(r_override.to_owned());
validate_override_with_default_configs(conn, &r_override)?;
validate_condition_with_functions(conn, &ctx_condition)?;
validate_override_with_functions(conn, &req.r#override)?;
validate_override_with_functions(conn, &r_override)?;

let dimension_schema_map = get_all_dimension_schema_map(conn)?;

let priority = validate_dimensions_and_calculate_priority(
"context",
&ctx_condition,
&condition_val,
&dimension_schema_map,
)?;

if priority == 0 {
return Err(bad_argument!("No dimension found in context"));
}

let context_id = hash(&ctx_condition);
let context_id = hash(&condition_val);
let override_id = hash(&ctx_override);
Ok(Context {
id: context_id.clone(),
value: ctx_condition,
value: condition_val,
priority,
override_id: override_id.to_owned(),
override_: ctx_override.to_owned(),
Expand Down Expand Up @@ -399,7 +401,7 @@ fn r#move(
) -> superposition::Result<PutResp> {
use contexts::dsl;
let req = req.into_inner();
let ctx_condition = Value::Object(req.context);
let ctx_condition = Value::Object(req.context.into_inner().into());
let new_ctx_id = hash(&ctx_condition);
let dimension_schema_map = get_all_dimension_schema_map(conn)?;
let priority = validate_dimensions_and_calculate_priority(
Expand Down
4 changes: 2 additions & 2 deletions crates/context_aware_config/src/api/context/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use base64::prelude::*;
use service_utils::helpers::extract_dimensions;
use std::str;
use superposition_macros::{unexpected_error, validation_error};
use superposition_types::result as superposition;
use superposition_types::{result as superposition, Condition};

use crate::api::functions::helpers::get_published_functions_by_names;
use crate::validation_functions::execute_fn;
Expand All @@ -24,7 +24,7 @@ type DBConnection = PooledConnection<ConnectionManager<PgConnection>>;

pub fn validate_condition_with_functions(
conn: &mut DBConnection,
context: &Value,
context: &Condition,
) -> superposition::Result<()> {
use dimensions::dsl;
let context = extract_dimensions(context)?;
Expand Down
Loading

0 comments on commit 8edfa52

Please sign in to comment.