Skip to content

Commit 3995d83

Browse files
committed
Add --year flag
1 parent eaceb15 commit 3995d83

File tree

5 files changed

+81
-39
lines changed

5 files changed

+81
-39
lines changed

src/cli/arguments.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ pub enum Line {
3131
/// Week number
3232
#[arg(long, short)]
3333
week: Option<u8>,
34+
35+
/// Year
36+
#[arg(long, short, requires = "week")]
37+
year: Option<i32>,
38+
3439
},
3540
}
3641

@@ -41,6 +46,11 @@ pub enum Command {
4146
/// Week number
4247
#[arg(long, short)]
4348
week: Option<u8>,
49+
50+
/// Year
51+
#[arg(long, short, requires = "week")]
52+
year: Option<i32>,
53+
4454
/// Output format
4555
#[arg(long, short, default_value = "table")]
4656
format: Format,
@@ -56,6 +66,10 @@ pub enum Command {
5666
#[arg(long, short)]
5767
week: Option<u8>,
5868

69+
/// Year
70+
#[arg(long, short, requires = "week")]
71+
year: Option<i32>,
72+
5973
/// Name of the job
6074
#[arg(long, short)]
6175
job: String,
@@ -100,6 +114,11 @@ pub enum Command {
100114
/// Week number
101115
#[arg(long, short)]
102116
week: Option<u8>,
117+
118+
/// Year
119+
#[arg(long, short, requires = "week")]
120+
year: Option<i32>,
121+
103122
},
104123

105124
/// Submit time sheet for week

src/cli/commands.rs

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,9 @@ impl<'a> CommandClient<'a> {
5757
Ok(())
5858
}
5959

60-
pub(crate) async fn get(&self, week: Option<u8>, format: Format) {
61-
let week = week.map(WeekNumber::from);
60+
pub(crate) async fn get(&self, week: Option<u8>, year: Option<i32>, format: Format) {
61+
let week = create_week_with_fallback(week, year);
62+
6263
match format {
6364
Format::Json => self.get_json(week.as_ref()).await.context("JSON"),
6465
Format::Table => self.get_table(week.as_ref()).await.context("table"),
@@ -73,6 +74,7 @@ impl<'a> CommandClient<'a> {
7374
hours: f32,
7475
days: Option<Days>,
7576
week: Option<u8>,
77+
year: Option<i32>,
7678
job: &str,
7779
task: &str,
7880
) {
@@ -81,7 +83,7 @@ impl<'a> CommandClient<'a> {
8183
}
8284

8385
let day = get_days(days);
84-
let week = week.map(WeekNumber::from);
86+
let week = create_week_with_fallback(week, year);
8587

8688
self.time_sheet_service
8789
.lock()
@@ -103,12 +105,13 @@ impl<'a> CommandClient<'a> {
103105
task: &str,
104106
days: Option<Days>,
105107
week: Option<u8>,
108+
year: Option<i32>,
106109
) {
107110
if days.as_ref().is_some_and(|days| days.is_empty()) {
108111
exit_with_error!("`--day` is set but no day was provided");
109112
}
110113

111-
let week = week.map(WeekNumber::from);
114+
let week = create_week_with_fallback(week, year);
112115
self.time_sheet_service
113116
.lock()
114117
.await
@@ -129,8 +132,13 @@ impl<'a> CommandClient<'a> {
129132
});
130133
}
131134

132-
pub(crate) async fn delete(&mut self, line_number: &LineNumber, week: Option<u8>) {
133-
let week = week.map(WeekNumber::from);
135+
pub(crate) async fn delete(
136+
&mut self,
137+
line_number: &LineNumber,
138+
week: Option<u8>,
139+
year: Option<i32>,
140+
) {
141+
let week = create_week_with_fallback(week, year);
134142

135143
self.repository
136144
.lock()
@@ -163,10 +171,10 @@ fn get_days(days: Option<Days>) -> Days {
163171
})
164172
}
165173

166-
impl From<Option<u8>> for WeekNumber {
167-
fn from(week: Option<u8>) -> Self {
168-
// Fall back to today's week
169-
week.unwrap_or_else(|| Local::now().date_naive().iso_week().week() as u8)
170-
.into()
171-
}
174+
fn create_week_with_fallback(week: Option<u8>, year: Option<i32>) -> Option<WeekNumber> {
175+
week.map(|week| {
176+
// Fall back to today's year
177+
let year = year.unwrap_or_else(|| year.unwrap_or_else(|| chrono::Utc::now().year()));
178+
WeekNumber::new(week, year).unwrap_or_else(|err| exit_with_error!("{err}"))
179+
})
172180
}

src/domain/models/week.rs

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,35 @@
1-
use std::fmt::Display;
2-
1+
use anyhow::anyhow;
32
use chrono::{NaiveDate, Weekday};
3+
use std::fmt::Display;
44

5-
// TODO: switch from `u8` to `IsoWeek`
65
#[derive(Debug, Clone)]
7-
pub(crate) struct WeekNumber(u8);
6+
pub(crate) struct WeekNumber {
7+
number: u8,
8+
year: i32,
9+
}
810

911
impl WeekNumber {
10-
pub(crate) fn first_day(&self, year: i32) -> Option<NaiveDate> {
11-
NaiveDate::from_isoywd_opt(year, self.0.into(), Weekday::Mon)
12+
pub(crate) fn new(week: u8, year: i32) -> anyhow::Result<Self> {
13+
first_day_of_week(week, year).ok_or(anyhow!("Invalid week '{week}'"))?;
14+
15+
Ok(Self { number: week, year })
1216
}
13-
}
1417

15-
impl From<u8> for WeekNumber {
16-
fn from(week: u8) -> Self {
17-
Self(week)
18+
pub(crate) fn first_day(&self) -> Option<NaiveDate> {
19+
first_day_of_week(self.number, self.year)
1820
}
1921
}
2022

2123
impl Display for WeekNumber {
2224
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23-
write!(f, "{}", self.0)
25+
write!(f, "Week {}, year {}", self.number, self.year)
2426
}
2527
}
2628

29+
fn first_day_of_week(week: u8, year: i32) -> Option<NaiveDate> {
30+
NaiveDate::from_isoywd_opt(year, week.into(), Weekday::Mon)
31+
}
32+
2733
#[cfg(test)]
2834
mod tests {
2935
use super::*;
@@ -37,8 +43,8 @@ mod tests {
3743
];
3844

3945
for (year, week, expected_date) in dates {
40-
let week_number = WeekNumber(week);
41-
let date = week_number.first_day(year).unwrap();
46+
let week_number = WeekNumber { number: week, year };
47+
let date = week_number.first_day().unwrap();
4248

4349
assert_eq!(
4450
date,

src/infrastructure/repositories/time_sheet_repository.rs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ use crate::{
1515
},
1616
};
1717
use anyhow::{anyhow, Context, Result};
18-
use chrono::{Datelike, Local};
1918
use log::{debug, info};
2019
use std::collections::HashSet;
2120

@@ -122,11 +121,12 @@ impl TimeSheetRepository<'_> {
122121
info!("Found no line for job '{job}', task '{task}'. Creating new line for it");
123122
let time_sheet = self.add_line(job, task).await?;
124123

125-
time_sheet
126-
.find_line_nr(job, task)
127-
.with_context(|| format!(
128-
"format not find job '{job}' and task '{task}', even after creating a new line for it"
129-
))?
124+
time_sheet.find_line_nr(job, task).with_context(|| {
125+
format!(
126+
"format not find job '{job}' and task '{task}', even after creating a new \
127+
line for it"
128+
)
129+
})?
130130
}
131131
};
132132

@@ -272,9 +272,8 @@ impl TimeSheetRepository<'_> {
272272
.await
273273
.context("Failed to get container instance")?;
274274

275-
let year = Local::now().date_naive().year();
276275
let date = week
277-
.first_day(year)
276+
.first_day()
278277
.with_context(|| format!("Failed to get first day of week {week}"))?;
279278

280279
let (time_registration, concurrency_control) = self

src/main.rs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,25 +45,35 @@ async fn main() -> anyhow::Result<()> {
4545
);
4646

4747
match parse_arguments() {
48-
Command::Get { week, format } => command_client.get(week, format).await,
48+
Command::Get { week, year, format } => command_client.get(week, year, format).await,
4949
Command::Set {
5050
hours,
51-
week,
5251
day,
52+
week,
53+
year,
5354
job,
5455
task,
55-
} => command_client.set(hours, day, week, &job, &task).await,
56+
} => {
57+
command_client
58+
.set(hours, day, week, year, &job, &task)
59+
.await
60+
}
5661
Command::Clear {
62+
day,
5763
week,
64+
year,
5865
job,
5966
task,
60-
day,
61-
} => command_client.clear(&job, &task, day, week).await,
67+
} => command_client.clear(&job, &task, day, week, year).await,
6268
// TODO: haven't actually tested this yet (can only be tested once a week)
6369
Command::Submit => command_client.submit().await,
6470
Command::Logout => command_client.logout().await,
6571
Command::Line(line) => match line {
66-
Line::Delete { line_number, week } => command_client.delete(&line_number, week).await,
72+
Line::Delete {
73+
line_number,
74+
week,
75+
year,
76+
} => command_client.delete(&line_number, week, year).await,
6777
},
6878
};
6979

0 commit comments

Comments
 (0)