Skip to content

Commit

Permalink
feat(backend): Integrate profile management functions into Tauri
Browse files Browse the repository at this point in the history
This commit introduced create, edit, and delete profile functions
into the Tauri application. It also modified the credentials and
profile structures to support serialization and deserialization,
which is essential for operation.

Refs: #9 #15 #16
  • Loading branch information
maikbasel committed Mar 16, 2024
1 parent 8b56ae8 commit 4c20a4b
Show file tree
Hide file tree
Showing 3 changed files with 137 additions and 6 deletions.
15 changes: 13 additions & 2 deletions src-tauri/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,18 @@

use std::sync::Arc;

use backend::__cmd__create_profile;
use backend::__cmd__delete_profile;
use backend::__cmd__edit_profile;
use backend::__cmd__get_profiles;
use backend::__cmd__validate_credentials;
use backend::credentials::application::tauri::credentials_handler::validate_credentials;
use backend::credentials::core::api::CredentialsDataAPI;
use backend::credentials::core::credentials_service::CredentialsService;
use backend::credentials::infrastructure::aws::sts::sts_adapter::STSAdapter;
use backend::profile::application::tauri::profile_handler::get_profiles;
use backend::profile::application::tauri::profile_handler::{
create_profile, delete_profile, edit_profile, get_profiles,
};
use backend::profile::core::spi::ProfileDataSPI;
use backend::profile::infrastructure::aws::sdk_config::sdk_config_adapter::SdkConfigAdapter;

Expand All @@ -21,7 +26,13 @@ fn main() {
tauri::Builder::default()
.manage(Arc::new(profile_data_spi) as Arc<dyn ProfileDataSPI>)
.manage(Arc::new(credentials_data_api) as Arc<dyn CredentialsDataAPI>)
.invoke_handler(tauri::generate_handler![get_profiles, validate_credentials])
.invoke_handler(tauri::generate_handler![
get_profiles,
create_profile,
edit_profile,
delete_profile,
validate_credentials
])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
31 changes: 30 additions & 1 deletion src-tauri/src/profile/application/tauri/profile_handler.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::sync::Arc;

use crate::profile::core::domain::ProfileSet;
use crate::profile::core::domain::{Profile, ProfileSet};
use crate::profile::core::error::ProfileError;
use crate::profile::core::spi::ProfileDataSPI;

Expand All @@ -11,3 +11,32 @@ pub async fn get_profiles(
) -> Result<ProfileSet, ProfileError> {
spi.load_profile_data().await.map_err(ProfileError::from)
}

#[tauri::command]
#[cfg(not(tarpaulin_include))]
pub fn create_profile(
spi: tauri::State<'_, Arc<dyn ProfileDataSPI>>,
profile: Profile,
) -> Result<(), ProfileError> {
spi.save_profile_data(&profile).map_err(ProfileError::from)
}

#[tauri::command]
#[cfg(not(tarpaulin_include))]
pub fn edit_profile(
spi: tauri::State<'_, Arc<dyn ProfileDataSPI>>,
profile: Profile,
) -> Result<(), ProfileError> {
spi.update_profile_data(&profile)
.map_err(ProfileError::from)
}

#[tauri::command]
#[cfg(not(tarpaulin_include))]
pub async fn delete_profile(
spi: tauri::State<'_, Arc<dyn ProfileDataSPI>>,
profile_name: String,
) -> Result<(), ProfileError> {
spi.remove_profile_data(&profile_name)
.map_err(ProfileError::from)
}
97 changes: 94 additions & 3 deletions src-tauri/src/profile/core/domain.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
use std::collections::HashMap;
use std::fmt::Formatter;

use derivative::Derivative;
use error_stack::{Report, Result};
use heck::AsSnakeCase;
use secstr::SecStr;
use serde::de::{MapAccess, SeqAccess, Visitor};
use serde::ser::SerializeStruct;
use serde::Serializer;
use serde::{Deserializer, Serializer};

use crate::common::report::extract_printable_attachments;
use crate::profile::core::error::ProfileError;
Expand Down Expand Up @@ -39,6 +41,77 @@ impl serde::Serialize for Credentials {
}
}

const FIELDS: &[&str] = &["access_key_id", "secret_access_key"];

struct CredentialsVisitor;

impl<'de> Visitor<'de> for CredentialsVisitor {
type Value = Credentials;

fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
formatter.write_str("struct Credentials")
}

fn visit_seq<A>(self, mut seq: A) -> std::result::Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
let access_key_id = seq
.next_element()?
.ok_or_else(|| serde::de::Error::invalid_length(0, &self))?;
let secret_access_key = seq.next_element::<String>()?.map(SecStr::from);

Ok(Credentials {
access_key_id,
secret_access_key,
})
}

fn visit_map<A>(self, mut map: A) -> std::result::Result<Self::Value, A::Error>
where
A: MapAccess<'de>,
{
let mut access_key_id = None;
let mut secret_access_key = None;

while let Some(key) = map.next_key()? {
match key {
"access_key_id" => {
if access_key_id.is_some() {
return Err(serde::de::Error::duplicate_field("access_key_id"));
}
access_key_id = map.next_value()?;
}
"secret_access_key" => {
if secret_access_key.is_some() {
return Err(serde::de::Error::duplicate_field("secret_access_key"));
}
let sec_str: String = map.next_value()?;
secret_access_key = Some(SecStr::from(sec_str));
}
_ => return Err(serde::de::Error::unknown_field(key, FIELDS)),
}
}

let access_key_id =
access_key_id.ok_or_else(|| serde::de::Error::missing_field("access_key_id"))?;

Ok(Credentials {
access_key_id,
secret_access_key,
})
}
}

impl<'de> serde::Deserialize<'de> for Credentials {
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_struct("Credentials", FIELDS, CredentialsVisitor)
}
}

impl Credentials {
pub fn new(access_key_id: Option<&str>, secret_access_key: Option<SecStr>) -> Self {
let access_key_id_str = access_key_id.map(|r| r.to_string());
Expand All @@ -50,7 +123,7 @@ impl Credentials {
}
}

#[derive(Debug, Eq, PartialEq, Clone, Default, serde::Serialize)]
#[derive(Debug, Eq, PartialEq, Clone, Default, serde::Serialize, serde::Deserialize)]
pub struct Config {
pub region: Option<String>,
pub output_format: Option<String>,
Expand All @@ -68,7 +141,7 @@ impl Config {
}
}

#[derive(Debug, Eq, PartialEq, Clone, serde::Serialize)]
#[derive(Debug, Eq, PartialEq, Clone, serde::Serialize, serde::Deserialize)]
pub struct Profile {
pub name: String,
pub credentials: Credentials,
Expand Down Expand Up @@ -291,4 +364,22 @@ mod tests {

assert_eq!(serialized_profile_value, expected_value);
}

#[test]
fn should_deserialize_credentials() {
let data = r#"{
"access_key_id": "myAccessKey",
"secret_access_key": "mySecretKey"
}"#;

// Perform the deserialization
let deserialized: Credentials = serde_json::from_str(data).unwrap();

// Test the deserialized data
assert_eq!(deserialized.access_key_id, Some("myAccessKey".to_string()));
let secret_access_key =
std::str::from_utf8(deserialized.secret_access_key.as_ref().unwrap().unsecure())
.expect("secret access key should be serializable to be UTF-8 string");
assert_eq!(secret_access_key, "mySecretKey".to_string());
}
}

0 comments on commit 4c20a4b

Please sign in to comment.