mirror of
https://github.com/storytold/artcraft.git
synced 2026-10-25 11:19:29 -04:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
06260277f7 |
@@ -0,0 +1 @@
|
||||
mod reset_artcraft_command;
|
||||
@@ -0,0 +1,34 @@
|
||||
use crate::core::commands::enqueue::image_edit::enqueue_contextual_edit_image_command::EnqueueContextualEditImageSuccessResponse;
|
||||
use crate::core::commands::response::shorthand::ResponseOrErrorMessage;
|
||||
use crate::core::commands::response::success_response_wrapper::SerializeMarker;
|
||||
use crate::core::state::app_preferences::app_preferences_manager::AppPreferencesManager;
|
||||
use crate::core::state::app_preferences::preferred_download_directory::PreferredDownloadDirectory;
|
||||
use crate::core::state::data_dir::app_data_root::AppDataRoot;
|
||||
use crate::services::storyteller::state::storyteller_credential_manager::StorytellerCredentialManager;
|
||||
use crate::services::storyteller::windows::clear_main_webview_window_storyteller_cookies::clear_main_webview_window_storyteller_cookies;
|
||||
use anyhow::anyhow;
|
||||
use errors::AnyhowResult;
|
||||
use log::{error, info};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use tauri::{AppHandle, State};
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct ResetArtcraftCommandResponse {
|
||||
pub success: bool,
|
||||
}
|
||||
|
||||
impl SerializeMarker for ResetArtcraftCommandResponse {}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn reset_artcraft_command(
|
||||
app: AppHandle,
|
||||
) -> ResponseOrErrorMessage<ResetArtcraftCommandResponse> {
|
||||
info!("reset_artcraft_command called");
|
||||
|
||||
// TODO: Reset local vs. production
|
||||
|
||||
Ok(ResetArtcraftCommandResponse {
|
||||
success: true,
|
||||
}.into())
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
pub mod app_preferences;
|
||||
pub mod app_state;
|
||||
pub mod enqueue;
|
||||
pub mod flip_image;
|
||||
pub mod get_app_info_command;
|
||||
|
||||
@@ -5,14 +5,13 @@ use crate::core::state::window::main_window_size::MainWindowSize;
|
||||
use crate::core::threads::main_window_thread::persist_storyteller_cookies_task::persist_storyteller_cookies_task;
|
||||
use crate::core::threads::main_window_thread::persist_window_position_task::persist_window_position_task;
|
||||
use crate::core::threads::main_window_thread::persist_window_resize_task::persist_window_resize_task;
|
||||
use crate::core::windows::main_window::constants::MAIN_WINDOW_NAME;
|
||||
use crate::services::storyteller::state::storyteller_credential_manager::StorytellerCredentialManager;
|
||||
use errors::AnyhowResult;
|
||||
use log::{error, info, warn};
|
||||
use memory_store::clone_slot::CloneSlot;
|
||||
use tauri::{AppHandle, Manager, Window};
|
||||
|
||||
const MAIN_WINDOW_NAME : &str = "main";
|
||||
|
||||
pub async fn main_window_thread(
|
||||
app: AppHandle,
|
||||
app_data_root: AppDataRoot,
|
||||
|
||||
-2
@@ -13,8 +13,6 @@ use tauri::{AppHandle, Manager};
|
||||
use tauri_plugin_http::reqwest_cookie_store::CookieStore;
|
||||
use tauri_plugin_http::Http;
|
||||
|
||||
const MAIN_WEBVIEW_NAME: &str = "main";
|
||||
|
||||
const STORYTELLER_ROOT_COOKIE_URL_STR: &str = "https://api.storyteller.ai/";
|
||||
|
||||
static STORYTELLER_ROOT_COOKIE_URL: Lazy<Url> = Lazy::new(|| {
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
/// This is the Artcraft application UX itself.
|
||||
pub const MAIN_WINDOW_NAME : &str = "main";
|
||||
|
||||
/// This is the name of the main window's main webview.
|
||||
pub const MAIN_WEBVIEW_NAME: &str = "main";
|
||||
|
||||
// TODO: handle pixel density, eg. retina displays
|
||||
/// This is the minimum width to resize the main window in an automated fashion
|
||||
pub const MAIN_WINDOW_MIN_WIDTH : u32 = 800;
|
||||
|
||||
@@ -48,6 +48,7 @@ use crate::services::sora::state::sora_task_queue::SoraTaskQueue;
|
||||
use crate::services::sora::threads::sora_task_polling_thread::sora_task_polling_thread;
|
||||
use crate::services::storyteller::commands::storyteller_get_credits_command::storyteller_get_credits_command;
|
||||
use crate::services::storyteller::commands::storyteller_get_subscription_command::storyteller_get_subscription_command;
|
||||
use crate::services::storyteller::commands::storyteller_purge_credentials_command::storyteller_purge_credentials_command;
|
||||
use crate::services::storyteller::commands::stripe_checkout::storyteller_open_credits_purchase_command::storyteller_open_credits_purchase_command;
|
||||
use crate::services::storyteller::commands::stripe_checkout::storyteller_open_subscription_purchase_command::storyteller_open_subscription_purchase_command;
|
||||
use crate::services::storyteller::commands::stripe_customer_portal::storyteller_open_customer_portal_cancel_plan_command::storyteller_open_customer_portal_cancel_plan_command;
|
||||
@@ -208,6 +209,7 @@ pub fn run() {
|
||||
storyteller_open_customer_portal_switch_plan_command,
|
||||
storyteller_open_customer_portal_update_payment_method_command,
|
||||
storyteller_open_subscription_purchase_command,
|
||||
storyteller_purge_credentials_command,
|
||||
update_app_preferences_command,
|
||||
]);
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
pub mod storyteller_purge_credentials_command;
|
||||
pub mod storyteller_get_credits_command;
|
||||
pub mod storyteller_get_subscription_command;
|
||||
pub mod stripe_checkout;
|
||||
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
use crate::core::commands::enqueue::image_edit::enqueue_contextual_edit_image_command::EnqueueContextualEditImageSuccessResponse;
|
||||
use crate::core::commands::response::shorthand::ResponseOrErrorMessage;
|
||||
use crate::core::commands::response::success_response_wrapper::SerializeMarker;
|
||||
use crate::core::state::app_preferences::app_preferences_manager::AppPreferencesManager;
|
||||
use crate::core::state::app_preferences::preferred_download_directory::PreferredDownloadDirectory;
|
||||
use crate::core::state::data_dir::app_data_root::AppDataRoot;
|
||||
use crate::services::storyteller::state::storyteller_credential_manager::StorytellerCredentialManager;
|
||||
use crate::services::storyteller::windows::clear_main_webview_window_storyteller_cookies::clear_main_webview_window_storyteller_cookies;
|
||||
use anyhow::anyhow;
|
||||
use errors::AnyhowResult;
|
||||
use log::{error, info};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use tauri::{AppHandle, State};
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct PurgeStorytellerCredentialsCommandResponse {
|
||||
pub success: bool,
|
||||
}
|
||||
|
||||
impl SerializeMarker for PurgeStorytellerCredentialsCommandResponse {}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn storyteller_purge_credentials_command(
|
||||
app: AppHandle,
|
||||
storyteller_creds_manager: State<'_, StorytellerCredentialManager>,
|
||||
) -> ResponseOrErrorMessage<PurgeStorytellerCredentialsCommandResponse> {
|
||||
info!("storyteller_purge_credentials_command called");
|
||||
|
||||
reset(&app, &storyteller_creds_manager)
|
||||
.await
|
||||
.map_err(|err| {
|
||||
error!("Error purging credentials: {:?}", err);
|
||||
format!("Error purging credentials: {:?}", err)
|
||||
})?;
|
||||
|
||||
Ok(PurgeStorytellerCredentialsCommandResponse {
|
||||
success: true,
|
||||
}.into())
|
||||
}
|
||||
|
||||
async fn reset(
|
||||
app: &AppHandle,
|
||||
storyteller_creds_manager: &StorytellerCredentialManager
|
||||
) -> AnyhowResult<()> {
|
||||
|
||||
clear_main_webview_window_storyteller_cookies(&app)?;
|
||||
|
||||
storyteller_creds_manager.clear_credentials()?;
|
||||
storyteller_creds_manager.delete_persisted_copies_on_disk()?;
|
||||
|
||||
// NB: Twice to be sure.
|
||||
storyteller_creds_manager.clear_credentials()?;
|
||||
storyteller_creds_manager.delete_persisted_copies_on_disk()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
+16
@@ -78,6 +78,22 @@ impl StorytellerCredentialManager {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn delete_persisted_copies_on_disk(&self) -> AnyhowResult<()> {
|
||||
let creds_dir = self.app_data_root.credentials_dir();
|
||||
|
||||
let session_file = creds_dir.get_storyteller_session_cookie_file_path();
|
||||
if session_file.exists() {
|
||||
std::fs::remove_file(session_file)?;
|
||||
}
|
||||
|
||||
let avt_file = creds_dir.get_storyteller_avt_cookie_file_path();
|
||||
if avt_file.exists() {
|
||||
std::fs::remove_file(avt_file)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn persist_session_to_disk(session: &StorytellerSessionCookie, app_data_root: &AppDataRoot) -> AnyhowResult<()> {
|
||||
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
use crate::core::windows::main_window::constants::MAIN_WINDOW_NAME;
|
||||
use errors::AnyhowResult;
|
||||
use log::warn;
|
||||
use tauri::webview::Cookie;
|
||||
use tauri::{AppHandle, Manager};
|
||||
|
||||
pub fn clear_main_webview_window_storyteller_cookies(app: &AppHandle) -> AnyhowResult<()> {
|
||||
let main_webview_window = app.get_webview_window(MAIN_WINDOW_NAME)
|
||||
.ok_or_else(|| anyhow::anyhow!("Main window not found"))?;
|
||||
|
||||
let cookies = main_webview_window.cookies()?;
|
||||
|
||||
let cookies_to_delete = get_cookies_to_delete(cookies);
|
||||
|
||||
let mut maybe_error = None;
|
||||
|
||||
for cookie in cookies_to_delete {
|
||||
if let Err(err) = main_webview_window.delete_cookie(cookie) {
|
||||
warn!("Failed to delete cookie: {:?}", err);
|
||||
maybe_error = Some(err);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(err) = maybe_error {
|
||||
return Err(anyhow::anyhow!("Failed to delete some cookies. Here's one failure: {:?}", err));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// TODO: This will need to handle local development, too.
|
||||
fn get_cookies_to_delete(cookies: Vec<Cookie>) -> Vec<Cookie> {
|
||||
cookies.into_iter()
|
||||
.filter(|cookie| {
|
||||
// Define your filtering logic here
|
||||
// For example, delete cookies with a specific name or domain
|
||||
match cookie.domain() {
|
||||
// storyteller.ai
|
||||
Some("api.storyteller.ai") => true,
|
||||
Some("storyteller.ai") => true,
|
||||
Some(domain) if domain.ends_with(".storyteller.ai") => true,
|
||||
// getartcraft.com
|
||||
Some("api.getartcraft.com") => true,
|
||||
Some("getartcraft.com") => true,
|
||||
Some(domain) if domain.ends_with(".getartcraft.com") => true,
|
||||
// artcraft.ai
|
||||
Some("api.artcraft.ai") => true,
|
||||
Some("artcraft.ai") => true,
|
||||
Some(domain) if domain.ends_with(".artcraft.ai") => true,
|
||||
// ignore all others
|
||||
None => false,
|
||||
Some(domain) => {
|
||||
warn!("Ignoring cookie with unrecognized domain: {}", domain);
|
||||
false
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
@@ -1,2 +1,3 @@
|
||||
pub mod clear_main_webview_window_storyteller_cookies;
|
||||
pub mod open_storyteller_billing_window;
|
||||
pub mod storyteller_billing_window_thread;
|
||||
+6
@@ -6,6 +6,7 @@ import { Button } from "@storyteller/ui-button";
|
||||
import { UsersApi } from "@storyteller/api";
|
||||
import { UserInfo } from "@storyteller/api";
|
||||
import { useLoginModalStore } from "@storyteller/ui-login-modal";
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
|
||||
const usersApi = new UsersApi();
|
||||
|
||||
@@ -52,7 +53,12 @@ export const ArtcraftAccountBlock = ({
|
||||
setIsLoggedIn(false);
|
||||
setIsCheckingArtcraftSession(false);
|
||||
globalAccountLogoutCallback(); // TODO: This resets the old global application state
|
||||
|
||||
|
||||
triggerRecheck(); // Trigger modal to recheck session and potentially open
|
||||
|
||||
await invoke("storyteller_purge_credentials_command");
|
||||
|
||||
} else {
|
||||
triggerRecheck(); // Open login modal instead of redirecting
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user