ordinary_modify/
content.rs1use ordinary_config::{Content, ContentDefinition, OrdinaryConfig};
6use ordinary_types::{ContentObject, Field};
7use std::io::Write;
8use std::path::Path;
9use tracing::instrument;
10
11#[instrument(err)]
12pub fn add_def(path: &str, name: &String, json_fields: &str) -> anyhow::Result<()> {
13 let proj_path = Path::new(path);
14 let mut app_config = OrdinaryConfig::get(path)?;
15
16 let mut file_path = "./content.json".to_string();
17
18 let mut content_defs = if let Some(d) = app_config.content {
19 file_path = d.file_path;
20 d.definitions
21 } else {
22 let mut file = fs_err::File::create(proj_path.join("content.json"))?;
23 file.write_all(b"[]")?;
24
25 vec![]
26 };
27
28 if content_defs.len() < 255
29 && let Ok(fields) = serde_json::from_str::<Vec<Field>>(json_fields)
30 {
31 let next_idx = u8::try_from(content_defs.len())?;
32
33 content_defs.push(ContentDefinition {
34 idx: next_idx,
35 name: name.clone(),
36 fields,
37 lifecycle: None,
38 });
39
40 app_config.content = Some(Content {
41 definitions: content_defs,
42 file_path,
43 update: None,
44 });
45
46 let ordinary_json = serde_json::to_string_pretty(&app_config)?;
47
48 let mut file = fs_err::File::create(proj_path.join("ordinary.json"))?;
49 file.write_all(ordinary_json.as_bytes())?;
50 } else {
51 tracing::error!("cannot support more than 255 content definitions for a single project.");
52 }
53
54 Ok(())
55}
56
57#[instrument(err)]
58pub fn edit_def(
59 path: &str,
60 idx: u8,
61 name: Option<String>,
62 json_fields: &str,
63) -> anyhow::Result<()> {
64 let proj_path = Path::new(path);
65 let mut app_config = OrdinaryConfig::get(path)?;
66
67 if let Some(content) = app_config.content.as_mut()
68 && let Some(def) = content.definitions.iter_mut().find(|v| v.idx == idx)
69 && let Ok(fields) = serde_json::from_str::<Vec<Field>>(json_fields)
70 {
71 def.fields = fields;
72
73 if let Some(name) = name {
74 def.name = name;
75 }
76 }
77
78 let ordinary_json = serde_json::to_string_pretty(&app_config)?;
79
80 let mut file = fs_err::File::create(proj_path.join("ordinary.json"))?;
81 file.write_all(ordinary_json.as_bytes())?;
82
83 Ok(())
84}
85
86#[instrument(skip_all, err)]
87fn before_all(
88 proj_path: &Path,
89 content_def: &ContentDefinition,
90 config: &OrdinaryConfig,
91) -> anyhow::Result<()> {
92 if let Some(lifecycle_config) = &config.lifecycle
93 && let Some(before_all) = &lifecycle_config.before_all
94 {
95 OrdinaryConfig::exec_lifecycle_script(proj_path, &None, "all", "before", before_all)?;
96 }
97
98 if let Some(lifecycle_config) = &content_def.lifecycle
99 && let Some(before_all) = &lifecycle_config.before_all
100 {
101 OrdinaryConfig::exec_lifecycle_script(
102 proj_path,
103 &None,
104 &content_def.name,
105 "before_all",
106 before_all,
107 )?;
108 }
109
110 Ok(())
111}
112
113#[instrument(skip_all, err)]
114pub fn add_obj(path: &str, object_json: &str) -> anyhow::Result<()> {
115 let proj_path = Path::new(path);
116 let app_config = OrdinaryConfig::get(path)?;
117
118 let new_obj: ContentObject = serde_json::from_str(object_json)?;
119
120 if let Some(content) = &app_config.content
121 && let Some(content_def) = content
122 .definitions
123 .iter()
124 .find(|d| d.name == new_obj.instance_of)
125 {
126 let content_json = fs_err::read_to_string(proj_path.join(&content.file_path))?;
127 let mut content_objects: Vec<ContentObject> = serde_json::from_str(&content_json)?;
128
129 before_all(proj_path, content_def, &app_config)?;
130
131 if let Some(lifecycle_config) = &content_def.lifecycle
132 && let Some(on_add) = &lifecycle_config.on_add
133 && let Some(before) = &on_add.before
134 {
135 OrdinaryConfig::exec_lifecycle_script(
136 proj_path,
137 &None,
138 &content_def.name,
139 "before",
140 before,
141 )?;
142 }
143
144 content_objects.push(new_obj.clone());
147
148 let new_objects = serde_json::to_string_pretty(&content_objects)?;
149
150 let mut file = fs_err::File::create(proj_path.join(&content.file_path))?;
151 file.write_all(new_objects.as_bytes())?;
152
153 if let Some(lifecycle_config) = &content_def.lifecycle
154 && let Some(on_add) = &lifecycle_config.on_add
155 && let Some(after) = &on_add.after
156 {
157 OrdinaryConfig::exec_lifecycle_script(
158 proj_path,
159 &Some(serde_json::to_string(&new_obj)?),
160 &content_def.name,
161 "after",
162 after,
163 )?;
164 }
165 }
166
167 Ok(())
168}
169
170#[instrument(skip_all, err)]
171pub fn edit_obj(path: &str, object_json: &str) -> anyhow::Result<()> {
172 let proj_path = Path::new(path);
173 let app_config = OrdinaryConfig::get(path)?;
174 let new_obj: ContentObject = serde_json::from_str(object_json)?;
175
176 if let Some(content) = &app_config.content
177 && let Some(content_def) = content
178 .definitions
179 .iter()
180 .find(|d| d.name == new_obj.instance_of)
181 {
182 let content_json = fs_err::read_to_string(proj_path.join(&content.file_path))?;
183 let mut content_objects: Vec<ContentObject> = serde_json::from_str(&content_json)?;
184
185 before_all(proj_path, content_def, &app_config)?;
186
187 if let Some(obj) = content_objects
188 .iter_mut()
189 .find(|obj| obj.uuid == new_obj.uuid && obj.instance_of == new_obj.instance_of)
190 {
191 if let Some(lifecycle_config) = &content_def.lifecycle
192 && let Some(on_edit) = &lifecycle_config.on_edit
193 && let Some(before) = &on_edit.before
194 {
195 OrdinaryConfig::exec_lifecycle_script(
196 proj_path,
197 &None,
198 &content_def.name,
199 "before",
200 before,
201 )?;
202 }
203
204 obj.fields.clone_from(&new_obj.fields);
205 }
206
207 let new_objects = serde_json::to_string_pretty(&content_objects)?;
208
209 let mut file = fs_err::File::create(proj_path.join(&content.file_path))?;
210 file.write_all(new_objects.as_bytes())?;
211
212 if let Some(lifecycle_config) = &content_def.lifecycle
213 && let Some(on_edit) = &lifecycle_config.on_edit
214 && let Some(after) = &on_edit.after
215 {
216 OrdinaryConfig::exec_lifecycle_script(
217 proj_path,
218 &Some(serde_json::to_string(&new_obj)?),
219 &content_def.name,
220 "after",
221 after,
222 )?;
223 }
224 }
225 Ok(())
226}
227
228#[instrument(skip_all, err)]
229pub fn delete_obj(path: &str, instance_of: &str, uuid: &str) -> anyhow::Result<()> {
230 let proj_path = Path::new(path);
231 let app_config = OrdinaryConfig::get(path)?;
232
233 if let Some(content) = &app_config.content
234 && let Some(content_def) = content.definitions.iter().find(|d| d.name == instance_of)
235 {
236 let content_json = fs_err::read_to_string(proj_path.join(&content.file_path))?;
237 let mut content_objects: Vec<ContentObject> = serde_json::from_str(&content_json)?;
238
239 before_all(proj_path, content_def, &app_config)?;
240
241 let mut removed = None;
242
243 if let Some(pos) = content_objects
244 .iter()
245 .position(|obj| obj.uuid == uuid && obj.instance_of == instance_of)
246 {
247 if let Some(lifecycle_config) = &content_def.lifecycle
248 && let Some(on_delete) = &lifecycle_config.on_delete
249 && let Some(before) = &on_delete.before
250 {
251 OrdinaryConfig::exec_lifecycle_script(
252 proj_path,
253 &None,
254 &content_def.name,
255 "before",
256 before,
257 )?;
258 }
259
260 removed = Some(content_objects.remove(pos));
261 }
262
263 let new_objects = serde_json::to_string_pretty(&content_objects)?;
264
265 let mut file = fs_err::File::create(proj_path.join(&content.file_path))?;
266 file.write_all(new_objects.as_bytes())?;
267
268 if let Some(removed) = removed
269 && let Some(lifecycle_config) = &content_def.lifecycle
270 && let Some(on_delete) = &lifecycle_config.on_delete
271 && let Some(after) = &on_delete.after
272 {
273 OrdinaryConfig::exec_lifecycle_script(
274 proj_path,
275 &Some(serde_json::to_string(&removed)?),
276 &content_def.name,
277 "after",
278 after,
279 )?;
280 }
281 }
282
283 Ok(())
284}