|
|
@ -4,7 +4,7 @@ use crate::session_ext::SessionExt; |
|
|
|
use crate::routes::models::object::ObjectModelForm; |
|
|
|
use crate::routes::models::object::ObjectModelForm; |
|
|
|
use crate::TERA; |
|
|
|
use crate::TERA; |
|
|
|
use crate::tera_ext::TeraExt; |
|
|
|
use crate::tera_ext::TeraExt; |
|
|
|
use yopa::{ID, model}; |
|
|
|
use yopa::{ID, model, Storage, data}; |
|
|
|
use yopa::data::Object; |
|
|
|
use yopa::data::Object; |
|
|
|
use serde::{Serialize,Deserialize}; |
|
|
|
use serde::{Serialize,Deserialize}; |
|
|
|
use yopa::insert::InsertObj; |
|
|
|
use yopa::insert::InsertObj; |
|
|
@ -14,6 +14,8 @@ use serde_json::Value; |
|
|
|
use itertools::Itertools; |
|
|
|
use itertools::Itertools; |
|
|
|
use yopa::model::{ObjectModel, PropertyModel, RelationModel}; |
|
|
|
use yopa::model::{ObjectModel, PropertyModel, RelationModel}; |
|
|
|
use heck::TitleCase; |
|
|
|
use heck::TitleCase; |
|
|
|
|
|
|
|
use std::collections::HashMap; |
|
|
|
|
|
|
|
use json_dotpath::DotPaths; |
|
|
|
|
|
|
|
|
|
|
|
// we only need references here, Context serializes everything to Value.
|
|
|
|
// we only need references here, Context serializes everything to Value.
|
|
|
|
// cloning would be a waste of cycles
|
|
|
|
// cloning would be a waste of cycles
|
|
|
@ -48,6 +50,17 @@ pub(crate) async fn create_form( |
|
|
|
|
|
|
|
|
|
|
|
context.insert("model", model); |
|
|
|
context.insert("model", model); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let form_data = prepare_object_create_data(&rg, model.id)?; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
context.insert("form_data", &form_data); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
TERA.build_response("objects/object_create", &context) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn prepare_object_create_data(rg : &Storage, model_id : ID) -> actix_web::Result<ObjectCreateData> { |
|
|
|
|
|
|
|
let model = rg.get_object_model(model_id) |
|
|
|
|
|
|
|
.ok_or_else(|| actix_web::error::ErrorNotFound("No such model"))?; |
|
|
|
|
|
|
|
|
|
|
|
let relations : Vec<_> = rg.get_relation_models_for_object_model(model.id).collect(); |
|
|
|
let relations : Vec<_> = rg.get_relation_models_for_object_model(model.id).collect(); |
|
|
|
|
|
|
|
|
|
|
|
let mut prop_object_ids : Vec<ID> = relations.iter().map(|r| r.id).collect(); |
|
|
|
let mut prop_object_ids : Vec<ID> = relations.iter().map(|r| r.id).collect(); |
|
|
@ -61,19 +74,15 @@ pub(crate) async fn create_form( |
|
|
|
related_ids.sort(); |
|
|
|
related_ids.sort(); |
|
|
|
related_ids.dedup(); |
|
|
|
related_ids.dedup(); |
|
|
|
|
|
|
|
|
|
|
|
let form_data = ObjectCreateData { |
|
|
|
Ok(ObjectCreateData { |
|
|
|
model_id: model.id, |
|
|
|
model_id: model.id, |
|
|
|
schema: Schema { |
|
|
|
schema: Schema { |
|
|
|
obj_models: rg.get_object_models().collect(), // TODO get only the ones that matter here
|
|
|
|
obj_models: rg.get_object_models().collect(), // TODO get only the ones that matter here
|
|
|
|
rel_models: relations, |
|
|
|
rel_models: relations, |
|
|
|
prop_models: rg.get_property_models_for_parents(&prop_object_ids).collect() |
|
|
|
prop_models: rg.get_property_models_for_parents(prop_object_ids).collect() |
|
|
|
}, |
|
|
|
}, |
|
|
|
objects: rg.get_objects_of_type(&related_ids).collect() |
|
|
|
objects: rg.get_objects_of_type(related_ids).collect() |
|
|
|
}; |
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
context.insert("form_data", &form_data); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
TERA.build_response("objects/object_create", &context) |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#[post("/object/create")] |
|
|
|
#[post("/object/create")] |
|
|
@ -189,7 +198,7 @@ pub(crate) async fn detail( |
|
|
|
let mut ids_to_get_values_for = relations.iter().map(|r| r.id).collect_vec(); |
|
|
|
let mut ids_to_get_values_for = relations.iter().map(|r| r.id).collect_vec(); |
|
|
|
ids_to_get_values_for.push(object_id); |
|
|
|
ids_to_get_values_for.push(object_id); |
|
|
|
let mut grouped_values = { |
|
|
|
let mut grouped_values = { |
|
|
|
rg.get_grouped_values_for_objects(&ids_to_get_values_for) |
|
|
|
rg.get_grouped_values_for_objects(ids_to_get_values_for) |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
// object's own properties
|
|
|
|
// object's own properties
|
|
|
@ -252,3 +261,120 @@ pub(crate) async fn detail( |
|
|
|
|
|
|
|
|
|
|
|
TERA.build_response("objects/object_detail", &context) |
|
|
|
TERA.build_response("objects/object_detail", &context) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Serialize,Debug,Clone)] |
|
|
|
|
|
|
|
struct EnrichedObject<'a> { |
|
|
|
|
|
|
|
id: ID, |
|
|
|
|
|
|
|
model: ID, |
|
|
|
|
|
|
|
name: String, |
|
|
|
|
|
|
|
values: HashMap<String /* ID but as string so serde will stop exploding */, Vec<&'a data::Value>>, |
|
|
|
|
|
|
|
relations: HashMap<String /* ID */, Vec<EnrichedRelation<'a>>>, |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Serialize,Debug,Clone)] |
|
|
|
|
|
|
|
struct EnrichedRelation<'a> { |
|
|
|
|
|
|
|
id: ID, |
|
|
|
|
|
|
|
object: ID, |
|
|
|
|
|
|
|
model: ID, |
|
|
|
|
|
|
|
related: ID, |
|
|
|
|
|
|
|
values: HashMap<String /* ID */, Vec<&'a data::Value>>, |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// FIXME relation values are now showing in the edit form!
|
|
|
|
|
|
|
|
// TODO save handling
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[get("/object/update/{id}")] |
|
|
|
|
|
|
|
pub(crate) async fn update_form( |
|
|
|
|
|
|
|
id: web::Path<ID>, |
|
|
|
|
|
|
|
store: crate::YopaStoreWrapper, |
|
|
|
|
|
|
|
session: Session |
|
|
|
|
|
|
|
) -> actix_web::Result<impl Responder> { |
|
|
|
|
|
|
|
let mut context = tera::Context::new(); |
|
|
|
|
|
|
|
session.render_flash(&mut context); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let rg = store.read().await; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let object = rg.get_object(*id) |
|
|
|
|
|
|
|
.ok_or_else(|| actix_web::error::ErrorNotFound("No such object"))?; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let model = rg.get_object_model(object.model) |
|
|
|
|
|
|
|
.ok_or_else(|| actix_web::error::ErrorNotFound("Object has no model"))?; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// maybe its useful,idk
|
|
|
|
|
|
|
|
context.insert("model", &model); |
|
|
|
|
|
|
|
context.insert("object", &object); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let create_data = prepare_object_create_data(&rg, model.id)?; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let mut value_map = HashMap::new(); |
|
|
|
|
|
|
|
let mut relation_map = HashMap::new(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Some properties may have no values, so we first check what IDs to expect
|
|
|
|
|
|
|
|
let prop_ids = create_data.schema.prop_models.iter() |
|
|
|
|
|
|
|
.filter(|p| p.object == model.id).map(|p| p.id).collect_vec(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let mut values_grouped = rg.get_values_for_object(*id) |
|
|
|
|
|
|
|
.into_group_map_by(|v| v.model); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
prop_ids.into_iter().for_each(|id| { |
|
|
|
|
|
|
|
value_map.insert(id.to_string(), values_grouped.remove(&id).unwrap_or_default()); |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
// Some properties may have no values, so we first check what IDs to expect
|
|
|
|
|
|
|
|
let rel_ids = create_data.schema.rel_models.iter() |
|
|
|
|
|
|
|
.filter(|p| p.object == model.id).map(|p| p.id).collect_vec(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let relations = rg.get_relations_for_object(*id).collect_vec(); |
|
|
|
|
|
|
|
let grouped_relations = relations.iter() |
|
|
|
|
|
|
|
.into_group_map_by(|relation| relation.model); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let mut relation_properties = rg.get_grouped_prop_models_for_parents(rel_ids.clone()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let mut relation_values = rg.get_grouped_values_for_objects(rel_ids.clone()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (rel_model_id, relations) in grouped_relations { |
|
|
|
|
|
|
|
let mut instances = vec![]; |
|
|
|
|
|
|
|
let props_for_rel = relation_properties.remove(&rel_model_id).unwrap_or_default(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for rel in relations { |
|
|
|
|
|
|
|
let mut relation_values_map = HashMap::new(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// values keyed by model
|
|
|
|
|
|
|
|
let mut rel_values = relation_values.remove(&rel.id).unwrap_or_default().into_iter() |
|
|
|
|
|
|
|
.into_group_map_by(|relation| relation.model); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
props_for_rel.iter().for_each(|prop_model| { |
|
|
|
|
|
|
|
relation_values_map.insert(prop_model.id.to_string(), rel_values.remove(&prop_model.id).unwrap_or_default()); |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let enriched = EnrichedRelation { |
|
|
|
|
|
|
|
id: rel.id, |
|
|
|
|
|
|
|
object: rel.object, |
|
|
|
|
|
|
|
model: rel.model, |
|
|
|
|
|
|
|
related: rel.related, |
|
|
|
|
|
|
|
values: relation_values_map |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
instances.push(enriched); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
relation_map.insert(rel_model_id.to_string(), instances); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let mut form = serde_json::to_value(create_data)?; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let object = EnrichedObject { |
|
|
|
|
|
|
|
id: object.id , |
|
|
|
|
|
|
|
model: object.model, |
|
|
|
|
|
|
|
name: object.name.clone(), |
|
|
|
|
|
|
|
values: value_map, |
|
|
|
|
|
|
|
relations: relation_map |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
form.dot_set("object", object); |
|
|
|
|
|
|
|
context.insert("form_data", &form); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
TERA.build_response("objects/object_update", &context) |
|
|
|
|
|
|
|
} |
|
|
|