use actix_session::Session; use actix_web::{Responder, web, HttpResponse}; use crate::session_ext::SessionExt; use crate::routes::models::object::ObjectModelForm; use crate::TERA; use crate::tera_ext::TeraExt; use yopa::{ID, model}; use yopa::data::Object; use serde::{Serialize,Deserialize}; use yopa::insert::InsertObj; use crate::utils::redirect; use actix_web::web::Json; use serde_json::Value; use itertools::Itertools; use yopa::model::ObjectModel; use heck::TitleCase; // we only need references here, Context serializes everything to Value. // cloning would be a waste of cycles #[derive(Debug, Default, Serialize, Clone)] pub struct Schema<'a> { pub obj_models: Vec<&'a model::ObjectModel>, pub rel_models: Vec<&'a model::RelationModel>, pub prop_models: Vec<&'a model::PropertyModel>, } #[derive(Serialize,Debug,Clone)] pub struct ObjectCreateData<'a> { pub model_id: ID, pub schema: Schema<'a>, pub objects: Vec<&'a Object>, } #[get("/object/create/{model_id}")] pub(crate) async fn create_form( model_id: web::Path, store: crate::YopaStoreWrapper, session: Session ) -> actix_web::Result { let mut context = tera::Context::new(); session.render_flash(&mut context); let rg = store.read().await; let model = rg.get_object_model(*model_id) .ok_or_else(|| actix_web::error::ErrorNotFound("No such model"))?; context.insert("model", model); let relations : Vec<_> = rg.get_relation_models_for_object(model.id).collect(); let mut prop_object_ids : Vec = relations.iter().map(|r| r.id).collect(); prop_object_ids.push(model.id); prop_object_ids.sort(); prop_object_ids.dedup(); let mut related_ids : Vec<_> = relations.iter().map(|r| r.related).collect(); related_ids.sort(); related_ids.dedup(); let form_data = ObjectCreateData { model_id: model.id, schema: Schema { obj_models: rg.get_object_models().collect(), // TODO get only the ones that matter here rel_models: relations, prop_models: rg.get_property_models_for_parents(&prop_object_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")] pub(crate) async fn create( form: web::Json, store: crate::YopaStoreWrapper, session: Session, ) -> actix_web::Result { warn!("{:?}", form); // let des : InsertObj = serde_json::from_value(form.into_inner()).unwrap(); // // Ok(HttpResponse::Ok().finish()) // let mut wg = store.write().await; let form = form.into_inner(); let name = form.name.clone(); let model_name = wg.get_model_name(form.model_id).to_owned().to_title_case(); match wg.insert_object(form) { Ok(_id) => { debug!("Object created, redirecting to root"); session.flash_success(format!("{} \"{}\" created.", model_name, name)); Ok(HttpResponse::Ok().finish()) } Err(e) => { warn!("Error creating model: {}", e); Ok(HttpResponse::BadRequest().body(e.to_string())) } } } #[derive(Debug, Serialize, Clone)] struct ModelWithObjects<'a> { model : &'a ObjectModel, objects: Vec<&'a Object> } #[get("/objects")] pub(crate) async fn list(session: Session, store: crate::YopaStoreWrapper) -> actix_web::Result { list_inner(session, store).await } pub(crate) async fn list_inner(session: Session, store: crate::YopaStoreWrapper) -> actix_web::Result { let rg = store.read().await; let mut objects_by_model = rg.get_grouped_objects(); let mut models : Vec<_> = rg.get_object_models() .sorted_by_key(|m| &m.name) .map(|model| { let mut objects = objects_by_model.remove(&model.id).unwrap_or_default(); objects.sort_by_key(|o| &o.name); ModelWithObjects { model, objects } }).collect(); let mut ctx = tera::Context::new(); ctx.insert("models", &models); session.render_flash(&mut ctx); TERA.build_response("objects/index", &ctx) }