forked from Roflin/gamenight
		
	Refactored the connect flow and make canceling behavior more consistent.
This commit is contained in:
		
							parent
							
								
									f0883a0ff0
								
							
						
					
					
						commit
						3f51d52edf
					
				@ -245,6 +245,9 @@ components:
 | 
			
		||||
          type: string
 | 
			
		||||
        datetime:
 | 
			
		||||
          type: string
 | 
			
		||||
      required:
 | 
			
		||||
        - name
 | 
			
		||||
        - datetime
 | 
			
		||||
    GamenightId:
 | 
			
		||||
      title: GamenightId
 | 
			
		||||
      type: object
 | 
			
		||||
 | 
			
		||||
@ -11,9 +11,9 @@ use crate::request::error::ApiError;
 | 
			
		||||
impl AddGamenightRequestBody {
 | 
			
		||||
    pub fn into_with_user(&self, user: AuthUser) -> Result<gamenight::Gamenight, ParseError> {
 | 
			
		||||
        Ok(gamenight::Gamenight {
 | 
			
		||||
            datetime: DateTime::parse_from_rfc3339(&self.clone().datetime.unwrap())?.with_timezone(&chrono::Utc),
 | 
			
		||||
            datetime: DateTime::parse_from_rfc3339(&self.datetime)?.with_timezone(&chrono::Utc),
 | 
			
		||||
            id: Uuid::new_v4(),
 | 
			
		||||
            name: self.clone().name.unwrap().clone(),
 | 
			
		||||
            name: self.name.clone(),
 | 
			
		||||
            owner_id: user.0.id
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -4,8 +4,8 @@
 | 
			
		||||
 | 
			
		||||
Name | Type | Description | Notes
 | 
			
		||||
------------ | ------------- | ------------- | -------------
 | 
			
		||||
**name** | Option<**String**> |  | [optional]
 | 
			
		||||
**datetime** | Option<**String**> |  | [optional]
 | 
			
		||||
**name** | **String** |  | 
 | 
			
		||||
**datetime** | **String** |  | 
 | 
			
		||||
 | 
			
		||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -13,17 +13,17 @@ use serde::{Deserialize, Serialize};
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
 | 
			
		||||
pub struct AddGamenightRequestBody {
 | 
			
		||||
    #[serde(rename = "name", skip_serializing_if = "Option::is_none")]
 | 
			
		||||
    pub name: Option<String>,
 | 
			
		||||
    #[serde(rename = "datetime", skip_serializing_if = "Option::is_none")]
 | 
			
		||||
    pub datetime: Option<String>,
 | 
			
		||||
    #[serde(rename = "name")]
 | 
			
		||||
    pub name: String,
 | 
			
		||||
    #[serde(rename = "datetime")]
 | 
			
		||||
    pub datetime: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl AddGamenightRequestBody {
 | 
			
		||||
    pub fn new() -> AddGamenightRequestBody {
 | 
			
		||||
    pub fn new(name: String, datetime: String) -> AddGamenightRequestBody {
 | 
			
		||||
        AddGamenightRequestBody {
 | 
			
		||||
            name: None,
 | 
			
		||||
            datetime: None,
 | 
			
		||||
            name,
 | 
			
		||||
            datetime,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -19,26 +19,27 @@ impl AddGamenight {
 | 
			
		||||
#[async_trait]
 | 
			
		||||
impl<'a> Flow<'a> for AddGamenight {
 | 
			
		||||
    async fn run(&self, state: &'a mut GamenightState) -> FlowResult<'a> {
 | 
			
		||||
        let mut add_gamenight = models::AddGamenightRequestBody::new();
 | 
			
		||||
 | 
			
		||||
        add_gamenight.name = Some(Text::new("What should we call your gamenight")
 | 
			
		||||
            .prompt()?);
 | 
			
		||||
        let naive_date = DateSelect::new("When is your gamenight")
 | 
			
		||||
            .prompt()?;
 | 
			
		||||
        let naive_time = CustomType::<NaiveTime>::new("At What time")
 | 
			
		||||
            .prompt()?;
 | 
			
		||||
        add_gamenight.datetime = Some(naive_date
 | 
			
		||||
            .and_time(naive_time)
 | 
			
		||||
            .and_local_timezone(Local)
 | 
			
		||||
            .earliest()
 | 
			
		||||
            .unwrap()
 | 
			
		||||
            .to_utc()
 | 
			
		||||
            .to_rfc3339());
 | 
			
		||||
 | 
			
		||||
        post_gamenight(&state.api_configuration, Some(add_gamenight)).await?;
 | 
			
		||||
        
 | 
			
		||||
        clear_screen::clear();
 | 
			
		||||
        Ok((FlowOutcome::Successful, state))
 | 
			
		||||
        if let Some(name) = Text::new("What should we call your gamenight").prompt_skippable()? {
 | 
			
		||||
            if let Some(naive_date) = DateSelect::new("When is your gamenight").prompt_skippable()? {
 | 
			
		||||
                if let Some(naive_time) = CustomType::<NaiveTime>::new("At What time").prompt_skippable()? {
 | 
			
		||||
                    
 | 
			
		||||
                    let datetime = naive_date
 | 
			
		||||
                        .and_time(naive_time)
 | 
			
		||||
                        .and_local_timezone(Local)
 | 
			
		||||
                        .earliest()
 | 
			
		||||
                        .unwrap()
 | 
			
		||||
                        .to_utc()
 | 
			
		||||
                        .to_rfc3339();
 | 
			
		||||
                    let add_gamenight = models::AddGamenightRequestBody::new(name, datetime);
 | 
			
		||||
                    post_gamenight(&state.api_configuration, Some(add_gamenight)).await?;
 | 
			
		||||
 | 
			
		||||
                    clear_screen::clear();
 | 
			
		||||
                    return Ok((FlowOutcome::Successful, state))
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        Ok((FlowOutcome::Cancelled, state))
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,9 +1,10 @@
 | 
			
		||||
use std::fmt::Display;
 | 
			
		||||
 | 
			
		||||
use async_trait::async_trait;
 | 
			
		||||
use gamenight_api_client_rs::apis::configuration::Configuration;
 | 
			
		||||
use inquire::Text;
 | 
			
		||||
 | 
			
		||||
use crate::{domain::config::{Config, Instance}, flows::{gamenight_menu::GamenightMenu, login::Login}};
 | 
			
		||||
use crate::{domain::config::{Config, Instance}, flows::{gamenight_menu::GamenightMenu, login::Login, FlowError}};
 | 
			
		||||
 | 
			
		||||
use super::{Flow, FlowOutcome, FlowResult, GamenightState};
 | 
			
		||||
 | 
			
		||||
@ -24,6 +25,64 @@ impl Connect {
 | 
			
		||||
            instance: None
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn prompt_new_instance(&self, config: &Config) -> Result<Option<Instance>, FlowError> {
 | 
			
		||||
        let instance_name: String;
 | 
			
		||||
        loop {
 | 
			
		||||
            if let Some(name) = Text::new("Name this instance:").prompt_skippable()? {
 | 
			
		||||
                if config.instances.iter().find(|x| x.name == name).is_none() {
 | 
			
		||||
                    instance_name = name;
 | 
			
		||||
                    break;
 | 
			
		||||
                } else {
 | 
			
		||||
                    clear_screen::clear();
 | 
			
		||||
                    println!("Name already in use, please provide a unique name");
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                return Ok(None);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if let Some(url) = Text::new("What is the server URL: ").prompt_skippable()? {
 | 
			
		||||
            Ok(Some(Instance::new(instance_name, url)))
 | 
			
		||||
        } else {
 | 
			
		||||
            Ok(None)
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub async fn try_refresh_token_if_exists(&self, instance: &mut Instance, api_configuration: &mut Configuration, config: &mut Config, instance_name: &String) -> Result<bool, FlowError> {
 | 
			
		||||
        if let Some(token) = &instance.token {
 | 
			
		||||
            api_configuration.bearer_access_token = Some(token.clone());
 | 
			
		||||
            let result = gamenight_api_client_rs::apis::default_api::post_token(api_configuration).await;
 | 
			
		||||
            if let Ok(token) = result {
 | 
			
		||||
                let instance = config.instances.iter_mut().find(|x| x.name == *instance_name).unwrap();
 | 
			
		||||
                instance.token = token.jwt_token.clone();
 | 
			
		||||
                api_configuration.bearer_access_token = token.jwt_token.clone();
 | 
			
		||||
                Config::save(&config)?;
 | 
			
		||||
                Ok(true)
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                Ok(false)
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            Ok(false)   
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn update_state_on_logon(&self, instance: &mut Instance, api_configuration: &mut Configuration, config: &mut Config, instance_name: &String) -> Result<(), FlowError> {
 | 
			
		||||
        if self.instance.is_none() {
 | 
			
		||||
            instance.token = Some(api_configuration.bearer_access_token.clone().unwrap());
 | 
			
		||||
            config.instances.push(instance.clone());
 | 
			
		||||
        } 
 | 
			
		||||
        else {
 | 
			
		||||
            let instance = config.instances.iter_mut().find(|x| x.name == *instance_name).unwrap();
 | 
			
		||||
            instance.token = Some(api_configuration.bearer_access_token.clone().unwrap());
 | 
			
		||||
        }
 | 
			
		||||
        config.last_instance = Some(instance_name.clone());
 | 
			
		||||
       
 | 
			
		||||
        Config::save(&config)?;
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[async_trait]
 | 
			
		||||
@ -32,58 +91,39 @@ impl<'a> Flow<'a> for Connect {
 | 
			
		||||
        let mut instance = if let Some(instance) = self.instance.clone() {
 | 
			
		||||
            instance
 | 
			
		||||
        } else {
 | 
			
		||||
            let mut name: String;
 | 
			
		||||
            loop {
 | 
			
		||||
                name = Text::new("Name this instance: ").prompt()?;
 | 
			
		||||
                if state.gamenight_configuration.instances.iter().find(|x| x.name == name).is_none() {
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                clear_screen::clear();
 | 
			
		||||
                println!("Name already in use, please provide a unique name");
 | 
			
		||||
            if let Some(instance) = self.prompt_new_instance(&state.gamenight_configuration)? {
 | 
			
		||||
                instance
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                return Ok((FlowOutcome::Cancelled, state));
 | 
			
		||||
            }
 | 
			
		||||
            let url = Text::new("What is the server URL: ").prompt()?;
 | 
			
		||||
            Instance::new(name, url)
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        let instance_name = instance.name.clone();
 | 
			
		||||
 | 
			
		||||
        state.api_configuration.base_path = instance.url.clone();
 | 
			
		||||
        if let Some(token) = instance.token {
 | 
			
		||||
            state.api_configuration.bearer_access_token = Some(token);
 | 
			
		||||
            let result = gamenight_api_client_rs::apis::default_api::post_token(&state.api_configuration).await;
 | 
			
		||||
            if let Ok(token) = result {
 | 
			
		||||
                let instance = state.gamenight_configuration.instances.iter_mut().find(|x| x.name == instance_name).unwrap();
 | 
			
		||||
                instance.token = token.jwt_token.clone();
 | 
			
		||||
                state.api_configuration.bearer_access_token = token.jwt_token.clone();
 | 
			
		||||
                Config::save(&state.gamenight_configuration)?;
 | 
			
		||||
                let gamenight_menu_flow = GamenightMenu::new();
 | 
			
		||||
                return gamenight_menu_flow.run(state).await
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let login_flow = Login::new();
 | 
			
		||||
        let (outcome, state) = login_flow.run(state).await?;
 | 
			
		||||
 | 
			
		||||
        if outcome == FlowOutcome::Successful {
 | 
			
		||||
            if self.instance.is_none() {
 | 
			
		||||
                instance.token = Some(state.api_configuration.bearer_access_token.clone().unwrap());
 | 
			
		||||
                state.gamenight_configuration.instances.push(instance.clone());
 | 
			
		||||
            } 
 | 
			
		||||
            else {
 | 
			
		||||
                let instance = state.gamenight_configuration.instances.iter_mut().find(|x| x.name == instance_name).unwrap();
 | 
			
		||||
                instance.token = Some(state.api_configuration.bearer_access_token.clone().unwrap());
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            state.gamenight_configuration.last_instance = Some(instance_name);
 | 
			
		||||
            
 | 
			
		||||
            Config::save(&state.gamenight_configuration)?;
 | 
			
		||||
 | 
			
		||||
        if self.try_refresh_token_if_exists(&mut instance, &mut state.api_configuration, &mut state.gamenight_configuration, &instance_name).await? {
 | 
			
		||||
            let gamenight_menu_flow = GamenightMenu::new();
 | 
			
		||||
            gamenight_menu_flow.run(state).await
 | 
			
		||||
        }
 | 
			
		||||
        } 
 | 
			
		||||
        else {
 | 
			
		||||
            Ok((outcome, state))
 | 
			
		||||
            let login_flow = Login::new();
 | 
			
		||||
            let (outcome, state) = login_flow.run(state).await?;
 | 
			
		||||
 | 
			
		||||
            if outcome == FlowOutcome::Successful {
 | 
			
		||||
                self.update_state_on_logon(&mut instance, &mut state.api_configuration, &mut state.gamenight_configuration, &instance_name)?;
 | 
			
		||||
 
 | 
			
		||||
                let gamenight_menu_flow = GamenightMenu::new();
 | 
			
		||||
                gamenight_menu_flow.run(state).await
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                Ok((outcome, state))
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -38,8 +38,7 @@ impl<'a> Flow<'a> for ListGamenights {
 | 
			
		||||
 | 
			
		||||
        view_flows.push(Box::new(Exit::new()));
 | 
			
		||||
 | 
			
		||||
        let choice = Select::new("What gamenight would you like to view?", view_flows)
 | 
			
		||||
            .prompt_skippable()?;
 | 
			
		||||
        let choice = Select::new("What gamenight would you like to view?", view_flows).prompt_skippable()?;
 | 
			
		||||
 | 
			
		||||
        clear_screen::clear();
 | 
			
		||||
        handle_choice_option(&choice, self, state).await
 | 
			
		||||
 | 
			
		||||
@ -97,8 +97,7 @@ impl From<ParseIntError> for FlowError {
 | 
			
		||||
#[derive(PartialEq)]
 | 
			
		||||
pub enum FlowOutcome {
 | 
			
		||||
    Successful,
 | 
			
		||||
    Bool(bool),
 | 
			
		||||
    String(String),
 | 
			
		||||
    Cancelled,
 | 
			
		||||
    Abort
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -113,7 +112,7 @@ pub trait Flow<'a>: Sync + DynClone + Send + Display {
 | 
			
		||||
 | 
			
		||||
async fn handle_choice<'a>(choice: &Box<dyn Flow<'a> + Send>, flow: &dyn Flow<'a>, state: &'a mut GamenightState) -> FlowResult<'a> {
 | 
			
		||||
    let (outcome, new_state) = choice.run(state).await?;
 | 
			
		||||
        
 | 
			
		||||
    
 | 
			
		||||
    if outcome == FlowOutcome::Abort {
 | 
			
		||||
        Ok((FlowOutcome::Successful, new_state))
 | 
			
		||||
    }
 | 
			
		||||
@ -127,6 +126,6 @@ async fn handle_choice_option<'a>(choice: &Option<Box<dyn Flow<'a> + Send>>, flo
 | 
			
		||||
        handle_choice(choice, flow, state).await
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        Ok((FlowOutcome::Abort, state))
 | 
			
		||||
        Ok((FlowOutcome::Cancelled, state))
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user