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

Support reading token from environment variable #82

Merged
merged 2 commits into from
Dec 10, 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
10 changes: 5 additions & 5 deletions src/commands/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ impl AuthenticationCommand {
pub async fn execute<W: Write>(
mut writer: W,
api_client: impl ApiClient,
credentials_storage: impl CredentialsStorage,
credentials_storage: Box<dyn CredentialsStorage>,
) -> ResultWithDefaultError<()> {
let user = api_client.get_user().await?;
credentials_storage.persist(user.api_token)?;
Expand Down Expand Up @@ -90,7 +90,7 @@ mod tests {
// Arrange
let mut output = Vec::new();
let api_client = create_working_api_client();
let credentials_storage = create_working_credentials_storage();
let credentials_storage = Box::new(create_working_credentials_storage());

// Act
let result =
Expand All @@ -105,7 +105,7 @@ mod tests {
// Arrange
let mut output = Vec::new();
let api_client = create_working_api_client();
let credentials_storage = create_working_credentials_storage();
let credentials_storage = Box::new(create_working_credentials_storage());

// Act
let _ = AuthenticationCommand::execute(&mut output, api_client, credentials_storage).await;
Expand All @@ -127,7 +127,7 @@ mod tests {
// Arrange
let mut output = Vec::new();
let api_client = create_failing_api_client();
let credentials_storage = create_working_credentials_storage();
let credentials_storage = Box::new(create_working_credentials_storage());

// Act
let result =
Expand All @@ -142,7 +142,7 @@ mod tests {
// Arrange
let mut output = Vec::new();
let api_client = create_working_api_client();
let credentials_storage = create_failing_credentials_storage();
let credentials_storage = Box::new(create_failing_credentials_storage());

// Act
let result =
Expand Down
2 changes: 1 addition & 1 deletion src/commands/cont.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,5 +75,5 @@ fn get_first_stopped_time_entry(
None => 0,
Some(_) => 1,
};
return time_entries.get(continue_entry_index).cloned();
time_entries.get(continue_entry_index).cloned()
}
2 changes: 1 addition & 1 deletion src/config/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -523,7 +523,7 @@ impl TrackConfig {
}
pub fn get_active_config(&self) -> ResultWithDefaultError<&BranchConfig> {
let current_dir = std::env::current_dir().expect("Failed to get current directory");
return Ok(self.get_branch_config_for_dir(&current_dir));
Ok(self.get_branch_config_for_dir(&current_dir))
}
pub fn get_default_entry(&self, entities: Entities) -> ResultWithDefaultError<TimeEntry> {
let config = self.get_active_config()?;
Expand Down
4 changes: 3 additions & 1 deletion src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@ pub const CREDENTIALS_WRITE_ERROR: &str =
pub const CREDENTIALS_DELETE_ERROR: &str =
"An unknown error occurred while deleting your credentials.";
pub const CREDENTIALS_EMPTY_ERROR: &str =
"Please set your API token first by calling toggl auth <API_TOKEN>.";
"Please set your API token first by calling toggl auth <API_TOKEN>. Or export it as TOGGL_API_TOKEN.";
pub const CREDENTIALS_FIND_TOKEN_MESSAGE: &str = "You can find your API token at";
pub const CREDENTIALS_FIND_TOKEN_LINK: &str = "https://track.toggl.com/profile";
pub const CREDENTIALS_OVERRIDE_ERROR: &str =
"You have set TOGGL_API_TOKEN in your environment. Unset it to update or delete your saved credentials.";

pub const FZF_NOT_INSTALLED_ERROR: &str = "fzf could not be found. Is it installed?";
pub const OPERATION_CANCELLED: &str = "Operation cancelled";
Expand Down
34 changes: 34 additions & 0 deletions src/credentials.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,37 @@ impl CredentialsStorage for KeyringStorage {
}
}
}

pub struct EnvironmentStorage {
token: String,
}

impl EnvironmentStorage {
pub fn new(token: String) -> EnvironmentStorage {
Self { token }
}
}

impl CredentialsStorage for EnvironmentStorage {
fn read(&self) -> ResultWithDefaultError<Credentials> {
Ok(Credentials {
api_token: self.token.clone(),
})
}
fn persist(&self, _api_token: String) -> ResultWithDefaultError<()> {
Err(Box::new(StorageError::EnvironmentOverride))
}
fn clear(&self) -> ResultWithDefaultError<()> {
Err(Box::new(StorageError::EnvironmentOverride))
}
}

pub fn get_storage() -> Box<dyn CredentialsStorage> {
if let Ok(api_token) = std::env::var("TOGGL_API_TOKEN") {
return Box::new(EnvironmentStorage::new(api_token));
}

let keyring = Entry::new("togglcli", "default")
.unwrap_or_else(|err| panic!("Couldn't create credentials_storage: {err}"));
Box::new(KeyringStorage::new(keyring))
}
4 changes: 4 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ pub enum StorageError {
Write,
Delete,
Unknown,
EnvironmentOverride,
}

impl Display for StorageError {
Expand Down Expand Up @@ -62,6 +63,9 @@ impl Display for StorageError {
constants::ISSUE_LINK.blue().bold().underline()
)
}
StorageError::EnvironmentOverride => {
format!("{}", constants::CREDENTIALS_OVERRIDE_ERROR.red())
}
};

writeln!(f, "{}", summary)
Expand Down
10 changes: 2 additions & 8 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ use commands::list::ListCommand;
use commands::running::RunningTimeEntryCommand;
use commands::start::StartCommand;
use commands::stop::{StopCommand, StopCommandOrigin};
use credentials::{Credentials, CredentialsStorage, KeyringStorage};
use keyring::Entry;
use credentials::get_storage;
use credentials::Credentials;
use models::ResultWithDefaultError;
use std::io;
use structopt::StructOpt;
Expand Down Expand Up @@ -141,9 +141,3 @@ fn get_api_client(proxy: Option<String>) -> ResultWithDefaultError<impl ApiClien
Err(err) => Err(err),
}
}

fn get_storage() -> impl CredentialsStorage {
let keyring = Entry::new("togglcli", "default")
.unwrap_or_else(|err| panic!("Couldn't create credentials_storage: {err}"));
KeyringStorage::new(keyring)
}
Loading