Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Count the number of words in WRs #8

Merged
merged 8 commits into from
Jan 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 5 additions & 15 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,13 @@ env:
RUSTFLAGS: "-Dwarnings"

jobs:
clippy_check:
checks:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build
run: cargo build
- name: Run Clippy
run: cargo clippy --all-targets --all-features

format_check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Rustfmt
run: cargo clippy --no-deps
- name: Run Rustfmt (run `cargo fmt --all` to fix)
run: cargo fmt --all -- --check

build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build
run: cargo build --all-targets --all-features
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ imap = "3.0.0-alpha.12"
imap-proto = "0.16.3"
itertools = "0.12.0"
log = "0.4.20"
mailparse = "0.14.1"
native-tls = "0.2.11"
open = "5.0.1"
pretty_env_logger = "0.5.0"
Expand Down
27 changes: 11 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,20 +37,23 @@ The configuration file is written in [TOML](https://toml.io). To login to your E
server = "my.mail.server"
# The port to connect to
port = 993
# (Optional) The username to use for authentication
# username = "my_username"
# (Optional) The password to use for authentication
# password = "my_password"
```
The configure which E-Mails to search for and fetch, you need to provide the following information:

```toml
[mail.fetch]
# The mailboxes to fetch from the WRs you sent, you can also run `cargo run mailboxes` to get a list of all mailboxes you have.
# The mailboxes to fetch from the WRs you sent,
# you can also run `cargo run mailboxes` to get a list of all mailboxes you have.
wr_mailboxes = ["Sent", "Sent Messages"]
# The mailboxes to fetch from the WR replies you received. Usually you only need to fetch from the INBOX. However, if you have a rule that moves the WR replies to a different mailbox, you need to add it here.
# The mailboxes to fetch from the WR replies you received.
# Usually you only need to fetch from the INBOX. However,
# if you have a rule that moves the WR replies to a different mailbox,
# you need to add it here.
re_mailboxes = ["INBOX"]
# The pattern to match the WR subject you sent. This will match all subjects that contain the strings "WR" OR "Weekly Report". This means that your Subject needs to be consistent over the years. Currently, you can only match at most two patterns (this is a limitation of the IMAP search query).
# The pattern to match the WR subject you sent.
# This will match all subjects that contain the strings "WR" OR "Weekly Report".
# This means that your Subject needs to be consistent over the years.
# Currently, you can only match at most two patterns (this is a limitation of the IMAP search query).
pattern = ["WR", "Weekly Report"]
# From which mail address you sent the WRs
from = "my_username@my.mail.server"
Expand All @@ -60,14 +63,6 @@ to = "theboss@my.mail.server"
year = 2023
```

Lastly, you have to configure a few things how the statistics are generated:

```toml
[stats]
# The number of holiday weeks you were not working. This includes holidays, sick days, etc.
num_holidays = 5
```

## How it works

The script works by connecting to your E-Mail account using IMAP. It then searches for all E-Mails that match the given criteria. For instance it creates an IMAP search query that looks like this:
Expand All @@ -76,7 +71,7 @@ The script works by connecting to your E-Mail account using IMAP. It then search
FROM "my_username@my.mail.server" TO "theboss@my.mail.server" SUBJECT "WR" OR SUBJECT "Weekly Report" SINCE 01-Jan-2023 BEFORE 31-Dec-2023
```

which will return a sequence of E-Mail IDs. The script then fetches only the header (or `ENVELOPE` in IMAP terms) of each E-Mail, which contains information such as the date, the sender, the recipient, etc. The content of the mail is not fetched at all. The script then parses the date and sender information to create a list of WRs.
which will return a sequence of E-Mail IDs. The script then fetches first the header (or `ENVELOPE` in IMAP terms) of each E-Mail, which contains information such as the date, the sender, the recipient, etc. In a second step, the content (or `BODY` in IMAP terms) is fetched and merged with the header to create a list of WRs.

The replies are fetched in a similar way, but the other way around:

Expand Down
26 changes: 14 additions & 12 deletions config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,27 @@
server = "my.mail.server"
# The port to connect to
port = 993
# (Optional) The username to use for authentication
# username = "my_username"
# (Optional) The password to use for authentication
# password = "my_password"

[mail.fetch]
# The mailboxes to fetch from the WRs you sent, you can also run `cargo run mailboxes` to get a list of all mailboxes you have.
wr_mailboxes = ["Sent", "Sent Messages"]
# The mailboxes to fetch from the WR replies you received. Usually you only need to fetch from the INBOX. However, if you have a rule that moves the WR replies to a different mailbox, you need to add it here.
# The mailboxes to fetch from the WRs you sent,
# you can also run `cargo run mailboxes` to get
# a list of all mailboxes you have.
wr_mailboxes = ["Sent"]
# The mailboxes to fetch from the WR replies you received.
# Usually you only need to fetch from the INBOX. However,
# if you have a rule that moves the WR replies to a
# different mailbox, you need to add it here.
re_mailboxes = ["INBOX"]
# The pattern to match the WR subject you sent. This will match all subjects that contain the strings "WR" OR "Weekly Report". This means that your Subject needs to be consistent over the years. Currently, you can only match at most two patterns (this is a limitation of the IMAP search query).
# The pattern to match the WR subject you sent.
# This will match all subjects that contain the
# strings "WR" OR "Weekly Report". This means that
# your Subject needs to be consistent over the years.
# Currently, you can only match at most two patterns
# (this is a limitation of the IMAP search query).
pattern = ["WR", "Weekly Report"]
# From which mail address you sent the WRs
from = "my_username@my.mail.server"
# To which mail address you sent the WRs
to = "theboss@my.mail.server"
# The year to fetch the WRs from
year = 2023

[stats]
# The number of holiday weeks you were not working. This includes holidays, sick days, etc.
num_holidays = 5
21 changes: 3 additions & 18 deletions src/config.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,11 @@
use serde::Deserialize;

#[derive(Deserialize, Debug)]
pub struct Config {
// The mail configuration
pub mail: MailConfig,
// The statistics configuration
pub stats: StatsConfig,
}

#[derive(Deserialize, Debug)]
pub struct MailConfig {
// The login configuration
pub login: MailLogin,
pub server: MailLogin,
// The fetch configuration
pub fetch: MailFetch,
pub query: MailQuery,
}

#[derive(Deserialize, Debug)]
Expand All @@ -29,7 +21,7 @@ pub struct MailLogin {
}

#[derive(Deserialize, Debug, Clone)]
pub struct MailFetch {
pub struct MailQuery {
// The mailboxes to fetch from the WRs you sent
pub wr_mailboxes: Vec<String>,
// The mailboxes to fetch from the WR replies you received
Expand All @@ -43,10 +35,3 @@ pub struct MailFetch {
// The year to fetch the WRs from
pub year: u32,
}

#[derive(Deserialize, Debug)]
pub struct StatsConfig {
// The number of holiday weeks you took this year, where you didn't had
// to write a WR, this includes sick days, vacation, etc.
pub num_holidays: u32,
}
13 changes: 11 additions & 2 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ pub enum WrError {
// IO Error
IoError(std::io::Error),
// Error from the IMAP crate
ImapError(imap::error::Error),
ImapError(String),
// Query Error
QueryError(String),
// Config Error
Expand All @@ -16,6 +16,8 @@ pub enum WrError {
SerializationError(String),
// Server Error
ServerError(String),
// Mail parsing error
MailParseError(String),
}

impl std::fmt::Display for WrError {
Expand All @@ -27,6 +29,7 @@ impl std::fmt::Display for WrError {
WrError::ConfigError(e) => write!(f, "Config error: {}", e),
WrError::SerializationError(e) => write!(f, "Serialization error: {}", e),
WrError::ServerError(e) => write!(f, "Server error: {}", e),
WrError::MailParseError(e) => write!(f, "Mail parse error: {}", e),
}
}
}
Expand All @@ -39,7 +42,7 @@ impl From<std::io::Error> for WrError {

impl From<imap::error::Error> for WrError {
fn from(error: imap::error::Error) -> Self {
WrError::ImapError(error)
WrError::ImapError(error.to_string())
}
}

Expand All @@ -49,4 +52,10 @@ impl From<serde_json::Error> for WrError {
}
}

impl From<mailparse::MailParseError> for WrError {
fn from(error: mailparse::MailParseError) -> Self {
WrError::MailParseError(error.to_string())
}
}

impl std::error::Error for WrError {}
Loading