Added NoUserInfo, NoMessageText and HandlerUsed error types to decrease the amount of unwraps

This commit is contained in:
StNicolay 2023-05-06 20:20:33 +03:00
parent c1e1b9c0c1
commit 71940762ff
Signed by: StNicolay
GPG Key ID: 9693D04DCD962B0D
18 changed files with 74 additions and 38 deletions

17
Cargo.lock generated
View File

@ -1303,9 +1303,9 @@ dependencies = [
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.142" version = "0.2.143"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a987beff54b60ffa6d51982e1aa1146bc42f19bd26be28b0586f252fccf5317" checksum = "edc207893e85c5d6be840e969b496b53d94cec8be2d501b214f50daa97fa8024"
[[package]] [[package]]
name = "libm" name = "libm"
@ -1582,6 +1582,7 @@ dependencies = [
"serde_json", "serde_json",
"sha2", "sha2",
"teloxide", "teloxide",
"thiserror",
"tokio", "tokio",
] ]
@ -2705,9 +2706,9 @@ dependencies = [
[[package]] [[package]]
name = "time" name = "time"
version = "0.3.20" version = "0.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd0cbfecb4d19b5ea75bb31ad904eb5b9fa13f21079c3b92017ebdf4999a5890" checksum = "8f3403384eaacbca9923fa06940178ac13e4edb725486d70e8e15881d0c836cc"
dependencies = [ dependencies = [
"itoa", "itoa",
"serde", "serde",
@ -2717,15 +2718,15 @@ dependencies = [
[[package]] [[package]]
name = "time-core" name = "time-core"
version = "0.1.0" version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb"
[[package]] [[package]]
name = "time-macros" name = "time-macros"
version = "0.2.8" version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd80a657e71da814b8e5d60d3374fc6d35045062245d80224748ae522dd76f36" checksum = "372950940a5f07bf38dbe211d7283c9e6d7327df53794992d293e534c733d09b"
dependencies = [ dependencies = [
"time-core", "time-core",
] ]

View File

@ -28,4 +28,5 @@ serde = "1.0.160"
serde_json = "1.0.96" serde_json = "1.0.96"
sha2 = "0.10.6" sha2 = "0.10.6"
teloxide = { version = "0.12.2", features = ["macros", "ctrlc_handler", "rustls", "throttle"], default-features = false } teloxide = { version = "0.12.2", features = ["macros", "ctrlc_handler", "rustls", "throttle"], default-features = false }
thiserror = "1.0.40"
tokio = { version = "1.27.0", features = ["macros", "rt-multi-thread"] } tokio = { version = "1.27.0", features = ["macros", "rt-multi-thread"] }

11
src/errors.rs Normal file
View File

@ -0,0 +1,11 @@
#[derive(thiserror::Error, Debug)]
#[error("No user info found")]
pub struct NoUserInfo;
#[derive(thiserror::Error, Debug)]
#[error("Message text not found")]
pub struct NoMessageText;
#[derive(thiserror::Error, Debug)]
#[error("Handler was already used")]
pub struct HandlerUsed;

View File

@ -1,4 +1,5 @@
use crate::entity::{account, prelude::Account}; use crate::entity::{account, prelude::Account};
use crate::errors::NoUserInfo;
use crate::handlers::{utils::package_handler, MainDialogue, State}; use crate::handlers::{utils::package_handler, MainDialogue, State};
use sea_orm::prelude::*; use sea_orm::prelude::*;
use teloxide::{adaptors::Throttle, prelude::*}; use teloxide::{adaptors::Throttle, prelude::*};
@ -16,7 +17,7 @@ async fn get_master_pass(
master_pass: String, master_pass: String,
) -> crate::Result<()> { ) -> crate::Result<()> {
let _ = bot.delete_message(previous.chat.id, previous.id).await; let _ = bot.delete_message(previous.chat.id, previous.id).await;
let user_id = msg.from().unwrap().id.0; let user_id = msg.from().ok_or(NoUserInfo)?.id.0;
dialogue.exit().await?; dialogue.exit().await?;
let account = spawn_blocking(move || { let account = spawn_blocking(move || {
account::ActiveModel::from_unencrypted(user_id, name, &login, &password, &master_pass) account::ActiveModel::from_unencrypted(user_id, name, &login, &password, &master_pass)
@ -91,7 +92,7 @@ async fn get_account_name(
name: String, name: String,
) -> crate::Result<()> { ) -> crate::Result<()> {
let _ = bot.delete_message(previous.chat.id, previous.id).await; let _ = bot.delete_message(previous.chat.id, previous.id).await;
let user_id = msg.from().unwrap().id.0; let user_id = msg.from().ok_or(NoUserInfo)?.id.0;
if Account::exists(user_id, &name, &db).await? { if Account::exists(user_id, &name, &db).await? {
bot.send_message(msg.chat.id, "Account alreay exists") bot.send_message(msg.chat.id, "Account alreay exists")
.await?; .await?;

View File

@ -1,5 +1,6 @@
use crate::{ use crate::{
entity::prelude::Account, entity::prelude::Account,
errors::NoUserInfo,
handlers::{markups, utils::package_handler, MainDialogue, State}, handlers::{markups, utils::package_handler, MainDialogue, State},
}; };
use sea_orm::prelude::*; use sea_orm::prelude::*;
@ -15,7 +16,7 @@ async fn get_master_pass(
) -> crate::Result<()> { ) -> crate::Result<()> {
let _ = bot.delete_message(previous.chat.id, previous.id).await; let _ = bot.delete_message(previous.chat.id, previous.id).await;
dialogue.exit().await?; dialogue.exit().await?;
let user_id = msg.from().unwrap().id.0; let user_id = msg.from().ok_or(NoUserInfo)?.id.0;
Account::delete_by_id((user_id, name)).exec(&db).await?; Account::delete_by_id((user_id, name)).exec(&db).await?;
bot.send_message(msg.chat.id, "The account is successfully deleted") bot.send_message(msg.chat.id, "The account is successfully deleted")
.await?; .await?;
@ -31,7 +32,7 @@ async fn get_account_name(
name: String, name: String,
) -> crate::Result<()> { ) -> crate::Result<()> {
let _ = bot.delete_message(previous.chat.id, previous.id).await; let _ = bot.delete_message(previous.chat.id, previous.id).await;
let user_id = msg.from().unwrap().id.0; let user_id = msg.from().ok_or(NoUserInfo)?.id.0;
if !Account::exists(user_id, &name, &db).await? { if !Account::exists(user_id, &name, &db).await? {
bot.send_message(msg.chat.id, "Account doesn't exists") bot.send_message(msg.chat.id, "Account doesn't exists")
.await?; .await?;
@ -56,7 +57,8 @@ pub async fn delete(
dialogue: MainDialogue, dialogue: MainDialogue,
db: DatabaseConnection, db: DatabaseConnection,
) -> crate::Result<()> { ) -> crate::Result<()> {
let markup = markups::account_markup(msg.from().unwrap().id.0, &db).await?; let user_id = msg.from().ok_or(NoUserInfo)?.id.0;
let markup = markups::account_markup(user_id, &db).await?;
let previous = bot let previous = bot
.send_message(msg.chat.id, "Send account name") .send_message(msg.chat.id, "Send account name")
.reply_markup(markup) .reply_markup(markup)

View File

@ -1,5 +1,6 @@
use crate::{ use crate::{
entity::{account, prelude::*}, entity::{account, prelude::*},
errors::NoUserInfo,
handlers::{utils::package_handler, MainDialogue, State}, handlers::{utils::package_handler, MainDialogue, State},
}; };
use sea_orm::prelude::*; use sea_orm::prelude::*;
@ -14,7 +15,7 @@ async fn get_master_pass(
) -> crate::Result<()> { ) -> crate::Result<()> {
let _ = bot.delete_message(previous.chat.id, previous.id).await; let _ = bot.delete_message(previous.chat.id, previous.id).await;
dialogue.exit().await?; dialogue.exit().await?;
let user_id = msg.from().unwrap().id.0; let user_id = msg.from().ok_or(NoUserInfo)?.id.0;
Account::delete_many() Account::delete_many()
.filter(account::Column::UserId.eq(user_id)) .filter(account::Column::UserId.eq(user_id))
.exec(&db) .exec(&db)

View File

@ -1,5 +1,6 @@
use crate::{ use crate::{
entity::prelude::Account, entity::prelude::Account,
errors::NoUserInfo,
handlers::{utils::package_handler, MainDialogue, State}, handlers::{utils::package_handler, MainDialogue, State},
models::{DecryptedAccount, User}, models::{DecryptedAccount, User},
}; };
@ -20,7 +21,7 @@ async fn get_master_pass(
) -> crate::Result<()> { ) -> crate::Result<()> {
let _ = bot.delete_message(previous.chat.id, previous.id).await; let _ = bot.delete_message(previous.chat.id, previous.id).await;
let master_pass: Arc<str> = master_pass.into(); let master_pass: Arc<str> = master_pass.into();
let user_id = msg.from().unwrap().id.0; let user_id = msg.from().ok_or(NoUserInfo)?.id.0;
let accounts = Arc::new(Mutex::new(Vec::new())); let accounts = Arc::new(Mutex::new(Vec::new()));
Account::get_all(user_id, &db) Account::get_all(user_id, &db)
.await? .await?

View File

@ -1,5 +1,6 @@
use crate::{ use crate::{
entity::{account, prelude::Account}, entity::{account, prelude::Account},
errors::NoUserInfo,
handlers::{markups, utils::package_handler, MainDialogue, State}, handlers::{markups, utils::package_handler, MainDialogue, State},
}; };
use sea_orm::prelude::*; use sea_orm::prelude::*;
@ -17,7 +18,7 @@ async fn get_master_pass(
) -> crate::Result<()> { ) -> crate::Result<()> {
let _ = bot.delete_message(previous.chat.id, previous.id).await; let _ = bot.delete_message(previous.chat.id, previous.id).await;
dialogue.exit().await?; dialogue.exit().await?;
let user_id = msg.from().unwrap().id.0; let user_id = msg.from().ok_or(NoUserInfo)?.id.0;
let account = Account::find() let account = Account::find()
.filter(account::Column::UserId.eq(user_id)) .filter(account::Column::UserId.eq(user_id))
.filter(account::Column::Name.eq(&name)) .filter(account::Column::Name.eq(&name))
@ -41,7 +42,7 @@ async fn get_account_name(
name: String, name: String,
) -> crate::Result<()> { ) -> crate::Result<()> {
let _ = bot.delete_message(previous.chat.id, previous.id).await; let _ = bot.delete_message(previous.chat.id, previous.id).await;
let user_id = msg.from().unwrap().id.0; let user_id = msg.from().ok_or(NoUserInfo)?.id.0;
if !Account::exists(user_id, &name, &db).await? { if !Account::exists(user_id, &name, &db).await? {
bot.send_message(msg.chat.id, "Account doesn't exists") bot.send_message(msg.chat.id, "Account doesn't exists")
.await?; .await?;
@ -66,7 +67,8 @@ pub async fn get_account(
dialogue: MainDialogue, dialogue: MainDialogue,
db: DatabaseConnection, db: DatabaseConnection,
) -> crate::Result<()> { ) -> crate::Result<()> {
let markup = markups::account_markup(msg.from().unwrap().id.0, &db).await?; let user_id = msg.from().ok_or(NoUserInfo)?.id.0;
let markup = markups::account_markup(user_id, &db).await?;
let previous = bot let previous = bot
.send_message(msg.chat.id, "Send account name") .send_message(msg.chat.id, "Send account name")
.reply_markup(markup) .reply_markup(markup)

View File

@ -1,4 +1,4 @@
use crate::entity::prelude::Account; use crate::{entity::prelude::Account, errors::NoUserInfo};
use futures::TryStreamExt; use futures::TryStreamExt;
use sea_orm::prelude::*; use sea_orm::prelude::*;
use teloxide::{adaptors::Throttle, prelude::*, types::ParseMode}; use teloxide::{adaptors::Throttle, prelude::*, types::ParseMode};
@ -8,7 +8,7 @@ pub async fn get_accounts(
msg: Message, msg: Message,
db: DatabaseConnection, db: DatabaseConnection,
) -> crate::Result<()> { ) -> crate::Result<()> {
let user_id = msg.from().unwrap().id.0; let user_id = msg.from().ok_or(NoUserInfo)?.id.0;
let mut account_names = Account::get_names(user_id, &db, true).await?; let mut account_names = Account::get_names(user_id, &db, true).await?;
let mut result = match account_names.try_next().await? { let mut result = match account_names.try_next().await? {
Some(name) => format!("Accounts:\n`{name}`"), Some(name) => format!("Accounts:\n`{name}`"),

View File

@ -1,4 +1,5 @@
use crate::{ use crate::{
errors::NoUserInfo,
handlers::{utils::package_handler, MainDialogue, State}, handlers::{utils::package_handler, MainDialogue, State},
models::{DecryptedAccount, User}, models::{DecryptedAccount, User},
}; };
@ -20,7 +21,7 @@ async fn get_master_pass(
accounts: Vec<DecryptedAccount>, accounts: Vec<DecryptedAccount>,
) -> crate::Result<()> { ) -> crate::Result<()> {
let _ = bot.delete_message(previous.chat.id, previous.id).await; let _ = bot.delete_message(previous.chat.id, previous.id).await;
let user_id = msg.from().unwrap().id.0; let user_id = msg.from().ok_or(NoUserInfo)?.id.0;
let master_pass: Arc<str> = master_pass.into(); let master_pass: Arc<str> = master_pass.into();
let failed = Arc::new(Mutex::new(Vec::new())); let failed = Arc::new(Mutex::new(Vec::new()));
stream::iter(accounts) stream::iter(accounts)

View File

@ -1,5 +1,6 @@
use crate::{ use crate::{
entity::{master_pass, prelude::*}, entity::{master_pass, prelude::*},
errors::NoUserInfo,
handlers::{utils::package_handler, MainDialogue, State}, handlers::{utils::package_handler, MainDialogue, State},
}; };
use sea_orm::prelude::*; use sea_orm::prelude::*;
@ -16,7 +17,7 @@ async fn get_master_pass(
) -> crate::Result<()> { ) -> crate::Result<()> {
let _ = bot.delete_message(previous.chat.id, previous.id).await; let _ = bot.delete_message(previous.chat.id, previous.id).await;
dialogue.exit().await?; dialogue.exit().await?;
let user_id = msg.from().unwrap().id.0; let user_id = msg.from().ok_or(NoUserInfo)?.id.0;
let model = task::spawn_blocking(move || { let model = task::spawn_blocking(move || {
master_pass::ActiveModel::from_unencrypted(user_id, &master_password) master_pass::ActiveModel::from_unencrypted(user_id, &master_password)
}) })
@ -32,7 +33,7 @@ pub async fn set_master_pass(
dialogue: MainDialogue, dialogue: MainDialogue,
db: DatabaseConnection, db: DatabaseConnection,
) -> crate::Result<()> { ) -> crate::Result<()> {
let user_id = msg.from().unwrap().id.0; let user_id = msg.from().ok_or(NoUserInfo)?.id.0;
if MasterPass::exists(user_id, &db).await? { if MasterPass::exists(user_id, &db).await? {
bot.send_message(msg.chat.id, "Master password already exists") bot.send_message(msg.chat.id, "Master password already exists")
.await?; .await?;

View File

@ -1,7 +1,7 @@
use sea_orm::prelude::*; use sea_orm::prelude::*;
use teloxide::{adaptors::Throttle, prelude::*}; use teloxide::{adaptors::Throttle, prelude::*};
use crate::PinnedFuture; use crate::{errors::HandlerUsed, PinnedFuture};
pub async fn generic<F>( pub async fn generic<F>(
bot: Throttle<Bot>, bot: Throttle<Bot>,
@ -37,5 +37,5 @@ where
return Err(err); return Err(err);
} }
}; };
next.lock().await.take().unwrap()(bot, msg, db, dialogue, text).await next.lock().await.take().ok_or(HandlerUsed)?(bot, msg, db, dialogue, text).await
} }

View File

@ -1,7 +1,10 @@
use sea_orm::prelude::*; use sea_orm::prelude::*;
use teloxide::{adaptors::Throttle, prelude::*}; use teloxide::{adaptors::Throttle, prelude::*};
use crate::handlers::{MainDialogue, PackagedHandler}; use crate::{
errors::NoMessageText,
handlers::{MainDialogue, PackagedHandler},
};
pub async fn get_account_name( pub async fn get_account_name(
bot: Throttle<Bot>, bot: Throttle<Bot>,
@ -10,7 +13,7 @@ pub async fn get_account_name(
dialogue: MainDialogue, dialogue: MainDialogue,
next: PackagedHandler<String>, next: PackagedHandler<String>,
) -> crate::Result<()> { ) -> crate::Result<()> {
let text = msg.text().unwrap().trim().to_owned(); let text = msg.text().ok_or(NoMessageText)?.trim().to_owned();
super::generic::generic( super::generic::generic(
bot, bot,
text, text,

View File

@ -1,4 +1,7 @@
use crate::handlers::{MainDialogue, PackagedHandler}; use crate::{
errors::HandlerUsed,
handlers::{MainDialogue, PackagedHandler},
};
use sea_orm::prelude::*; use sea_orm::prelude::*;
use teloxide::{adaptors::Throttle, prelude::*}; use teloxide::{adaptors::Throttle, prelude::*};
@ -9,5 +12,5 @@ pub async fn get_document(
dialogue: MainDialogue, dialogue: MainDialogue,
next: PackagedHandler<()>, next: PackagedHandler<()>,
) -> crate::Result<()> { ) -> crate::Result<()> {
next.lock().await.take().unwrap()(bot, msg, db, dialogue, ()).await next.lock().await.take().ok_or(HandlerUsed)?(bot, msg, db, dialogue, ()).await
} }

View File

@ -1,7 +1,10 @@
use sea_orm::prelude::*; use sea_orm::prelude::*;
use teloxide::{adaptors::Throttle, prelude::*}; use teloxide::{adaptors::Throttle, prelude::*};
use crate::handlers::{MainDialogue, PackagedHandler}; use crate::{
errors::NoMessageText,
handlers::{MainDialogue, PackagedHandler},
};
pub async fn get_login( pub async fn get_login(
bot: Throttle<Bot>, bot: Throttle<Bot>,
@ -10,7 +13,7 @@ pub async fn get_login(
dialogue: MainDialogue, dialogue: MainDialogue,
next: PackagedHandler<String>, next: PackagedHandler<String>,
) -> crate::Result<()> { ) -> crate::Result<()> {
let text = msg.text().unwrap().trim().to_owned(); let text = msg.text().ok_or(NoMessageText)?.trim().to_owned();
super::generic::generic( super::generic::generic(
bot, bot,
text, text,

View File

@ -1,5 +1,6 @@
use crate::{ use crate::{
entity::prelude::MasterPass, entity::prelude::MasterPass,
errors::{NoMessageText, NoUserInfo},
handlers::{MainDialogue, PackagedHandler}, handlers::{MainDialogue, PackagedHandler},
}; };
use sea_orm::prelude::*; use sea_orm::prelude::*;
@ -12,8 +13,8 @@ pub async fn check_master_pass<'a>(
db: &'a DatabaseConnection, db: &'a DatabaseConnection,
master_pass: &'a str, master_pass: &'a str,
) -> crate::Result<bool> { ) -> crate::Result<bool> {
let result = let user_id = msg.from().ok_or(NoUserInfo)?.id.0;
MasterPass::verify_master_pass(msg.from().unwrap().id.0, master_pass.to_owned(), db).await; let result = MasterPass::verify_master_pass(user_id, master_pass.to_owned(), db).await;
match result { match result {
Ok(Some(true)) => Ok(true), Ok(Some(true)) => Ok(true),
Ok(Some(false)) => { Ok(Some(false)) => {
@ -37,7 +38,7 @@ pub async fn get_master_pass(
dialogue: MainDialogue, dialogue: MainDialogue,
next: PackagedHandler<String>, next: PackagedHandler<String>,
) -> crate::Result<()> { ) -> crate::Result<()> {
let text = msg.text().unwrap().trim().to_owned(); let text = msg.text().ok_or(NoMessageText)?.trim().to_owned();
super::generic::generic( super::generic::generic(
bot, bot,
text, text,

View File

@ -1,7 +1,10 @@
use sea_orm::prelude::*; use sea_orm::prelude::*;
use teloxide::{adaptors::Throttle, prelude::*}; use teloxide::{adaptors::Throttle, prelude::*};
use crate::handlers::{MainDialogue, PackagedHandler}; use crate::{
errors::NoMessageText,
handlers::{MainDialogue, PackagedHandler},
};
pub async fn get_password( pub async fn get_password(
bot: Throttle<Bot>, bot: Throttle<Bot>,
@ -10,7 +13,7 @@ pub async fn get_password(
dialogue: MainDialogue, dialogue: MainDialogue,
next: PackagedHandler<String>, next: PackagedHandler<String>,
) -> crate::Result<()> { ) -> crate::Result<()> {
let text = msg.text().unwrap().trim().to_owned(); let text = msg.text().ok_or(NoMessageText)?.trim().to_owned();
super::generic::generic( super::generic::generic(
bot, bot,
text, text,

View File

@ -1,4 +1,5 @@
mod entity; mod entity;
mod errors;
mod handlers; mod handlers;
mod models; mod models;
@ -16,8 +17,8 @@ async fn main() -> Result<()> {
let _ = dotenv(); let _ = dotenv();
pretty_env_logger::init(); pretty_env_logger::init();
let token = env::var("TOKEN").unwrap(); let token = env::var("TOKEN").expect("expected TOKEN in the enviroment");
let database_url = env::var("DATABASE_URL").unwrap(); let database_url = env::var("DATABASE_URL").expect("expected DATABASE_URL in the enviroment");
let db = Database::connect(database_url).await?; let db = Database::connect(database_url).await?;
Migrator::up(&db, None).await?; Migrator::up(&db, None).await?;
get_dispatcher(token, db).dispatch().await; get_dispatcher(token, db).dispatch().await;