Skip to content

Commit

Permalink
refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
opeolluwa committed Sep 8, 2023
1 parent e01115d commit 4de3855
Show file tree
Hide file tree
Showing 9 changed files with 126 additions and 70 deletions.
4 changes: 1 addition & 3 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
{
"cSpell.words": [
"sqlx"
],
"cSpell.words": ["lettre", "sqlx"],
"workbench.colorCustomizations": {
"activityBar.background": "#462511",
"titleBar.activeBackground": "#613417",
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ authors = ["adeoye adefemi <[email protected]>"]
description = "a compilation of utility scripts for every day use in building applications and using certain features on my laptop"
edition = "2021"
name = "utils"
version = "0.1.0"
version = "0.5.22"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

Expand Down
64 changes: 39 additions & 25 deletions src/commands/email.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use std::fs;
use std::time::Duration;

use clap::{Args, Subcommand};
Expand All @@ -8,27 +7,27 @@ use lettre::message::{header, MultiPart, SinglePart};
use serde::{Deserialize, Serialize};
use serde_json::json;

use crate::ASSETS_DIR;
use crate::database::{self, SmtpCredentials};
// use crate::database::Database;
use crate::style::PrintColoredText;
use lettre::message::header::ContentType;

use lettre::transport::smtp::authentication::Credentials;
use lettre::{Message, SmtpTransport, Transport};

#[derive(clap::Args, Debug, Serialize)]
pub struct EmailCommands {
/// the email recipient
#[clap(short, long, value_parser)]
pub name: String,
pub name: Option<String>,
/// the recipient email address
#[clap(short, long, value_parser)]
pub email: String,
pub email: Option<String>,
/// the message content
#[clap(short, long, value_parser)]
pub subject: String,
pub subject: Option<String>,
/// body/content of the message
#[clap(short, long, value_parser)]
pub body: Vec<String>, //
pub body: Option<Vec<String>>, //
/// the email history
#[command(subcommand)]
pub subcommands: Option<EmailSubCommands>,
Expand Down Expand Up @@ -71,25 +70,37 @@ pub struct ConfigOptions {
/// utils email delete --id 76c310d6-2bda-58ae-8cc6-885df4fa2f99
impl EmailCommands {
/// parse the commands
pub fn parse(&self) {
println!("{:?}", self);

if self.subcommands.is_none() {
//send email
}
pub async fn parse(&self) {
if let Some(command) = &self.subcommands {
match command {
EmailSubCommands::History => self.list(),
EmailSubCommands::Delete { id } => self.delete(id),
EmailSubCommands::Config(config) => self.config(config),
}
} else {
macro_rules! check_required_field {
($self:expr, $field:ident) => {
if let Some($field) = $self.$field.clone() {
$field
} else {
PrintColoredText::warning(&format!("{} is required", stringify!($field)));
return;
}
};
}

let name = check_required_field!(self, name);
let email = check_required_field!(self, email);
let subject = check_required_field!(self, subject);
let body = check_required_field!(self, body);

self.send(&SendOptions {
name: self.name.clone(),
email: self.email.clone(),
subject: self.subject.clone(),
body: self.body.clone(),
name,
email,
subject,
body,
})
.await
}
}

Expand All @@ -102,16 +113,19 @@ impl EmailCommands {
}

fn config(&self, config: &ConfigOptions) {
// dave config to database
// save config to database
println!("{:?}", config)
}

fn send(&self, data: &SendOptions) {
//TODO get the email credentials from the database

//TODO throw error if not found
async fn send(&self, data: &SendOptions) {
/* get the email credentials from the database
* if not found, prompt the user to enter the credentials
*/
let SmtpCredentials {
smtp_username,
smtp_password,
} = database::SmtpCredentials::fetch().await;

// if found use the template to send email
let prompt = format!("Proceed to send email to {email}?", email = data.email);
if Confirm::new()
.with_prompt(prompt)
Expand Down Expand Up @@ -163,7 +177,7 @@ impl EmailCommands {
.singlepart(
SinglePart::builder()
.header(header::ContentType::TEXT_HTML)
.body(String::from(html)),
.body(html),
),
).ok();

Expand All @@ -174,7 +188,7 @@ impl EmailCommands {
return;
};

let credentials = Credentials::new("".to_owned(), "".to_owned());
let credentials = Credentials::new(smtp_username, smtp_password);

// Open a remote connection to gmail
let mailer = SmtpTransport::relay("smtp.gmail.com")
Expand Down
10 changes: 5 additions & 5 deletions src/commands/readme.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ impl ReadmeCommands {
} else {
// remove the current readme and create a new one
fs::remove_file(path).unwrap();
ReadmeCommands::new(path, &self.title, &self.description);
ReadmeCommands::create_new(path, &self.title, &self.description);
}
}
// if the readme exist and the force flag is set, backup the existing readme
Expand All @@ -79,16 +79,16 @@ impl ReadmeCommands {
let backup_path = Path::new(&self.path).join("README.md.bak");
fs::copy(path, backup_path).expect("failed to create backup");
// create the readme
ReadmeCommands::new(path, &self.title, &self.description);
ReadmeCommands::create_new(path, &self.title, &self.description);
}
} else {
// if the readme does not exist, create it
ReadmeCommands::new(path, &self.title, &self.description);
ReadmeCommands::create_new(path, &self.title, &self.description);
}
}

/// create a new readem
fn new(path: &Path, title: &str, description: &str) {
/// create a new readme
fn create_new(path: &Path, title: &str, description: &str) {
let mut file = File::create(path).unwrap();
file.write_all(ReadmeCommands::get_template(title, description).as_bytes())
.unwrap();
Expand Down
29 changes: 0 additions & 29 deletions src/config.rs

This file was deleted.

77 changes: 77 additions & 0 deletions src/database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,13 @@ impl Database {
let store_create_table =
"CREATE TABLE IF NOT EXISTS store (id VARCHAR, key VARCHAR, value TEXT, date_added TEXT, last_updated TEXT)";

let config_table =
"CREATE TABLE IF NOT EXISTS config ( id INTEGER PRIMARY KEY DEFAULT 1, smtp_username VARCHAR, smtp_password VARCHAR)";

let db = SqlitePool::connect(&DB_URL).await.unwrap();
let _ = sqlx::query(store_create_table).execute(&db).await.unwrap();
let _ = sqlx::query(email_create_table).execute(&db).await.unwrap();
let _ = sqlx::query(config_table).execute(&db).await.unwrap();
}

// return connection to the database;
Expand Down Expand Up @@ -199,3 +203,76 @@ impl Store {
PrintColoredText::success(&message);
}
}

#[derive(Debug, Clone, Serialize, FromRow, Deserialize)]
pub struct Email {
pub id: String,
pub name: String,
pub email: String,
pub message: String,
pub date: String,
}

impl Default for Email {
fn default() -> Self {
Self {
id: Uuid::new_v4().to_string(),
name: Default::default(),
email: Default::default(),
message: Default::default(),
date: Local::now().to_rfc2822(),
}
}
}

#[derive(Debug, Clone, Serialize, FromRow, Deserialize, Default)]
pub struct SmtpCredentials {
pub smtp_username: String,
pub smtp_password: String,
}

impl SmtpCredentials {
pub async fn save(&self) -> Result<Self, ()> {
let db = Database::conn().await;
let _ = sqlx::query(
"INSERT OR REPLACE INTO config (id, smtp_username, smtp_password) VALUES (1,?,?)",
)
.bind(self.smtp_username.clone())
.bind(self.smtp_password.clone())
.execute(&db)
.await
.unwrap();

Ok(Self { ..self.clone() })
}

pub async fn fetch() -> Self {
let db = Database::conn().await;
let result = sqlx::query_as::<_, Self>("SELECT * FROM config")
.fetch_one(&db)
.await
.ok();

if result.is_none() {
let smtp_username = dialoguer::Input::new()
.with_prompt("SMTP Username?")
.interact_text()
.expect("error reading input");

let smtp_password = dialoguer::Input::new()
.with_prompt("SMTP Password?")
.interact_text()
.expect("error reading input");

let smtp_creds = SmtpCredentials {
smtp_username,
smtp_password,
};

smtp_creds.save().await.unwrap();
return smtp_creds;
}

result.unwrap()
}
}
6 changes: 1 addition & 5 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,20 @@ lazy_static! {
let db_path = format!(
"{home_dir}/{upload_dir}",
home_dir = os_default_home_dir.display(),
upload_dir = "utils"
upload_dir = ".utils"
);
// create the path if not exist path if not exist
let _ = std::fs::create_dir_all(&db_path);
format!("sqlite://{db_path}/utils.db")
};
}
mod commands;
mod config;
mod database;
mod parser;
mod style;
mod utils;
#[tokio::main]
async fn main() {
// let src_path = "/email.hbs";
// let file_path = ASSETS_DIR.path();
// println!("{:?}", file_path);
database::Database::init().await;
parser::Utils::run().await;
}
2 changes: 1 addition & 1 deletion src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ impl Utils {
let utils = Utils::parse();
match utils.command {
Commands::Ignore(git_ignore) => git_ignore.parse(),
Commands::Mailto(email) => email.parse(),
Commands::Mailto(email) => email.parse().await,
Commands::Readme(readme) => readme.parse(),
Commands::Store { key, value } => {
// TODO: handle conflict
Expand Down

0 comments on commit 4de3855

Please sign in to comment.