all the updater opts for editing things in place

429aa90 · gmorell · 2025-01-09 01:32

16 files +1686 -28

Files changed

modified Cargo.lock
+11 −0
@@ -497,6 +497,16 @@ version = "1.0.0"
497 497 source = "registry+https://github.com/rust-lang/crates.io-index"
498 498 checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
499 499
500 +[[package]]
501 +name = "colored"
502 +version = "2.2.0"
503 +source = "registry+https://github.com/rust-lang/crates.io-index"
504 +checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c"
505 +dependencies = [
506 + "lazy_static",
507 + "windows-sys 0.59.0",
508 +]
509 +
500 510 [[package]]
501 511 name = "compact_str"
502 512 version = "0.8.0"
@@ -1863,6 +1873,7 @@ dependencies = [
1863 1873 "chrono",
1864 1874 "clap",
1865 1875 "color-eyre",
1876 + "colored",
1866 1877 "crossterm",
1867 1878 "dateparser",
1868 1879 "directories",
modified Cargo.toml
+1 −0
@@ -28,3 +28,4 @@ tracing = "0.1.41"
28 28 tracing-subscriber = { version = "0.3.19", features = ["env-filter"] }
29 29 directories = "5.0.1"
30 30 lazy_static = "1.5.0"
31 +colored = { version = "2.2.0" }
added src/color.rs
+8 −0
@@ -0,0 +1,8 @@
1 +use ratatui::prelude::Color;
2 +
3 +pub fn colo(color: Color) -> (u8, u8, u8) {
4 + match color {
5 + Color::Rgb(r, g, b) => (r, g, b),
6 + _ => (128, 128, 128),
7 + }
8 +}
modified src/data.rs
+600 −0
@@ -0,0 +1,600 @@
1 +use crate::color::colo;
2 +use crate::do_tui::Editable;
3 +use crate::entities::ppl::Model;
4 +use crate::entities::prelude::Tier;
5 +use crate::entities::prelude::Traits;
6 +use crate::entities::prelude::{Contact, Ppl, Relation, SigDate, TierDefaults, TraitDefaults};
7 +use crate::entities::{
8 + contact, ppl, relation, sig_date, tier, tier_defaults, trait_defaults, traits,
9 +};
10 +use crate::PplError;
11 +use chrono::{Date, Local, NaiveDate};
12 +use clap::builder::Str;
13 +use color_eyre::owo_colors::OwoColorize;
14 +use log::warn;
15 +use ratatui::style::palette::tailwind::{AMBER, PURPLE};
16 +use sea_orm::ActiveValue::Set;
17 +use sea_orm::{ActiveModelTrait, DatabaseConnection, DbErr, EntityTrait};
18 +use tokio::fs::symlink;
19 +use tracing_subscriber::registry::Data;
20 +
21 +fn bool_from_string(input: Option<String>) -> bool {
22 + if input.is_none() {
23 + return false;
24 + }
25 +
26 + let input = input.unwrap_or("false".to_string());
27 + // Check if the input is an empty string
28 + if input.is_empty() {
29 + return false;
30 + }
31 +
32 + // Convert the input to lowercase for case-insensitive comparison
33 + let input = input.to_lowercase();
34 +
35 + // Check if the input matches any of the bool-like values
36 + match input.as_str() {
37 + "true" | "yes" | "t" | "y" => true,
38 + "false" | "no" | "f" | "n" => false,
39 + _ => false,
40 + }
41 +}
42 +
43 +fn option_naive_date_from_option_string(input: Option<String>) -> Option<NaiveDate> {
44 + match input {
45 + Some(s) => chrono::NaiveDate::parse_from_str(&s, "%Y-%m-%d").ok(),
46 + None => None,
47 + }
48 +}
49 +
50 +pub struct ContactOps {}
51 +
52 +impl ContactOps {
53 + pub async fn create(
54 + db: &DatabaseConnection,
55 + ppl_id: i32,
56 + typ: String,
57 + designator: String,
58 + value: String,
59 + ) -> Result<(), PplError> {
60 + let p = contact::ActiveModel {
61 + id: Default::default(),
62 + ppl_id: Set(ppl_id),
63 + r#type: Set(typ),
64 + designator: Set(Option::from(designator)),
65 + value: Set(value),
66 + date_acq: Set(Some(Local::today().naive_local())),
67 + date_ins: Set(Local::today().naive_local()),
68 + date_up: Set(Local::today().naive_local()),
69 + };
70 +
71 + let pp = p.insert(db).await;
72 + match pp {
73 + Ok(item) => {
74 + let (r, g, b) = colo(PURPLE.c500);
75 + warn!("contact {:?}", item.id.truecolor(r, g, b));
76 + Ok(())
77 + }
78 + Err(err) => {
79 + warn!("contact {}", err.red());
80 + Err(err.into())
81 + }
82 + }
83 + }
84 +
85 + pub async fn list(db: &DatabaseConnection) -> Result<Vec<contact::Model>, DbErr> {
86 + Contact::find().all(db).await
87 + }
88 +
89 + pub async fn updatee(db: &DatabaseConnection, editable: Editable) {
90 + Self::update(
91 + db,
92 + editable.id as u8,
93 + editable.first,
94 + editable.second,
95 + editable.third.unwrap_or("".to_string()),
96 + None,
97 + )
98 + .await
99 + .expect("TODO: panic message");
100 + }
101 +
102 + pub async fn update(
103 + db: &DatabaseConnection,
104 + model_id: u8,
105 + typ: String,
106 + designator: Option<String>,
107 + value: String,
108 + date_acq: Option<String>,
109 + ) -> Result<(), PplError> {
110 + let loaded_model = Contact::find_by_id(model_id).one(db).await?;
111 + match loaded_model {
112 + None => Ok(()),
113 + Some(instance) => {
114 + let mut am: contact::ActiveModel = instance.into();
115 + match date_acq {
116 + None => {}
117 + Some(d) => {
118 + am.date_acq = Set(option_naive_date_from_option_string(Option::from(d)))
119 + }
120 + }
121 + am.designator = Set(designator);
122 + am.r#type = Set(typ);
123 + am.value = Set(value);
124 + am.update(db).await?;
125 + Ok(())
126 + }
127 + }
128 + }
129 +}
130 +
131 +pub struct PplOps {}
132 +
133 +impl PplOps {
134 + pub async fn create_me(
135 + db: &DatabaseConnection,
136 + name: String,
137 + ) -> Result<(ppl::Model), PplError> {
138 + let p = ppl::ActiveModel {
139 + id: Default::default(),
140 + name: Set(name),
141 + me: Set(true),
142 + date_ins: Set(Local::today().naive_local()),
143 + date_up: Set(Local::today().naive_local()),
144 + };
145 + let pp = p.insert(db).await;
146 + match pp {
147 + Ok(item) => {
148 + warn!("ppl {:?}", item.id);
149 + Ok(item)
150 + }
151 + Err(err) => {
152 + warn!("ppl {}", err.red());
153 + Err(err.into())
154 + }
155 + }
156 + }
157 + pub async fn create(db: &DatabaseConnection, name: String) -> Result<(ppl::Model), PplError> {
158 + let p = ppl::ActiveModel {
159 + id: Default::default(),
160 + name: Set(name),
161 + me: Set(false),
162 + date_ins: Set(Local::today().naive_local()),
163 + date_up: Set(Local::today().naive_local()),
164 + };
165 + let pp = p.insert(db).await;
166 + match pp {
167 + Ok(item) => {
168 + warn!("ppl {:?}", item.id);
169 + Ok(item)
170 + }
171 + Err(err) => {
172 + warn!("ppl {}", err.red());
173 + Err(err.into())
174 + }
175 + }
176 + }
177 +
178 + pub async fn list(db: &DatabaseConnection) -> Result<Vec<Model>, DbErr> {
179 + Ppl::find().all(db).await
180 + }
181 +
182 + pub async fn update(
183 + db: &DatabaseConnection,
184 + id: u8,
185 + name: Option<String>,
186 + ) -> Result<(), PplError> {
187 + let loaded_model = Ppl::find_by_id(id).one(db).await?;
188 + match loaded_model {
189 + None => Ok(()),
190 + Some(instance) => {
191 + let mut am: ppl::ActiveModel = instance.into();
192 + match name {
193 + None => {}
194 + Some(i) => am.name = Set(i),
195 + }
196 + am.update(db).await?;
197 + Ok(())
198 + }
199 + }
200 + }
201 +}
202 +
203 +pub struct RelationOps {}
204 +
205 +impl RelationOps {
206 + pub async fn create(
207 + db: &DatabaseConnection,
208 + a: i32,
209 + b: i32,
210 + typ: String,
211 + superseded: bool,
212 + entered: Option<NaiveDate>,
213 + ended: Option<NaiveDate>,
214 + ) -> Result<(), PplError> {
215 + let p = relation::ActiveModel {
216 + id: Default::default(),
217 + ppl_id_a: Set(a),
218 + ppl_id_b: Set(b),
219 + r#type: Set(typ),
220 + date_entered: Set(entered),
221 + date_ended: Set(ended),
222 + date_ins: Set(Local::today().naive_local()),
223 + date_up: Set(Local::today().naive_local()),
224 + superseded: Set(superseded),
225 + };
226 + let pp = p.insert(db).await;
227 + match pp {
228 + Ok(item) => {
229 + warn!("relation {:?}", item.id);
230 + Ok(())
231 + }
232 + Err(err) => {
233 + warn!("relation {}", err.red());
234 + Err(err.into())
235 + }
236 + }
237 + }
238 +
239 + pub async fn list(db: &DatabaseConnection) -> Result<Vec<relation::Model>, DbErr> {
240 + Relation::find().all(db).await
241 + }
242 +
243 + pub async fn updatee(db: &DatabaseConnection, editable: Editable) {
244 + Self::update(
245 + db,
246 + editable.id as u8,
247 + None,
248 + None,
249 + editable.first,
250 + None,
251 + option_naive_date_from_option_string(editable.second),
252 + option_naive_date_from_option_string(editable.third),
253 + ).await.expect("huh");
254 + }
255 +
256 + pub async fn update(
257 + db: &DatabaseConnection,
258 + model_id: u8,
259 + a: Option<i32>,
260 + b: Option<i32>,
261 + typ: String,
262 + superseded: Option<bool>,
263 + entered: Option<NaiveDate>,
264 + ended: Option<NaiveDate>,
265 + ) -> Result<(), PplError> {
266 + let loaded_model = Relation::find_by_id(model_id).one(db).await?;
267 + match loaded_model {
268 + None => Ok(()),
269 + Some(instance) => {
270 + let mut am: relation::ActiveModel = instance.into();
271 + match a {
272 + None => {}
273 + Some(i) => am.ppl_id_a = Set(i),
274 + }
275 + match b {
276 + None => {}
277 + Some(j) => am.ppl_id_b = Set(j),
278 + }
279 + match superseded {
280 + None => {}
281 + Some(bool_val) => am.superseded = Set(bool_val),
282 + }
283 + match entered {
284 + None => {}
285 + Some(date) => am.date_entered = Set(Option::from(date)),
286 + }
287 + match ended {
288 + None => {}
289 + Some(date) => am.date_ended = Set(Option::from(date)),
290 + }
291 + am.r#type = Set(typ);
292 + am.update(db).await?;
293 + Ok(())
294 + }
295 + }
296 + }
297 +}
298 +
299 +pub struct SigDateOps {}
300 +
301 +impl SigDateOps {
302 + pub async fn create(
303 + db: &DatabaseConnection,
304 + ppl_id: i32,
305 + date: NaiveDate,
306 + event: String,
307 + do_remind: bool,
308 + ) -> Result<(), PplError> {
309 + let p = sig_date::ActiveModel {
310 + id: Default::default(),
311 + ppl_id: Set(ppl_id),
312 + date: Set(date),
313 + event: Set(event),
314 + do_remind: Set(do_remind),
315 + with_ppl: Default::default(),
316 + date_ins: Set(Local::today().naive_local()),
317 + date_up: Set(Local::today().naive_local()),
318 + };
319 +
320 + let pp = p.insert(db).await;
321 + match pp {
322 + Ok(item) => {
323 + let (r, g, b) = colo(PURPLE.c500);
324 + warn!("sigDate {:?}", item.id.truecolor(r, g, b));
325 + Ok(())
326 + }
327 + Err(err) => {
328 + warn!("sigDate {}", err.red());
329 + Err(err.into())
330 + }
331 + }
332 + }
333 +
334 + pub async fn list(db: &DatabaseConnection) -> Result<Vec<sig_date::Model>, DbErr> {
335 + SigDate::find().all(db).await
336 + }
337 +
338 + pub async fn updatee(db: &DatabaseConnection, editable: Editable) {
339 + Self::update(
340 + db,
341 + editable.id as u8,
342 + editable.first,
343 + option_naive_date_from_option_string(editable.second),
344 + bool_from_string(editable.third),
345 + None,
346 + )
347 + .await
348 + .expect("TODO: panic message");
349 + }
350 +
351 + pub async fn update(
352 + db: &DatabaseConnection,
353 + id: u8,
354 + event: String,
355 + date: Option<NaiveDate>,
356 + do_remind: bool,
357 + with_ppl: Option<String>,
358 + ) -> Result<(), PplError> {
359 + let loaded_model = SigDate::find_by_id(id).one(db).await?;
360 + match loaded_model {
361 + None => Ok(()),
362 + Some(instance) => {
363 + let mut am: sig_date::ActiveModel = instance.into();
364 +
365 + am.event = Set(event);
366 + am.date = Set(date.unwrap_or(NaiveDate::default()));
367 + am.do_remind = Set(do_remind);
368 + am.update(db).await?;
369 + Ok(())
370 + }
371 + }
372 + }
373 +}
374 +
375 +pub struct TierOps {}
376 +
377 +impl TierOps {
378 + pub async fn create(
379 + db: &DatabaseConnection,
380 + ppl_id: i32,
381 + tier: String,
382 + ) -> Result<(), PplError> {
383 + let t = tier::ActiveModel {
384 + id: Default::default(),
385 + ppl_id: Set(ppl_id),
386 + name: Set(tier.to_string()),
387 + color: Default::default(),
388 + symbol: Default::default(),
389 + date_ins: Set(Local::today().naive_local()),
390 + date_up: Set(Local::today().naive_local()),
391 + };
392 + let tt = t.insert(db).await;
393 + match tt {
394 + Ok(item) => {
395 + warn!("tier {:?}", item.id);
396 + Ok(())
397 + }
398 + Err(err) => {
399 + warn!("tier {}", err.red());
400 + Err(err.into())
401 + }
402 + }
403 + }
404 +
405 + pub async fn list(db: &DatabaseConnection) -> Result<Vec<tier::Model>, DbErr> {
406 + Tier::find().all(db).await
407 + }
408 +
409 + pub async fn updatee(db: &DatabaseConnection, editable: Editable) {
410 + Self::update(
411 + db,
412 + editable.id as u8,
413 + editable.first,
414 + editable.second,
415 + editable.third,
416 + )
417 + .await
418 + .expect("TODO: panic message");
419 + }
420 +
421 + pub async fn update(
422 + db: &DatabaseConnection,
423 + model_id: u8,
424 + name: String,
425 + color: Option<String>,
426 + symbol: Option<String>,
427 + ) -> Result<(), PplError> {
428 + let loaded_model = Tier::find_by_id(model_id).one(db).await?;
429 + match loaded_model {
430 + None => Ok(()),
431 + Some(instance) => {
432 + let mut am: tier::ActiveModel = instance.into();
433 +
434 + am.name = Set(name);
435 + am.color = Set(color);
436 + am.symbol = Set(symbol);
437 + am.update(db).await?;
438 + Ok(())
439 + }
440 + }
441 + }
442 +}
443 +
444 +pub struct TraitOps {}
445 +
446 +impl TraitOps {
447 + pub async fn create(
448 + db: &DatabaseConnection,
449 + ppl_id: i32,
450 + key: String,
451 + value: String,
452 + hidden: bool,
453 + ) -> Result<(), PplError> {
454 + let t = traits::ActiveModel {
455 + id: Default::default(),
456 + ppl_id: Set(ppl_id),
457 + key: Set(key.to_string()),
458 + value: Set(value),
459 + hidden: Set(hidden),
460 + date_ins: Set(Local::today().naive_local()),
461 + date_up: Set(Local::today().naive_local()),
462 + };
463 + let tt = t.insert(db).await;
464 + match tt {
465 + Ok(item) => {
466 + warn!("trait {:?}", item.id);
467 + Ok(())
468 + }
469 + Err(err) => {
470 + warn!("trait {}", err.red());
471 + Err(err.into())
472 + }
473 + }
474 + }
475 + pub async fn list(db: &DatabaseConnection) -> Result<Vec<traits::Model>, DbErr> {
476 + Traits::find().all(db).await
477 + }
478 +
479 + pub async fn updatee(db: &DatabaseConnection, editable: Editable) {
480 + Self::update(
481 + db,
482 + editable.id as u8,
483 + Option::from(editable.first),
484 + editable.second,
485 + bool_from_string(editable.third),
486 + )
487 + .await
488 + .expect("TODO: panic message");
489 + }
490 +
491 + pub async fn update(
492 + db: &DatabaseConnection,
493 + model_id: u8,
494 + key: Option<String>,
495 + value: Option<String>,
496 + hidden: bool,
497 + ) -> Result<(), PplError> {
498 + let loaded_model = Traits::find_by_id(model_id).one(db).await?;
499 + match loaded_model {
500 + None => Ok(()),
501 + Some(instance) => {
502 + let mut am: traits::ActiveModel = instance.into();
503 + match key {
504 + None => {}
505 + Some(i) => am.key = Set(i),
506 + }
507 + match value {
508 + None => {}
509 + Some(j) => am.value = Set(j),
510 + }
511 + am.hidden = Set(hidden);
512 + am.update(db).await?;
513 + Ok(())
514 + }
515 + }
516 + }
517 +}
518 +
519 +pub struct TierDefaultOps {}
520 +
521 +impl TierDefaultOps {
522 + pub async fn create(
523 + db: &DatabaseConnection,
524 + key: String,
525 + value: String,
526 + default: bool,
527 + enabled: bool,
528 + color: String,
529 + symbol: String,
530 + ) -> Result<(), PplError> {
531 + let t = tier_defaults::ActiveModel {
532 + id: Default::default(),
533 + key: Default::default(),
534 + default: Default::default(),
535 + enabled: Default::default(),
536 + color: Default::default(),
537 + symbol: Default::default(),
538 + date_ins: Set(Local::today().naive_local()),
539 + date_up: Set(Local::today().naive_local()),
540 + };
541 + let tt = t.insert(db).await;
542 + match tt {
543 + Ok(item) => {
544 + warn!("tierDefault {:?}", item.id);
545 + Ok(())
546 + }
547 + Err(err) => {
548 + warn!("tierDefault {}", err.red());
549 + Err(err.into())
550 + }
551 + }
552 + }
553 +
554 + pub async fn list(db: &DatabaseConnection) -> Result<Vec<tier_defaults::Model>, DbErr> {
555 + TierDefaults::find().all(db).await
556 + }
557 +}
558 +
559 +pub struct TraitDefaultOps {}
560 +
561 +impl TraitDefaultOps {
562 + pub async fn create(
563 + db: &DatabaseConnection,
564 + ppl_id: i32,
565 + key: String,
566 + color: String,
567 + symbol: String,
568 + default: bool,
569 + enabled: bool,
570 + is_date: bool,
571 + is_contact: bool,
572 + ) -> Result<(), PplError> {
573 + let t = trait_defaults::ActiveModel {
574 + id: Default::default(),
575 + key: Set(key.to_string()),
576 + default: Set(default),
577 + enabled: Set(enabled),
578 + is_date: Set(is_date),
579 + is_contact: Set(is_contact),
580 + color: Set(color),
581 + symbol: Set(symbol),
582 + date_ins: Set(Local::today().naive_local()),
583 + date_up: Set(Local::today().naive_local()),
584 + };
585 + let tt = t.insert(db).await;
586 + match tt {
587 + Ok(item) => {
588 + warn!("traitDefault {:?}", item.id);
589 + Ok(())
590 + }
591 + Err(err) => {
592 + warn!("traitDefault {}", err.red());
593 + Err(err.into())
594 + }
595 + }
596 + }
597 + pub async fn list(db: &DatabaseConnection) -> Result<Vec<trait_defaults::Model>, DbErr> {
598 + TraitDefaults::find().all(db).await
599 + }
600 +}
added src/do_add.rs
+188 −0
@@ -0,0 +1,188 @@
1 +use crate::data::{ContactOps, PplOps, RelationOps, SigDateOps, TierOps, TraitOps};
2 +use crate::entities::ppl::Column::Me;
3 +use crate::entities::prelude::Ppl;
4 +use crate::entities::tier;
5 +use crate::entities::tier::Model;
6 +use crate::entities::{contact, ppl};
7 +use crate::PplError;
8 +use chrono::Local;
9 +use clap::Parser;
10 +use color_eyre::owo_colors::OwoColorize;
11 +use interim::datetime::Date;
12 +use interim::{parse_date_string, Dialect};
13 +use log::warn;
14 +use sea_orm::ActiveValue::Set;
15 +use sea_orm::ColumnTrait;
16 +use sea_orm::{ActiveModelTrait, DatabaseConnection, DbErr, EntityTrait, QueryFilter};
17 +use tracing::info;
18 +
19 +// RUST_LOG=warn cargo run -- add Anjali Budday "+1 5088089658" avenkatesh.wpi@gmail.com 1993-08-28 2018-12-20 Wife 2012-01-01 WPI
20 +// RUST_LOG=warn cargo run -- add Ajax Budday "+1 5088675309" me@me.io
21 +
22 +#[derive(Parser, Debug)]
23 +#[command(version, about, long_about = None)]
24 +pub struct AddArgs {
25 + name: String,
26 + tier: Option<String>,
27 + phone: Option<String>,
28 + email: Option<String>,
29 + bday: Option<String>,
30 + wedding: Option<String>,
31 + relation: Option<String>,
32 + met: Option<String>,
33 + from: Option<String>,
34 + address: Option<String>,
35 +}
36 +
37 +pub async fn do_add(args: &AddArgs, db: DatabaseConnection) -> Result<(), PplError> {
38 + info!(args = ?args, "Adding arguments");
39 +
40 + let me = Ppl::find().filter(Me.eq(true)).one(&db).await?.unwrap();
41 +
42 + let pp = PplOps::create(&db, args.name.clone()).await?;
43 +
44 + match &args.tier {
45 + None => Ok(()),
46 + Some(tier) => TierOps::create(&db, pp.id.clone(), tier.clone()).await,
47 + }?;
48 + match &args.phone {
49 + None => Ok(()),
50 + Some(phone) => {
51 + ContactOps::create(
52 + &db,
53 + pp.id.clone(),
54 + "phone".to_string(),
55 + "primary".to_string(),
56 + phone.to_string(),
57 + )
58 + .await
59 + }
60 + }?;
61 + match &args.email {
62 + None => Ok(()),
63 + Some(phone) => {
64 + ContactOps::create(
65 + &db,
66 + pp.id.clone(),
67 + "email".to_string(),
68 + "primary".to_string(),
69 + phone.to_string(),
70 + )
71 + .await
72 + }
73 + }?;
74 + match &args.bday {
75 + None => Ok(()),
76 + Some(bday) => {
77 + let date = parse_date_string(bday, Local::now(), Dialect::Us);
78 + match date {
79 + Ok(parsed) => {
80 + SigDateOps::create(
81 + &db,
82 + pp.id.clone(),
83 + parsed.date_naive(),
84 + "birthday".to_string(),
85 + true,
86 + )
87 + .await
88 + }
89 + Err(e) => {
90 + warn!("failed to parse bday {:?}", e.red());
91 + Err(e.into())
92 + }
93 + }
94 + }
95 + }?;
96 +
97 + match &args.wedding {
98 + None => Ok(()),
99 + Some(wed) => {
100 + let date = parse_date_string(wed, Local::now(), Dialect::Us);
101 + match date {
102 + Ok(parsed) => {
103 + SigDateOps::create(
104 + &db,
105 + pp.id.clone(),
106 + parsed.date_naive(),
107 + "wedding".to_string(),
108 + false,
109 + )
110 + .await
111 + }
112 + Err(e) => {
113 + warn!("failed to parse wedding {:?}", e.red());
114 + Err(e.into())
115 + }
116 + }
117 + }
118 + }?;
119 +
120 + match &args.relation {
121 + None => Ok(()),
122 + Some(relation) => {
123 + RelationOps::create(
124 + &db,
125 + me.id.clone(),
126 + pp.id.clone(),
127 + relation.to_owned(),
128 + false,
129 + None,
130 + None,
131 + )
132 + .await
133 + }
134 + }?;
135 +
136 + match &args.met {
137 + None => Ok(()),
138 + Some(met) => {
139 + let date = parse_date_string(met, Local::now(), Dialect::Us);
140 + match date {
141 + Ok(parsed) => {
142 + SigDateOps::create(
143 + &db,
144 + pp.id.clone(),
145 + parsed.date_naive(),
146 + "met".to_string(),
147 + false,
148 + )
149 + .await
150 + }
151 + Err(e) => {
152 + warn!("failed to parse metdate {:?}", e.red());
153 + Err(e.into())
154 + }
155 + }
156 + }
157 + }?;
158 +
159 + match &args.from {
160 + None => Ok(()),
161 + Some(from) => {
162 + TraitOps::create(
163 + &db,
164 + pp.id.clone(),
165 + "from".to_string(),
166 + from.to_string(),
167 + false,
168 + )
169 + .await
170 + }
171 + }?;
172 +
173 + match &args.address {
174 + None => Ok(()),
175 + Some(addr) => {
176 + ContactOps::create(
177 + &db,
178 + pp.id.clone(),
179 + "address".to_string(),
180 + "primary".to_string(),
181 + addr.to_string(),
182 + )
183 + .await
184 + }
185 + }?;
186 +
187 + Ok(())
188 +}
modified src/do_init.rs
+5 −11

Click to load diff…

added src/do_tui.rs
+829 −0

Click to load diff…

modified src/entities/contact.rs
+1 −1

Click to load diff…

modified src/entities/tier.rs
+2 −2

Click to load diff…

modified src/main.rs
+30 −7

Click to load diff…

modified src/migrator/m20241220_000002_create_contact.rs
+1 −1

Click to load diff…

modified src/migrator/m20241220_000007_create_tier.rs
+2 −2

Click to load diff…

modified src/migrator/m20241222_000008_create_traitsettings.rs
+8 −4

Click to load diff…

Parents: c5d0c05