2021-06-18 11:27:19 -05:00
|
|
|
use std::convert::TryFrom;
|
2021-08-25 14:30:27 -05:00
|
|
|
use std::io::{BufRead, Write};
|
2021-06-18 11:27:19 -05:00
|
|
|
|
|
|
|
use clap::ArgMatches;
|
2021-06-24 00:07:52 -05:00
|
|
|
use chrono::{DateTime, Utc};
|
2021-06-18 11:27:19 -05:00
|
|
|
|
2021-06-21 11:12:30 -05:00
|
|
|
use crate::database::Database;
|
2021-07-20 10:08:04 -05:00
|
|
|
use crate::error::{Error, Result};
|
2021-06-21 11:12:30 -05:00
|
|
|
use crate::editor;
|
2021-08-25 14:30:27 -05:00
|
|
|
use crate::commands::{Command, Facts};
|
2021-07-01 23:42:59 -05:00
|
|
|
use crate::timeparse::parse_time;
|
2021-07-20 10:08:04 -05:00
|
|
|
use crate::old::{time_or_warning, warn_if_needed};
|
2021-08-25 14:30:27 -05:00
|
|
|
use crate::io::Streams;
|
2021-06-18 11:27:19 -05:00
|
|
|
|
2021-07-17 22:04:54 -05:00
|
|
|
#[derive(Default)]
|
2021-06-18 11:27:19 -05:00
|
|
|
pub struct Args {
|
2021-07-26 16:55:24 -05:00
|
|
|
pub at: Option<DateTime<Utc>>,
|
|
|
|
pub note: Option<String>,
|
2021-06-18 11:27:19 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> TryFrom<&'a ArgMatches<'a>> for Args {
|
2021-07-20 10:08:04 -05:00
|
|
|
type Error = Error;
|
2021-06-18 11:27:19 -05:00
|
|
|
|
2021-07-20 10:08:04 -05:00
|
|
|
fn try_from(matches: &'a ArgMatches) -> Result<Self> {
|
2021-06-18 11:27:19 -05:00
|
|
|
Ok(Args {
|
2021-12-13 14:20:56 -06:00
|
|
|
at: matches.value_of("at").map(parse_time).transpose()?,
|
2021-06-18 11:27:19 -05:00
|
|
|
note: matches.value_of("note").map(|s| s.into()),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct InCommand {}
|
|
|
|
|
|
|
|
impl<'a> Command<'a> for InCommand {
|
|
|
|
type Args = Args;
|
|
|
|
|
2021-08-25 14:30:27 -05:00
|
|
|
fn handle<D, I, O, E>(args: Args, streams: &mut Streams<D, I, O, E>, facts: &Facts) -> Result<()>
|
2021-06-18 11:27:19 -05:00
|
|
|
where
|
|
|
|
D: Database,
|
2021-08-25 14:30:27 -05:00
|
|
|
I: BufRead,
|
2021-06-29 12:02:33 -05:00
|
|
|
O: Write,
|
|
|
|
E: Write,
|
2021-06-18 11:27:19 -05:00
|
|
|
{
|
2021-08-25 14:30:27 -05:00
|
|
|
let start = args.at.unwrap_or(facts.now);
|
2022-05-07 22:36:03 -05:00
|
|
|
let sheet = streams.db.current_sheet()?;
|
2021-07-17 22:04:54 -05:00
|
|
|
|
2021-08-25 14:30:27 -05:00
|
|
|
if streams.db.running_entry(&sheet)?.is_some() {
|
|
|
|
writeln!(streams.out, "Timer is already running for sheet '{}'", sheet)?;
|
2021-07-17 22:04:54 -05:00
|
|
|
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
|
2021-06-18 11:27:19 -05:00
|
|
|
let note = if let Some(note) = args.note {
|
2021-08-04 18:27:08 -05:00
|
|
|
Some(note.trim().to_owned())
|
2021-08-25 14:30:27 -05:00
|
|
|
} else if !facts.config.require_note {
|
2021-08-02 19:10:34 -05:00
|
|
|
None
|
2021-06-18 11:27:19 -05:00
|
|
|
} else {
|
2021-08-25 14:30:27 -05:00
|
|
|
Some(editor::get_string(facts.config.note_editor.as_deref(), None)?)
|
2021-06-18 11:27:19 -05:00
|
|
|
};
|
|
|
|
|
2021-08-25 14:30:27 -05:00
|
|
|
let (start, needs_warning) = time_or_warning(start, &streams.db)?;
|
2021-07-17 22:04:54 -05:00
|
|
|
|
2021-08-25 14:30:27 -05:00
|
|
|
streams.db.entry_insert(start, None, note, &sheet)?;
|
2021-07-17 22:04:54 -05:00
|
|
|
|
2021-08-25 14:30:27 -05:00
|
|
|
writeln!(streams.out, "Checked into sheet \"{}\".", sheet)?;
|
2021-07-17 22:04:54 -05:00
|
|
|
|
2021-08-25 14:30:27 -05:00
|
|
|
warn_if_needed(&mut streams.err, needs_warning, &facts.env)?;
|
2021-06-18 11:27:19 -05:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2021-07-17 22:04:54 -05:00
|
|
|
use pretty_assertions::assert_eq;
|
2021-07-17 22:15:03 -05:00
|
|
|
use chrono::{TimeZone, Local};
|
2021-06-18 11:27:19 -05:00
|
|
|
|
|
|
|
use crate::database::SqliteDatabase;
|
2021-08-25 14:30:27 -05:00
|
|
|
use crate::config::Config;
|
2021-06-18 11:27:19 -05:00
|
|
|
|
2021-07-17 22:04:54 -05:00
|
|
|
use super::*;
|
|
|
|
|
2021-06-18 11:27:19 -05:00
|
|
|
#[test]
|
2021-07-17 22:04:54 -05:00
|
|
|
fn handles_new_entry() {
|
2021-06-18 11:27:19 -05:00
|
|
|
let args = Args {
|
|
|
|
at: None,
|
|
|
|
note: Some("hola".into()),
|
|
|
|
};
|
2021-08-25 14:30:27 -05:00
|
|
|
let mut streams = Streams::fake(b"");
|
|
|
|
let facts = Facts::new();
|
2021-06-18 11:27:19 -05:00
|
|
|
|
2021-08-25 14:30:27 -05:00
|
|
|
assert_eq!(streams.db.entries_full(None, None).unwrap().len(), 0);
|
2021-06-18 11:27:19 -05:00
|
|
|
|
2021-08-25 14:30:27 -05:00
|
|
|
InCommand::handle(args, &mut streams, &facts).unwrap();
|
2021-07-17 22:04:54 -05:00
|
|
|
|
2021-08-25 14:30:27 -05:00
|
|
|
let e = streams.db.entries_full(None, None).unwrap().into_iter().next().unwrap();
|
2021-07-17 22:04:54 -05:00
|
|
|
|
|
|
|
assert_eq!(e.note, Some("hola".into()));
|
2021-08-25 14:30:27 -05:00
|
|
|
assert_eq!(e.start, facts.now);
|
2021-07-17 22:04:54 -05:00
|
|
|
assert_eq!(e.end, None);
|
|
|
|
assert_eq!(e.sheet, "default".to_owned());
|
|
|
|
|
2022-07-19 05:38:37 -05:00
|
|
|
assert_eq!(&String::from_utf8_lossy(&streams.out), "Checked into sheet \"default\".\n");
|
|
|
|
assert_eq!(&String::from_utf8_lossy(&streams.err), "");
|
2021-06-18 11:27:19 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_handles_already_running_entry() {
|
|
|
|
let args = Args {
|
|
|
|
at: None,
|
|
|
|
note: Some("hola".into()),
|
|
|
|
};
|
2021-08-25 14:30:27 -05:00
|
|
|
let mut streams = Streams::fake(b"");
|
|
|
|
let facts = Facts::new();
|
2021-06-18 11:27:19 -05:00
|
|
|
|
2021-12-13 14:20:56 -06:00
|
|
|
streams.db.entry_insert(facts.now, None, None, "default").unwrap();
|
2021-07-17 22:04:54 -05:00
|
|
|
|
2021-08-25 14:30:27 -05:00
|
|
|
assert_eq!(streams.db.entries_full(None, None).unwrap().len(), 1);
|
2021-06-18 11:27:19 -05:00
|
|
|
|
2021-08-25 14:30:27 -05:00
|
|
|
InCommand::handle(args, &mut streams, &facts).unwrap();
|
2021-06-18 11:27:19 -05:00
|
|
|
|
2021-08-25 14:30:27 -05:00
|
|
|
assert_eq!(streams.db.entries_full(None, None).unwrap().len(), 1);
|
2021-07-17 22:04:54 -05:00
|
|
|
|
|
|
|
assert_eq!(
|
2022-07-19 05:38:37 -05:00
|
|
|
&String::from_utf8_lossy(&streams.out),
|
|
|
|
"Timer is already running for sheet 'default'\n"
|
2021-07-17 22:04:54 -05:00
|
|
|
);
|
2021-06-18 11:27:19 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2021-07-17 22:04:54 -05:00
|
|
|
fn no_note_and_no_mandatory_leaves_none() {
|
|
|
|
let args = Default::default();
|
2021-08-25 14:30:27 -05:00
|
|
|
let mut streams = Streams::fake(b"");
|
|
|
|
let facts = Facts::new().with_config(Config {
|
2021-07-17 22:04:54 -05:00
|
|
|
require_note: false,
|
|
|
|
..Default::default()
|
2021-08-25 14:30:27 -05:00
|
|
|
});
|
2021-07-17 22:04:54 -05:00
|
|
|
|
2021-08-25 14:30:27 -05:00
|
|
|
assert_eq!(streams.db.entries_full(None, None).unwrap().len(), 0);
|
2021-07-17 22:04:54 -05:00
|
|
|
|
2021-08-25 14:30:27 -05:00
|
|
|
InCommand::handle(args, &mut streams, &facts).unwrap();
|
2021-07-17 22:04:54 -05:00
|
|
|
|
2021-08-25 14:30:27 -05:00
|
|
|
let e = streams.db.entries_full(None, None).unwrap().into_iter().next().unwrap();
|
2021-07-17 22:04:54 -05:00
|
|
|
|
|
|
|
assert_eq!(e.note, None);
|
2021-08-25 14:30:27 -05:00
|
|
|
assert_eq!(e.start, facts.now);
|
2021-07-17 22:04:54 -05:00
|
|
|
assert_eq!(e.end, None);
|
|
|
|
assert_eq!(e.sheet, "default".to_owned());
|
2021-06-18 11:27:19 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2021-07-17 22:04:54 -05:00
|
|
|
fn warns_if_old_database() {
|
|
|
|
let args = Args {
|
|
|
|
at: None,
|
|
|
|
note: Some("hola".into()),
|
|
|
|
};
|
2021-08-25 14:30:27 -05:00
|
|
|
let mut streams = Streams::fake(b"").with_db({
|
|
|
|
let mut db = SqliteDatabase::from_memory().unwrap();
|
|
|
|
|
|
|
|
db.init_old().unwrap();
|
2021-07-17 22:04:54 -05:00
|
|
|
|
2021-08-25 14:30:27 -05:00
|
|
|
db
|
|
|
|
});
|
|
|
|
let facts = Facts::new();
|
2021-07-17 22:04:54 -05:00
|
|
|
|
2021-08-25 14:30:27 -05:00
|
|
|
assert_eq!(streams.db.entries_full(None, None).unwrap().len(), 0);
|
2021-07-17 22:04:54 -05:00
|
|
|
|
2021-08-25 14:30:27 -05:00
|
|
|
InCommand::handle(args, &mut streams, &facts).unwrap();
|
2021-07-17 22:04:54 -05:00
|
|
|
|
2021-08-25 14:30:27 -05:00
|
|
|
let e = streams.db.entries_full(None, None).unwrap().into_iter().next().unwrap();
|
2021-07-17 22:04:54 -05:00
|
|
|
|
|
|
|
assert_eq!(e.note, Some("hola".into()));
|
2021-08-25 14:30:27 -05:00
|
|
|
assert_eq!(e.start, Utc.from_utc_datetime(&facts.now.with_timezone(&Local).naive_local()));
|
2021-07-17 22:04:54 -05:00
|
|
|
assert_eq!(e.end, None);
|
|
|
|
assert_eq!(e.sheet, "default".to_owned());
|
|
|
|
|
2022-07-19 05:38:37 -05:00
|
|
|
assert_eq!(&String::from_utf8_lossy(&streams.out), "Checked into sheet \"default\".\n");
|
2022-08-26 11:33:56 -05:00
|
|
|
assert_eq!(&String::from_utf8_lossy(&streams.err),
|
2021-08-25 14:30:27 -05:00
|
|
|
"[WARNING] You are using the old timetrap format, it is advised that \
|
2022-08-29 18:03:11 -05:00
|
|
|
you update your database using t migrate. To supress this warning set TIEMPO_SUPRESS_TIMETRAP_WARNING=1\n");
|
2021-07-17 22:04:54 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn notes_are_trimmed() {
|
|
|
|
let args = Args {
|
|
|
|
at: None,
|
|
|
|
note: Some("hola\n".into()),
|
|
|
|
};
|
2021-08-25 14:30:27 -05:00
|
|
|
let mut streams = Streams::fake(b"");
|
|
|
|
let facts = Facts::new();
|
2021-07-17 22:04:54 -05:00
|
|
|
|
2021-08-25 14:30:27 -05:00
|
|
|
assert_eq!(streams.db.entries_full(None, None).unwrap().len(), 0);
|
2021-07-17 22:04:54 -05:00
|
|
|
|
2021-08-25 14:30:27 -05:00
|
|
|
InCommand::handle(args, &mut streams, &facts).unwrap();
|
2021-07-17 22:04:54 -05:00
|
|
|
|
2021-08-25 14:30:27 -05:00
|
|
|
let e = streams.db.entries_full(None, None).unwrap().into_iter().next().unwrap();
|
2021-07-17 22:04:54 -05:00
|
|
|
|
|
|
|
assert_eq!(e.note, Some("hola".into()));
|
2021-08-25 14:30:27 -05:00
|
|
|
assert_eq!(e.start, facts.now);
|
2021-07-17 22:04:54 -05:00
|
|
|
assert_eq!(e.end, None);
|
|
|
|
assert_eq!(e.sheet, "default".to_owned());
|
|
|
|
|
2022-07-19 05:38:37 -05:00
|
|
|
assert_eq!(&String::from_utf8_lossy(&streams.out), "Checked into sheet \"default\".\n");
|
|
|
|
assert_eq!(&String::from_utf8_lossy(&streams.err), "");
|
2021-06-18 11:27:19 -05:00
|
|
|
}
|
|
|
|
}
|