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
|
type: string
|
||||||
datetime:
|
datetime:
|
||||||
type: string
|
type: string
|
||||||
|
required:
|
||||||
|
- name
|
||||||
|
- datetime
|
||||||
GamenightId:
|
GamenightId:
|
||||||
title: GamenightId
|
title: GamenightId
|
||||||
type: object
|
type: object
|
||||||
|
@ -11,9 +11,9 @@ use crate::request::error::ApiError;
|
|||||||
impl AddGamenightRequestBody {
|
impl AddGamenightRequestBody {
|
||||||
pub fn into_with_user(&self, user: AuthUser) -> Result<gamenight::Gamenight, ParseError> {
|
pub fn into_with_user(&self, user: AuthUser) -> Result<gamenight::Gamenight, ParseError> {
|
||||||
Ok(gamenight::Gamenight {
|
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(),
|
id: Uuid::new_v4(),
|
||||||
name: self.clone().name.unwrap().clone(),
|
name: self.name.clone(),
|
||||||
owner_id: user.0.id
|
owner_id: user.0.id
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -4,8 +4,8 @@
|
|||||||
|
|
||||||
Name | Type | Description | Notes
|
Name | Type | Description | Notes
|
||||||
------------ | ------------- | ------------- | -------------
|
------------ | ------------- | ------------- | -------------
|
||||||
**name** | Option<**String**> | | [optional]
|
**name** | **String** | |
|
||||||
**datetime** | Option<**String**> | | [optional]
|
**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)
|
[[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)]
|
#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct AddGamenightRequestBody {
|
pub struct AddGamenightRequestBody {
|
||||||
#[serde(rename = "name", skip_serializing_if = "Option::is_none")]
|
#[serde(rename = "name")]
|
||||||
pub name: Option<String>,
|
pub name: String,
|
||||||
#[serde(rename = "datetime", skip_serializing_if = "Option::is_none")]
|
#[serde(rename = "datetime")]
|
||||||
pub datetime: Option<String>,
|
pub datetime: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AddGamenightRequestBody {
|
impl AddGamenightRequestBody {
|
||||||
pub fn new() -> AddGamenightRequestBody {
|
pub fn new(name: String, datetime: String) -> AddGamenightRequestBody {
|
||||||
AddGamenightRequestBody {
|
AddGamenightRequestBody {
|
||||||
name: None,
|
name,
|
||||||
datetime: None,
|
datetime,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,26 +19,27 @@ impl AddGamenight {
|
|||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl<'a> Flow<'a> for AddGamenight {
|
impl<'a> Flow<'a> for AddGamenight {
|
||||||
async fn run(&self, state: &'a mut GamenightState) -> FlowResult<'a> {
|
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();
|
if let Some(name) = Text::new("What should we call your gamenight").prompt_skippable()? {
|
||||||
Ok((FlowOutcome::Successful, state))
|
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 std::fmt::Display;
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use gamenight_api_client_rs::apis::configuration::Configuration;
|
||||||
use inquire::Text;
|
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};
|
use super::{Flow, FlowOutcome, FlowResult, GamenightState};
|
||||||
|
|
||||||
@ -24,6 +25,64 @@ impl Connect {
|
|||||||
instance: None
|
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]
|
#[async_trait]
|
||||||
@ -32,58 +91,39 @@ impl<'a> Flow<'a> for Connect {
|
|||||||
let mut instance = if let Some(instance) = self.instance.clone() {
|
let mut instance = if let Some(instance) = self.instance.clone() {
|
||||||
instance
|
instance
|
||||||
} else {
|
} else {
|
||||||
let mut name: String;
|
if let Some(instance) = self.prompt_new_instance(&state.gamenight_configuration)? {
|
||||||
loop {
|
instance
|
||||||
name = Text::new("Name this instance: ").prompt()?;
|
}
|
||||||
if state.gamenight_configuration.instances.iter().find(|x| x.name == name).is_none() {
|
else {
|
||||||
break;
|
return Ok((FlowOutcome::Cancelled, state));
|
||||||
}
|
|
||||||
clear_screen::clear();
|
|
||||||
println!("Name already in use, please provide a unique name");
|
|
||||||
}
|
}
|
||||||
let url = Text::new("What is the server URL: ").prompt()?;
|
|
||||||
Instance::new(name, url)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let instance_name = instance.name.clone();
|
let instance_name = instance.name.clone();
|
||||||
|
|
||||||
state.api_configuration.base_path = instance.url.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();
|
let gamenight_menu_flow = GamenightMenu::new();
|
||||||
gamenight_menu_flow.run(state).await
|
gamenight_menu_flow.run(state).await
|
||||||
}
|
}
|
||||||
else {
|
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()));
|
view_flows.push(Box::new(Exit::new()));
|
||||||
|
|
||||||
let choice = Select::new("What gamenight would you like to view?", view_flows)
|
let choice = Select::new("What gamenight would you like to view?", view_flows).prompt_skippable()?;
|
||||||
.prompt_skippable()?;
|
|
||||||
|
|
||||||
clear_screen::clear();
|
clear_screen::clear();
|
||||||
handle_choice_option(&choice, self, state).await
|
handle_choice_option(&choice, self, state).await
|
||||||
|
@ -97,8 +97,7 @@ impl From<ParseIntError> for FlowError {
|
|||||||
#[derive(PartialEq)]
|
#[derive(PartialEq)]
|
||||||
pub enum FlowOutcome {
|
pub enum FlowOutcome {
|
||||||
Successful,
|
Successful,
|
||||||
Bool(bool),
|
Cancelled,
|
||||||
String(String),
|
|
||||||
Abort
|
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> {
|
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?;
|
let (outcome, new_state) = choice.run(state).await?;
|
||||||
|
|
||||||
if outcome == FlowOutcome::Abort {
|
if outcome == FlowOutcome::Abort {
|
||||||
Ok((FlowOutcome::Successful, new_state))
|
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
|
handle_choice(choice, flow, state).await
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Ok((FlowOutcome::Abort, state))
|
Ok((FlowOutcome::Cancelled, state))
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user