pass_manager/src/state/get_user.rs

166 lines
4.6 KiB
Rust
Raw Normal View History

2023-05-27 23:21:50 +00:00
use crate::{
errors::HandlerUsed,
markups::deletion_markup,
models::{DecryptedAccount, User},
utils::delete_optional,
MainDialogue,
2023-05-27 23:21:50 +00:00
};
use futures::TryStreamExt;
use itertools::Itertools;
2023-05-27 23:21:50 +00:00
use sea_orm::prelude::*;
use std::fmt::Write;
use teloxide::{adaptors::Throttle, net::Download, prelude::*, types::Document};
2023-05-27 23:21:50 +00:00
use tokio::task::spawn_blocking;
use trim_in_place::TrimInPlace;
#[inline]
async fn download_file(bot: &Throttle<Bot>, document: &Document) -> crate::Result<Vec<u8>> {
let path = bot.get_file(document.file.id.as_str()).await?.path;
let mut data = Vec::with_capacity(document.file.size as usize);
bot.download_file_stream(&path)
.try_for_each(|bytes| {
data.extend(bytes);
async { Ok(()) }
})
.await?;
Ok(data)
}
#[inline]
fn process_accounts(accounts: &mut [DecryptedAccount]) -> crate::Result<Result<(), String>> {
for account in accounts.iter_mut() {
account.name.trim_in_place();
account.login.trim_in_place();
account.password.trim_in_place();
}
accounts.sort_unstable_by(|a, b| a.name.cmp(&b.name));
let mut duplicates = Vec::new();
let mut invalid = Vec::new();
accounts
.iter()
.dedup_by_with_count(|a, b| a.name == b.name)
.for_each(|(count, account)| {
if count != 1 {
duplicates.push(account.name.as_str());
} else if !account.validate() {
invalid.push(account.name.as_str());
}
});
if duplicates.is_empty() && invalid.is_empty() {
return Ok(Ok(()));
}
let mut error_text = "Your accounts have the following problems:".to_owned();
if !duplicates.is_empty() {
write!(
error_text,
"\n\nDuplicate names:\n{:?}",
duplicates.into_iter().format("\n")
)?
}
if !invalid.is_empty() {
write!(
error_text,
"\n\nInvalid account fields:\n{:?}",
invalid.into_iter().format("\n")
)?
}
error_text.push_str("\n\nFix these problems and send the file again");
Ok(Err(error_text))
}
#[inline]
fn user_from_vec(vector: Vec<u8>) -> crate::Result<Result<User, String>> {
let mut user: User = serde_json::from_slice(&vector)?;
drop(vector);
match process_accounts(&mut user.accounts)? {
Ok(()) => Ok(Ok(user)),
Err(error_text) => Ok(Err(error_text)),
}
}
2023-05-27 23:21:50 +00:00
/// Function to handle GetUser state. It doesn't actually validate anything
pub async fn get_user(
bot: Throttle<Bot>,
msg: Message,
db: DatabaseConnection,
dialogue: MainDialogue,
next: super::PackagedHandler<User>,
) -> crate::Result<()> {
let mut handler = next.lock().await;
delete_optional(&bot, handler.previous.as_ref()).await;
if let Some("/cancel") = msg.text().map(str::trim_end) {
dialogue.exit().await?;
bot.send_message(msg.chat.id, "Successfully cancelled")
.reply_markup(deletion_markup())
.await?;
return Ok(());
}
if handler.func.is_none() {
let _ = dialogue.exit().await;
return Err(HandlerUsed.into());
}
let document = match msg.document() {
Some(document) => document,
None => {
let msg = bot
.send_message(msg.chat.id, "You didn't send a file. Try again")
.await?;
handler.previous = Some(msg);
return Ok(());
}
};
match document.file_name.as_deref() {
Some(name) if name.trim_end().ends_with(".json") => (),
_ => {
let msg = bot
.send_message(
msg.chat.id,
"Invalid file name. You need to send a json file. Try again",
)
.await?;
handler.previous = Some(msg);
return Ok(());
}
}
let data = download_file(&bot, document).await?;
2023-05-27 23:21:50 +00:00
let user = match spawn_blocking(move || user_from_vec(data)).await? {
Ok(Ok(user)) => user,
Ok(Err(error_text)) => {
let msg = bot.send_message(msg.chat.id, error_text).await?;
handler.previous = Some(msg);
return Ok(());
}
2023-05-27 23:21:50 +00:00
Err(_) => {
let msg = bot
.send_message(msg.chat.id, "Error parsing the json file. Try again")
.await?;
handler.previous = Some(msg);
return Ok(());
}
};
let func = handler.func.take().unwrap();
drop(handler);
if let Err(err) = func(bot, msg, db, dialogue.clone(), user).await {
let _ = dialogue.exit().await;
return Err(err);
}
Ok(())
}