You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
268 lines
8.2 KiB
268 lines
8.2 KiB
use actix_session::Session;
|
|
use actix_web::{Responder, web};
|
|
use serde::{Serialize, Deserialize};
|
|
|
|
use yopa::{DataType, ID, TypedValue};
|
|
use yopa::model::{PropertyModel, RelationModel};
|
|
|
|
use crate::session_ext::SessionExt;
|
|
use crate::TERA;
|
|
use crate::tera_ext::TeraExt;
|
|
use crate::utils::{ParseOrBadReq, redirect};
|
|
use crate::routes::models::relation::ObjectOrRelationModelDisplay;
|
|
|
|
#[get("/model/property/create/{object_id}")]
|
|
pub(crate) async fn create_form(
|
|
object_id: web::Path<String>,
|
|
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;
|
|
|
|
// Re-fill old values
|
|
if let Ok(Some(form)) = session.take::<PropertyModelCreateForm>("old") {
|
|
context.insert("old", &form);
|
|
} else {
|
|
context.insert("old", &PropertyModelCreateForm {
|
|
object: Default::default(),
|
|
name: "".to_string(),
|
|
optional: false,
|
|
multiple: false,
|
|
data_type: DataType::String,
|
|
default: "".to_string()
|
|
});
|
|
}
|
|
|
|
debug!("ID = {}", object_id);
|
|
|
|
let object = {
|
|
let id = object_id.parse_or_bad_request()?;
|
|
debug!("Create property for ID={}", id);
|
|
if let Some(om) = rg.get_object_model(id) {
|
|
ObjectOrRelationModelDisplay {
|
|
id: om.id,
|
|
describe: format!("object model \"{}\"", om.name),
|
|
}
|
|
} else if let Some(rm) = rg.get_relation_model(id) {
|
|
ObjectOrRelationModelDisplay {
|
|
id: rm.id,
|
|
describe: format!("relation model \"{}\"", rm.name),
|
|
}
|
|
} else {
|
|
return Err(actix_web::error::ErrorNotFound("No such source object"));
|
|
}
|
|
};
|
|
|
|
context.insert("object", &object);
|
|
TERA.build_response("models/property_create", &context)
|
|
}
|
|
|
|
#[derive(Serialize,Deserialize)]
|
|
pub(crate) struct PropertyModelCreateForm {
|
|
pub object: ID,
|
|
pub name: String,
|
|
#[serde(default)]
|
|
pub optional: bool,
|
|
#[serde(default)]
|
|
pub multiple: bool,
|
|
pub data_type: DataType,
|
|
/// Default value to be parsed to the data type
|
|
/// May be unused if empty and optional
|
|
pub default: String,
|
|
}
|
|
|
|
fn parse_default(data_type : DataType, default : String) -> Result<TypedValue, String> {
|
|
Ok(match data_type {
|
|
DataType::String => {
|
|
TypedValue::String(default.into())
|
|
}
|
|
DataType::Integer => {
|
|
if default.is_empty() {
|
|
TypedValue::Integer(0)
|
|
} else {
|
|
// TODO better error reporting
|
|
TypedValue::Integer(default.parse()
|
|
.map_err(|_| {
|
|
format!("Error parsing \"{}\" as integer", default)
|
|
})?)
|
|
}
|
|
}
|
|
DataType::Decimal => {
|
|
if default.is_empty() {
|
|
TypedValue::Decimal(0.0)
|
|
} else {
|
|
// TODO better error reporting
|
|
TypedValue::Decimal(default.parse()
|
|
.map_err(|_| {
|
|
format!("Error parsing \"{}\" as decimal", default)
|
|
})?)
|
|
}
|
|
}
|
|
DataType::Boolean => {
|
|
if default.is_empty() {
|
|
TypedValue::Boolean(false)
|
|
} else {
|
|
TypedValue::String(default.clone().into())
|
|
.cast_to(DataType::Boolean).map_err(|_| {
|
|
format!("Error parsing \"{}\" as boolean", default)
|
|
})?
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
#[post("/model/property/create")]
|
|
pub(crate) async fn create(
|
|
form: web::Form<PropertyModelCreateForm>,
|
|
store: crate::YopaStoreWrapper,
|
|
session: Session,
|
|
) -> actix_web::Result<impl Responder> {
|
|
let mut wg = store.write().await;
|
|
let form = form.into_inner();
|
|
|
|
let optional = form.optional;
|
|
let multiple = form.multiple;
|
|
|
|
let default = match parse_default(form.data_type, form.default.clone()) {
|
|
Ok(def) => def,
|
|
Err(msg) => {
|
|
warn!("{}", msg);
|
|
session.flash_error(msg);
|
|
session.set("old", &form);
|
|
return redirect(format!("/model/property/create/{}", form.object));
|
|
}
|
|
};
|
|
|
|
match wg.define_property(PropertyModel {
|
|
id: Default::default(),
|
|
object: form.object,
|
|
name: form.name.clone(),
|
|
optional,
|
|
multiple,
|
|
data_type: form.data_type,
|
|
default,
|
|
}) {
|
|
Ok(_id) => {
|
|
debug!("Property created, redirecting to root");
|
|
session.flash_success(format!("Property model \"{}\" created.", form.name));
|
|
redirect("/models")
|
|
}
|
|
Err(e) => {
|
|
warn!("Error creating property model: {}", e);
|
|
session.flash_error(e.to_string());
|
|
session.set("old", &form);
|
|
redirect(format!("/model/property/create/{}", form.object))
|
|
}
|
|
}
|
|
}
|
|
|
|
#[get("/model/property/delete/{id}")]
|
|
pub(crate) async fn delete(
|
|
id: web::Path<String>,
|
|
store: crate::YopaStoreWrapper,
|
|
session: Session,
|
|
) -> actix_web::Result<impl Responder> {
|
|
let mut wg = store.write().await;
|
|
match wg.undefine_property(id.parse_or_bad_request()?) {
|
|
Ok(rm) => {
|
|
debug!("Property deleted, redirecting to root");
|
|
session.flash_success(format!("Property \"{}\" deleted.", rm.name));
|
|
redirect("/models")
|
|
}
|
|
Err(e) => {
|
|
warn!("Error deleting property: {}", e);
|
|
session.flash_error(e.to_string());
|
|
redirect("/models") // back?
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize)]
|
|
pub(crate) struct PropertyModelEditForm {
|
|
pub name: String,
|
|
#[serde(default)]
|
|
pub optional: bool,
|
|
#[serde(default)]
|
|
pub multiple: bool,
|
|
pub data_type: DataType,
|
|
/// Default value to be parsed to the data type
|
|
/// May be unused if empty and optional
|
|
pub default: String,
|
|
}
|
|
|
|
|
|
#[get("/model/property/update/{model_id}")]
|
|
pub(crate) async fn update_form(
|
|
model_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 model = rg.get_property_model(*model_id)
|
|
.ok_or_else(|| actix_web::error::ErrorNotFound("No such model"))?;
|
|
|
|
// Re-fill old values
|
|
if let Ok(Some(form)) = session.take::<PropertyModelEditForm>("old") {
|
|
let mut model = model.clone();
|
|
model.name = form.name;
|
|
model.data_type = form.data_type;
|
|
model.default = TypedValue::String(form.default.into());
|
|
model.optional = form.optional;
|
|
model.multiple = form.multiple;
|
|
context.insert("model", &model);
|
|
} else {
|
|
context.insert("model", model);
|
|
}
|
|
|
|
TERA.build_response("models/property_update", &context)
|
|
}
|
|
|
|
#[post("/model/property/update/{model_id}")]
|
|
pub(crate) async fn update(
|
|
model_id: web::Path<ID>,
|
|
form: web::Form<PropertyModelEditForm>,
|
|
store: crate::YopaStoreWrapper,
|
|
session: Session,
|
|
) -> actix_web::Result<impl Responder> {
|
|
let mut wg = store.write().await;
|
|
let form = form.into_inner();
|
|
|
|
let id = model_id.into_inner();
|
|
let default = match parse_default(form.data_type, form.default.clone()) {
|
|
Ok(def) => def,
|
|
Err(msg) => {
|
|
warn!("{}", msg);
|
|
session.flash_error(msg);
|
|
session.set("old", form);
|
|
return redirect(format!("/model/property/update/{}", id));
|
|
}
|
|
};
|
|
|
|
match wg.update_property(PropertyModel {
|
|
id,
|
|
object: Default::default(), // dummy
|
|
name: form.name.clone(),
|
|
optional: form.optional,
|
|
multiple: form.multiple,
|
|
data_type: form.data_type,
|
|
default,
|
|
}) {
|
|
Ok(_id) => {
|
|
debug!("Relation updated, redirecting to root");
|
|
session.flash_success(format!("Property \"{}\" updated.", form.name));
|
|
redirect("/models")
|
|
}
|
|
Err(e) => {
|
|
warn!("Error updating model: {}", e);
|
|
session.flash_error(e.to_string());
|
|
session.set("old", form);
|
|
redirect(format!("/model/relation/update/{}", id))
|
|
}
|
|
}
|
|
}
|
|
|