ada-judge-app 0.2.12

Native desktop app for ada-judge
use crate::{
    AJAlertType, AJAppState, AJMainWindow, AJUserState, alert::show_alert, app_state::AppState,
    load_all,
};
use ada_judge_public_models::{
    DeletionRequest,
    users::{AdminLevel, PrivateUserData, PublicUserData},
};
use keyring::Entry;
use reqwest::StatusCode;
use slint::{ComponentHandle, ToSharedString, Weak};
use std::sync::Arc;
use tokio::sync::Mutex;

pub async fn load_account_data(state: Arc<Mutex<AppState>>, weak: Weak<AJMainWindow>) {
    if let Err(e) = load_account_data_impl(state.clone(), weak.clone()).await {
        show_alert(weak.clone(), e, AJAlertType::Error);
    }
}

pub async fn load_account_data_impl(
    state: Arc<Mutex<AppState>>,
    weak: Weak<AJMainWindow>,
) -> Result<(), anyhow::Error> {
    let client = reqwest::Client::new();
    let token = state.lock().await.token.clone();
    let base_url = state.lock().await.base_url.clone();
    let user = client
        .get(format!("{base_url}/users/me"))
        .bearer_auth(token)
        .send()
        .await?
        .json::<PrivateUserData>()
        .await?;
    state.lock().await.user = Some(user.clone());
    slint::invoke_from_event_loop(move || {
        if let Some(ui) = weak.upgrade() {
            ui.global::<AJUserState>().set_user(user.into());
        }
    })
    .unwrap();

    Ok(())
}

pub fn logout(state: Arc<Mutex<AppState>>, weak: Weak<AJMainWindow>) {
    tokio::spawn(async move {
        if let Err(e) = logout_impl(state.clone(), weak.clone()).await {
            show_alert(weak.clone(), e, AJAlertType::Error);
        }
    });
}

pub async fn logout_impl(
    _state: Arc<Mutex<AppState>>,
    weak: Weak<AJMainWindow>,
) -> Result<(), anyhow::Error> {
    let entry = Entry::new("com.oneprog.ada-judge", "jwt")?;
    entry.delete_credential()?;

    slint::invoke_from_event_loop(move || {
        if let Some(ui) = weak.upgrade() {
            ui.global::<AJAppState>().set_page(0);
        }
    })
    .unwrap();

    Ok(())
}

pub fn load_user_data(id: i64, state: Arc<Mutex<AppState>>, weak: Weak<AJMainWindow>) {
    tokio::spawn(async move {
        if let Err(e) = load_user_data_impl(id, state.clone(), weak.clone()).await {
            show_alert(weak.clone(), e, AJAlertType::Error);
        }
    });
}

pub async fn load_user_data_impl(
    id: i64,
    state: Arc<Mutex<AppState>>,
    weak: Weak<AJMainWindow>,
) -> Result<(), anyhow::Error> {
    let client = reqwest::Client::new();
    let token = state.lock().await.token.clone();
    let base_url = state.lock().await.base_url.clone();
    let current_user = state.lock().await.user.clone().unwrap();
    if current_user.admin_level != AdminLevel::Owner {
        let user = client
            .get(format!("{base_url}/users/{id}"))
            .bearer_auth(token)
            .send()
            .await?
            .json::<PublicUserData>()
            .await?;
        slint::invoke_from_event_loop(move || {
            if let Some(ui) = weak.upgrade() {
                ui.global::<AJAppState>()
                    .set_opened_user_public_profile(user.into());
                ui.global::<AJAppState>().set_page(7);
            }
        })
        .unwrap();
    } else {
        let user = client
            .get(format!("{base_url}/users/{id}/private"))
            .bearer_auth(token)
            .send()
            .await?
            .json::<PrivateUserData>()
            .await?;
        slint::invoke_from_event_loop(move || {
            if let Some(ui) = weak.upgrade() {
                ui.global::<AJAppState>()
                    .set_opened_user_private_profile(user.into());
                ui.global::<AJAppState>().set_page(8);
            }
        })
        .unwrap();
    }

    Ok(())
}

pub fn delete_my_account(
    login: String,
    password: String,
    password_confirmation: String,
    deletion_confirmation: bool,
    state: Arc<Mutex<AppState>>,
    weak: Weak<AJMainWindow>,
) {
    tokio::spawn(async move {
        if let Err(e) = delete_my_account_impl(
            login,
            password,
            password_confirmation,
            deletion_confirmation,
            state.clone(),
            weak.clone(),
        )
        .await
        {
            show_alert(weak.clone(), e, AJAlertType::Error);
        }
    });
}

pub async fn delete_my_account_impl(
    login: String,
    password: String,
    password_confirmation: String,
    deletion_confirmation: bool,
    state: Arc<Mutex<AppState>>,
    weak: Weak<AJMainWindow>,
) -> Result<(), anyhow::Error> {
    let client = reqwest::Client::new();
    let token = state.lock().await.token.clone();
    let base_url = state.lock().await.base_url.clone();
    let request = DeletionRequest {
        login,
        password,
        password_confirmation,
        deletion_confirmation,
    };
    let res = client
        .delete(format!("{base_url}/users/me/delete_account"))
        .bearer_auth(token.clone())
        .json(&request)
        .send()
        .await?;

    logout(state.clone(), weak.clone());

    match res.status() {
        StatusCode::OK => {
            show_alert(
                weak.clone(),
                "успешно".to_shared_string(),
                AJAlertType::Success,
            );
        }
        _ => {
            show_alert(
                weak.clone(),
                "ошибка".to_shared_string(),
                AJAlertType::Error,
            );
        }
    }

    Ok(())
}

pub fn delete_user_account(id: i32, state: Arc<Mutex<AppState>>, weak: Weak<AJMainWindow>) {
    tokio::spawn(async move {
        if let Err(e) = delete_user_account_impl(id, state.clone(), weak.clone()).await {
            show_alert(weak.clone(), e, AJAlertType::Error);
        }
    });
}

pub async fn delete_user_account_impl(
    id: i32,
    state: Arc<Mutex<AppState>>,
    weak: Weak<AJMainWindow>,
) -> Result<(), anyhow::Error> {
    let client = reqwest::Client::new();
    let token = state.lock().await.token.clone();
    let base_url = state.lock().await.base_url.clone();
    let res = client
        .delete(format!("{base_url}/users/{id}/delete_account"))
        .bearer_auth(token.clone())
        .send()
        .await?;

    {
        let weak = weak.clone();

        slint::invoke_from_event_loop(move || {
            if let Some(ui) = weak.upgrade() {
                ui.global::<AJAppState>().set_page(5);
            }
        })
        .unwrap();
    }

    match res.status() {
        StatusCode::OK => {
            show_alert(
                weak.clone(),
                "успешно".to_shared_string(),
                AJAlertType::Success,
            );
        }
        _ => {
            show_alert(
                weak.clone(),
                "ошибка".to_shared_string(),
                AJAlertType::Error,
            );
        }
    }
    Ok(())
}

pub fn change_user_admin_level(
    id: i32,
    admin_level: AdminLevel,
    state: Arc<Mutex<AppState>>,
    weak: Weak<AJMainWindow>,
) {
    tokio::spawn(async move {
        if let Err(e) =
            change_user_admin_level_impl(id, admin_level, state.clone(), weak.clone()).await
        {
            show_alert(weak.clone(), e, AJAlertType::Error);
        }
    });
}

pub async fn change_user_admin_level_impl(
    id: i32,
    admin_level: AdminLevel,
    state: Arc<Mutex<AppState>>,
    weak: Weak<AJMainWindow>,
) -> Result<(), anyhow::Error> {
    let client = reqwest::Client::new();
    let token = state.lock().await.token.clone();
    let base_url = state.lock().await.base_url.clone();
    let res = client
        .patch(format!("{base_url}/users/{id}/change_admin_level"))
        .bearer_auth(token.clone())
        .json(&admin_level)
        .send()
        .await?;

    load_all(state.clone(), weak.clone()).await;

    match res.status() {
        StatusCode::OK => {
            show_alert(
                weak.clone(),
                "успешно".to_shared_string(),
                AJAlertType::Success,
            );
        }
        _ => {
            show_alert(
                weak.clone(),
                "ошибка".to_shared_string(),
                AJAlertType::Error,
            );
        }
    }
    Ok(())
}