Added checks if the account already exists in the database
This commit is contained in:
		@@ -1,12 +1,14 @@
 | 
			
		||||
use crate::{
 | 
			
		||||
    errors::HandlerUsed,
 | 
			
		||||
    errors::{HandlerUsed, NoUserInfo},
 | 
			
		||||
    markups::deletion_markup,
 | 
			
		||||
    models::{DecryptedAccount, User},
 | 
			
		||||
    utils::delete_optional,
 | 
			
		||||
    MainDialogue,
 | 
			
		||||
};
 | 
			
		||||
use futures::TryStreamExt;
 | 
			
		||||
use entity::prelude::*;
 | 
			
		||||
use futures::{future::try_join, TryStreamExt};
 | 
			
		||||
use itertools::Itertools;
 | 
			
		||||
use rustc_hash::FxHashSet;
 | 
			
		||||
use sea_orm::prelude::*;
 | 
			
		||||
use std::fmt::Write;
 | 
			
		||||
use teloxide::{adaptors::Throttle, net::Download, prelude::*, types::Document};
 | 
			
		||||
@@ -27,7 +29,10 @@ async fn download_file(bot: &Throttle<Bot>, document: &Document) -> crate::Resul
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[inline]
 | 
			
		||||
fn process_accounts(accounts: &mut [DecryptedAccount]) -> crate::Result<Result<(), String>> {
 | 
			
		||||
fn process_accounts(
 | 
			
		||||
    accounts: &mut [DecryptedAccount],
 | 
			
		||||
    existing_names: FxHashSet<String>,
 | 
			
		||||
) -> crate::Result<Result<(), String>> {
 | 
			
		||||
    for account in accounts.iter_mut() {
 | 
			
		||||
        account.name.trim_in_place();
 | 
			
		||||
        account.login.trim_in_place();
 | 
			
		||||
@@ -37,20 +42,30 @@ fn process_accounts(accounts: &mut [DecryptedAccount]) -> crate::Result<Result<(
 | 
			
		||||
    accounts.sort_unstable_by(|a, b| a.name.cmp(&b.name));
 | 
			
		||||
 | 
			
		||||
    let mut duplicates = Vec::new();
 | 
			
		||||
    let mut existing = 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 {
 | 
			
		||||
            let duplicate = count != 1;
 | 
			
		||||
            let exists = existing_names.contains(&account.name);
 | 
			
		||||
            if duplicate {
 | 
			
		||||
                duplicates.push(account.name.as_str());
 | 
			
		||||
            } else if !account.validate() {
 | 
			
		||||
            }
 | 
			
		||||
            if exists {
 | 
			
		||||
                existing.push(account.name.as_str())
 | 
			
		||||
            }
 | 
			
		||||
            // If it already exists or if it is a duplicate there's no need to check the account's validity
 | 
			
		||||
            if !duplicate && !exists && !account.validate() {
 | 
			
		||||
                invalid.push(account.name.as_str());
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
    if duplicates.is_empty() && invalid.is_empty() {
 | 
			
		||||
    drop(existing_names);
 | 
			
		||||
 | 
			
		||||
    if duplicates.is_empty() && invalid.is_empty() && existing.is_empty() {
 | 
			
		||||
        return Ok(Ok(()));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -64,6 +79,14 @@ fn process_accounts(accounts: &mut [DecryptedAccount]) -> crate::Result<Result<(
 | 
			
		||||
        )?
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if !existing.is_empty() {
 | 
			
		||||
        write!(
 | 
			
		||||
            error_text,
 | 
			
		||||
            "\n\nAccounts with these names already exist in the database:\n{:?}",
 | 
			
		||||
            existing.into_iter().format("\n")
 | 
			
		||||
        )?
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if !invalid.is_empty() {
 | 
			
		||||
        write!(
 | 
			
		||||
            error_text,
 | 
			
		||||
@@ -78,10 +101,13 @@ fn process_accounts(accounts: &mut [DecryptedAccount]) -> crate::Result<Result<(
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[inline]
 | 
			
		||||
fn user_from_vec(vector: Vec<u8>) -> crate::Result<Result<User, String>> {
 | 
			
		||||
fn user_from_vec(
 | 
			
		||||
    vector: Vec<u8>,
 | 
			
		||||
    existing_names: FxHashSet<String>,
 | 
			
		||||
) -> crate::Result<Result<User, String>> {
 | 
			
		||||
    let mut user: User = serde_json::from_slice(&vector)?;
 | 
			
		||||
    drop(vector);
 | 
			
		||||
    match process_accounts(&mut user.accounts)? {
 | 
			
		||||
    match process_accounts(&mut user.accounts, existing_names)? {
 | 
			
		||||
        Ok(()) => Ok(Ok(user)),
 | 
			
		||||
        Err(error_text) => Ok(Err(error_text)),
 | 
			
		||||
    }
 | 
			
		||||
@@ -95,6 +121,7 @@ pub async fn get_user(
 | 
			
		||||
    dialogue: MainDialogue,
 | 
			
		||||
    next: super::PackagedHandler<User>,
 | 
			
		||||
) -> crate::Result<()> {
 | 
			
		||||
    let user_id = msg.from().ok_or(NoUserInfo)?.id.0;
 | 
			
		||||
    let mut handler = next.lock().await;
 | 
			
		||||
    delete_optional(&bot, handler.previous.as_ref()).await;
 | 
			
		||||
 | 
			
		||||
@@ -136,9 +163,17 @@ pub async fn get_user(
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let data = download_file(&bot, document).await?;
 | 
			
		||||
    let existing_names = async {
 | 
			
		||||
        Account::get_names(user_id, &db)
 | 
			
		||||
            .await?
 | 
			
		||||
            .try_collect::<FxHashSet<_>>()
 | 
			
		||||
            .await
 | 
			
		||||
            .map_err(Into::into)
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    let user = match spawn_blocking(move || user_from_vec(data)).await? {
 | 
			
		||||
    let (data, existing_names) = try_join(download_file(&bot, document), existing_names).await?;
 | 
			
		||||
 | 
			
		||||
    let user = match spawn_blocking(move || user_from_vec(data, existing_names)).await? {
 | 
			
		||||
        Ok(Ok(user)) => user,
 | 
			
		||||
        Ok(Err(error_text)) => {
 | 
			
		||||
            let msg = bot.send_message(msg.chat.id, error_text).await?;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user