Skip to content

Commit 8921f9a

Browse files
committed
Allow flag in --week previous
Also, fix a bug where a previous `--week` argument is remembered when running with no `--week` argument. It seems that Maconomy remembers the selected week for like a minute. Now I just always specify the week, which sadly adds an extra (sometimes redundant) request. Perhaps there's a simpler way to specify the week without an extra request? I haven't found one yet.
1 parent 7670315 commit 8921f9a

File tree

12 files changed

+123
-80
lines changed

12 files changed

+123
-80
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,9 @@ cargo run
9999

100100
# To pass arguments to maconomy-cli you can use `--`:
101101
cargo run -- set --job '<job name>' --task '<task name>' 8
102+
103+
# To get the full debug log printed to stderr
104+
RUST_LOG=debug cargo run -- ...
102105
```
103106

104107
To run tests:

src/cli/arguments.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ pub enum Line {
3030

3131
/// Week number (defaults to current week if omitted)
3232
#[arg(long, short)]
33-
week: Option<u8>,
33+
week: Option<String>,
3434

3535
/// Year (defaults to current year if omitted)
3636
#[arg(long, short, requires = "week")]
@@ -44,7 +44,7 @@ pub enum Command {
4444
Get {
4545
/// Week number (defaults to current week if omitted)
4646
#[arg(long, short)]
47-
week: Option<u8>,
47+
week: Option<String>,
4848

4949
/// Year (defaults to current year if omitted)
5050
#[arg(long, short, requires = "week")]
@@ -82,7 +82,7 @@ pub enum Command {
8282

8383
/// Week number (defaults to current week if omitted)
8484
#[arg(long, short)]
85-
week: Option<u8>,
85+
week: Option<String>,
8686

8787
/// Year (defaults to current year if omitted)
8888
#[arg(long, short, requires = "week")]
@@ -112,7 +112,7 @@ pub enum Command {
112112

113113
/// Week number (defaults to current week if omitted)
114114
#[arg(long, short)]
115-
week: Option<u8>,
115+
week: Option<String>,
116116

117117
/// Year (defaults to current year if omitted)
118118
#[arg(long, short, requires = "week")]
@@ -123,7 +123,7 @@ pub enum Command {
123123
Submit {
124124
/// Week number (defaults to current week if omitted)
125125
#[arg(long, short)]
126-
week: Option<u8>,
126+
week: Option<String>,
127127

128128
/// Year (defaults to current year if omitted)
129129
#[arg(long, short, requires = "week")]

src/cli/commands.rs

Lines changed: 56 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use crate::{
1111
};
1212
use anyhow::Context;
1313
use chrono::{Datelike, Local};
14+
use log::info;
1415
use std::collections::HashSet;
1516
use std::rc::Rc;
1617
use tokio::sync::Mutex;
@@ -42,14 +43,14 @@ impl<'a> CommandClient<'a> {
4243
}
4344
}
4445

45-
pub(crate) async fn get_table(&self, week: Option<&WeekNumber>) -> anyhow::Result<()> {
46+
pub(crate) async fn get_table(&self, week: &WeekNumber) -> anyhow::Result<()> {
4647
let time_sheet = self.repository.lock().await.get_time_sheet(week).await?;
4748

4849
println!("{time_sheet}");
4950
Ok(())
5051
}
5152

52-
async fn get_json(&self, week: Option<&WeekNumber>) -> anyhow::Result<()> {
53+
async fn get_json(&self, week: &WeekNumber) -> anyhow::Result<()> {
5354
let time_sheet = self.repository.lock().await.get_time_sheet(week).await?;
5455
let json =
5556
serde_json::to_string(&time_sheet).context("Failed to deserialize time sheet")?;
@@ -58,12 +59,13 @@ impl<'a> CommandClient<'a> {
5859
Ok(())
5960
}
6061

61-
pub(crate) async fn get(&self, week: Option<u8>, year: Option<i32>, format: Format) {
62-
let week = to_week_with_fallback(week, year);
62+
pub(crate) async fn get(&self, week: Option<String>, year: Option<i32>, format: Format) {
63+
let week =
64+
get_week_with_fallback(week, year).unwrap_or_else(|err| exit_with_error!("{err}"));
6365

6466
match format {
65-
Format::Json => self.get_json(week.as_ref()).await.context("JSON"),
66-
Format::Table => self.get_table(week.as_ref()).await.context("table"),
67+
Format::Json => self.get_json(&week).await.context("JSON"),
68+
Format::Table => self.get_table(&week).await.context("table"),
6769
}
6870
.unwrap_or_else(|err| {
6971
exit_with_error!("Failed to get time sheet as {}", error_stack_fmt(&err));
@@ -74,7 +76,7 @@ impl<'a> CommandClient<'a> {
7476
&mut self,
7577
hours: f32,
7678
days: Option<Days>,
77-
week: Option<u8>,
79+
week: Option<String>,
7880
year: Option<i32>,
7981
job: &str,
8082
task: &str,
@@ -84,12 +86,13 @@ impl<'a> CommandClient<'a> {
8486
}
8587

8688
let day = get_days(days);
87-
let week = to_week_with_fallback(week, year);
89+
let week =
90+
get_week_with_fallback(week, year).unwrap_or_else(|err| exit_with_error!("{err}"));
8891

8992
self.time_sheet_service
9093
.lock()
9194
.await
92-
.set_time(hours, &day, week.as_ref(), job, task)
95+
.set_time(hours, &day, &week, job, task)
9396
.await
9497
.unwrap_or_else(|err| {
9598
if let SetTimeError::Unknown(err) = err {
@@ -105,18 +108,19 @@ impl<'a> CommandClient<'a> {
105108
job: &str,
106109
task: &str,
107110
days: Option<Days>,
108-
week: Option<u8>,
111+
week: Option<String>,
109112
year: Option<i32>,
110113
) {
111114
if days.as_ref().is_some_and(|days| days.is_empty()) {
112115
exit_with_error!("`--day` is set but no day was provided");
113116
}
114117

115-
let week = to_week_with_fallback(week, year);
118+
let week =
119+
get_week_with_fallback(week, year).unwrap_or_else(|err| exit_with_error!("{err}"));
116120
self.time_sheet_service
117121
.lock()
118122
.await
119-
.clear(job, task, &get_days(days), week.as_ref())
123+
.clear(job, task, &get_days(days), &week)
120124
.await
121125
.unwrap_or_else(|err| {
122126
if let SetTimeError::Unknown(err) = err {
@@ -136,28 +140,31 @@ impl<'a> CommandClient<'a> {
136140
pub(crate) async fn delete(
137141
&mut self,
138142
line_number: &LineNumber,
139-
week: Option<u8>,
143+
week: Option<String>,
140144
year: Option<i32>,
141145
) {
142-
let week = to_week_with_fallback(week, year);
146+
let week =
147+
get_week_with_fallback(week, year).unwrap_or_else(|err| exit_with_error!("{err}"));
143148

144149
self.repository
145150
.lock()
146151
.await
147-
.delete_line(line_number, week.as_ref())
152+
.delete_line(line_number, &week)
148153
.await
149154
.unwrap_or_else(|err| {
150155
let source = error_stack_fmt(&err);
151156
exit_with_error!("Failed to delete line {line_number:?}: {source}");
152157
});
153158
}
154159

155-
pub(crate) async fn submit(&mut self, week: Option<u8>, year: Option<i32>) {
156-
let week = to_week_with_fallback(week, year);
160+
pub(crate) async fn submit(&mut self, week: Option<String>, year: Option<i32>) {
161+
let week =
162+
get_week_with_fallback(week, year).unwrap_or_else(|err| exit_with_error!("{err}"));
163+
157164
self.repository
158165
.lock()
159166
.await
160-
.submit(week.as_ref())
167+
.submit(&week)
161168
.await
162169
.unwrap_or_else(|err| {
163170
exit_with_error!("Failed to submit: {}", error_stack_fmt(&err));
@@ -173,8 +180,35 @@ fn get_days(days: Option<Days>) -> Days {
173180
})
174181
}
175182

176-
fn to_week_with_fallback(week: Option<u8>, year: Option<i32>) -> Option<WeekNumber> {
177-
week.map(|week| {
178-
WeekNumber::new_with_fallback(week, year).unwrap_or_else(|err| exit_with_error!("{err}"))
179-
})
183+
// TODO: refactor this so that it lives on WeekNumber and parse_week calls this instead of
184+
// vice-versa
185+
fn get_week_with_fallback(week: Option<String>, year: Option<i32>) -> anyhow::Result<WeekNumber> {
186+
if let Some(week) = week {
187+
let week = parse_week(week)?;
188+
189+
let week = WeekNumber::new_with_fallback(week, year)?;
190+
Ok(week)
191+
} else {
192+
let week = Local::now().date_naive().iso_week().week().try_into();
193+
let week = week.expect("Week numbers are always less than 255");
194+
195+
WeekNumber::new_with_fallback(week, year)
196+
}
197+
}
198+
199+
fn parse_week(week: String) -> anyhow::Result<u8> {
200+
let week = match week.trim().to_lowercase().as_str() {
201+
"previous" => {
202+
let week = Local::now().date_naive().iso_week().week() - 1;
203+
info!("Using previous week number: {week}");
204+
Ok(week)
205+
}
206+
number => number
207+
.parse()
208+
.with_context(|| format!("Invalid week number '{week}'")),
209+
}?
210+
.try_into()
211+
.expect("Week numbers are always less than 255");
212+
213+
Ok(week)
180214
}

src/cli/rendering.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use crate::domain::models::time_sheet::{Line, TimeSheet};
22
use owo_colors::OwoColorize;
33
use std::fmt::Display;
44
use tabled::settings::{
5-
object::Rows, style::BorderColor, themes::Colorization, Color, Style, Theme,
5+
object::Rows, style::BorderColor, themes::Colorization, Color, Panel, Style, Theme,
66
};
77

88
#[derive(tabled::Tabled, Default)]
@@ -89,6 +89,7 @@ impl Display for TimeSheet {
8989
[tabled::settings::Color::BOLD],
9090
Rows::first(),
9191
))
92+
.with(Panel::footer(format!("Week {}", self.week_number)))
9293
.with(gray_borders());
9394

9495
write!(f, "{table}")

src/domain/models/time_sheet.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,15 @@ impl Line {
2929
}
3030
}
3131

32-
#[derive(Default, Debug, serde::Serialize)]
32+
#[derive(Debug, serde::Serialize)]
3333
pub(crate) struct TimeSheet {
3434
pub(crate) lines: Vec<Line>,
35+
pub(crate) week_number: u8,
3536
}
3637

3738
impl TimeSheet {
38-
pub(crate) fn new(lines: Vec<Line>) -> Self {
39-
Self { lines }
39+
pub(crate) fn new(lines: Vec<Line>, week_number: u8) -> Self {
40+
Self { lines, week_number }
4041
}
4142
}
4243

src/domain/models/week.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use anyhow::anyhow;
22
use chrono::{Datelike, NaiveDate, Weekday};
33
use std::fmt::Display;
44

5-
#[derive(Debug, Clone)]
5+
#[derive(Debug, Clone, Default, serde::Serialize)]
66
pub(crate) struct WeekNumber {
77
number: u8,
88
year: i32,

src/domain/time_sheet_service.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ impl TimeSheetService<'_> {
3737
job: &str,
3838
task: &str,
3939
days: &Days,
40-
week: Option<&WeekNumber>,
40+
week: &WeekNumber,
4141
) -> Result<(), SetTimeError> {
4242
self.set_time(0.0, days, week, job, task).await
4343
}
@@ -47,7 +47,7 @@ impl TimeSheetService<'_> {
4747
&mut self,
4848
hours: f32,
4949
days: &Days,
50-
week: Option<&WeekNumber>,
50+
week: &WeekNumber,
5151
job: &str,
5252
task: &str,
5353
) -> Result<(), SetTimeError> {

src/infrastructure/repositories/maconomy_http_client.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,7 @@ impl MaconomyHttpClient<'_> {
383383
Ok((time_registration, concurrency_control.into()))
384384
}
385385

386+
// Setting the week also returns its time registration
386387
pub(crate) async fn set_week(
387388
&self,
388389
date: NaiveDate,

0 commit comments

Comments
 (0)