Add check of user membership to delete wallet modal
This commit is contained in:
parent
1ca02a4897
commit
f62d942958
@ -143,7 +143,7 @@ pub async fn delete_wallet(
|
||||
.await
|
||||
.map_err(|e| DeleteError::Connect(e.to_string()))?
|
||||
{
|
||||
tracing::info!("Deleting wallet on Liana-Connect {} plateform", network);
|
||||
tracing::info!("Deleting wallet on Liana-Connect {} backend", network);
|
||||
client
|
||||
.delete_wallet()
|
||||
.await
|
||||
|
||||
@ -16,11 +16,15 @@ use tokio::runtime::Handle;
|
||||
use crate::{
|
||||
app::{
|
||||
self,
|
||||
settings::{self, WalletId, WalletSettings},
|
||||
settings::{self, AuthConfig, WalletId, WalletSettings},
|
||||
},
|
||||
delete::{delete_wallet, DeleteError},
|
||||
dir::{LianaDirectory, NetworkDirectory},
|
||||
installer::UserFlow,
|
||||
services::connect::{
|
||||
client::{auth::AuthClient, backend::api::UserRole, get_service_config},
|
||||
login::{connect_with_credentials, BackendState},
|
||||
},
|
||||
};
|
||||
|
||||
const NETWORKS: [Network; 4] = [
|
||||
@ -437,6 +441,7 @@ struct DeleteWalletModal {
|
||||
warning: Option<DeleteError>,
|
||||
deleted: bool,
|
||||
delete_liana_connect: bool,
|
||||
user_role: Option<UserRole>,
|
||||
// `None` means we were not able to determine whether wallet uses internal bitcoind.
|
||||
internal_bitcoind: Option<bool>,
|
||||
}
|
||||
@ -448,7 +453,7 @@ impl DeleteWalletModal {
|
||||
wallet_settings: WalletSettings,
|
||||
internal_bitcoind: Option<bool>,
|
||||
) -> Self {
|
||||
Self {
|
||||
let mut modal = Self {
|
||||
network,
|
||||
wallet_settings,
|
||||
network_directory,
|
||||
@ -456,7 +461,23 @@ impl DeleteWalletModal {
|
||||
deleted: false,
|
||||
delete_liana_connect: false,
|
||||
internal_bitcoind,
|
||||
user_role: None,
|
||||
};
|
||||
if let Some(auth) = &modal.wallet_settings.remote_backend_auth {
|
||||
match Handle::current().block_on(check_membership(
|
||||
modal.network,
|
||||
&modal.network_directory,
|
||||
auth,
|
||||
)) {
|
||||
Err(e) => {
|
||||
modal.warning = Some(e);
|
||||
}
|
||||
Ok(user_role) => {
|
||||
modal.user_role = user_role;
|
||||
}
|
||||
}
|
||||
}
|
||||
modal
|
||||
}
|
||||
|
||||
fn update(&mut self, message: Message) -> Task<Message> {
|
||||
@ -500,18 +521,22 @@ impl DeleteWalletModal {
|
||||
));
|
||||
}
|
||||
// Use separate `Row`s for help text in order to have better spacing.
|
||||
let help_text_1 = if let Some(alias) = &self.wallet_settings.alias {
|
||||
format!(
|
||||
"Are you sure you want to delete the configuration and all associated data for the wallet {} (Liana-{})?",
|
||||
alias,
|
||||
self.wallet_settings.descriptor_checksum
|
||||
)
|
||||
} else {
|
||||
format!(
|
||||
"Are you sure you want to delete the configuration and all associated data for the wallet Liana-{}?",
|
||||
&self.wallet_settings.descriptor_checksum,
|
||||
)
|
||||
};
|
||||
let help_text_1 = format!(
|
||||
"Are you sure you want to {} for the wallet {}",
|
||||
if self.wallet_settings.remote_backend_auth.is_some() {
|
||||
"delete locally the configuration"
|
||||
} else {
|
||||
"delete the configuration and all associated data"
|
||||
},
|
||||
if let Some(alias) = &self.wallet_settings.alias {
|
||||
format!(
|
||||
"{} (Liana-{})?",
|
||||
alias, self.wallet_settings.descriptor_checksum
|
||||
)
|
||||
} else {
|
||||
format!("Liana-{}?", &self.wallet_settings.descriptor_checksum)
|
||||
}
|
||||
);
|
||||
let help_text_2 = match self.internal_bitcoind {
|
||||
Some(true) => Some("(The Liana-managed Bitcoin node for this network will not be affected by this action.)"),
|
||||
Some(false) => None,
|
||||
@ -538,20 +563,28 @@ impl DeleteWalletModal {
|
||||
.style(theme::text::destructive)
|
||||
.width(Length::Fill),
|
||||
))
|
||||
.push_maybe(self.wallet_settings.remote_backend_auth.as_ref().map(|_| {
|
||||
checkbox("Delete also on Liana-Connect", self.delete_liana_connect)
|
||||
.on_toggle(|v| {
|
||||
ViewMessage::DeleteWallet(DeleteWalletMessage::DeleteLianaConnect(
|
||||
v,
|
||||
))
|
||||
})
|
||||
}))
|
||||
.push(Row::new().push(text(help_text_1)))
|
||||
.push_maybe(
|
||||
help_text_2
|
||||
.map(|t| Row::new().push(p1_regular(t).style(theme::text::secondary))),
|
||||
)
|
||||
.push(Row::new())
|
||||
.push_maybe(self.wallet_settings.remote_backend_auth.as_ref().map(|a| {
|
||||
checkbox(
|
||||
match self.user_role {
|
||||
Some(UserRole::Owner) | None => "Also permanently delete this wallet from Liana Connect (for all members).".to_string(),
|
||||
Some(UserRole::Member) => format!("Also disassociate {} from this Liana Connect wallet.", a.email),
|
||||
},
|
||||
self.delete_liana_connect,
|
||||
)
|
||||
.on_toggle_maybe(if !self.deleted {
|
||||
Some(|v| {
|
||||
ViewMessage::DeleteWallet(DeleteWalletMessage::DeleteLianaConnect(v))
|
||||
})
|
||||
} else {
|
||||
None
|
||||
})
|
||||
}))
|
||||
.push(Row::new().push(text(help_text_3)))
|
||||
.push_maybe(self.warning.as_ref().map(|w| {
|
||||
notification::warning(w.to_string(), w.to_string()).width(Length::Fill)
|
||||
@ -577,6 +610,40 @@ impl DeleteWalletModal {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn check_membership(
|
||||
network: Network,
|
||||
network_dir: &NetworkDirectory,
|
||||
auth: &AuthConfig,
|
||||
) -> Result<Option<UserRole>, DeleteError> {
|
||||
let service_config = get_service_config(network)
|
||||
.await
|
||||
.map_err(|e| DeleteError::Connect(e.to_string()))?;
|
||||
|
||||
if let BackendState::WalletExists(client, _, _) = connect_with_credentials(
|
||||
AuthClient::new(
|
||||
service_config.auth_api_url,
|
||||
service_config.auth_api_public_key,
|
||||
auth.email.to_string(),
|
||||
),
|
||||
auth.wallet_id.clone(),
|
||||
service_config.backend_api_url,
|
||||
network,
|
||||
network_dir,
|
||||
)
|
||||
.await
|
||||
.map_err(|e| DeleteError::Connect(e.to_string()))?
|
||||
{
|
||||
Ok(Some(
|
||||
client
|
||||
.user_wallet_membership()
|
||||
.await
|
||||
.map_err(|e| DeleteError::Connect(e.to_string()))?,
|
||||
))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
async fn check_network_datadir(path: NetworkDirectory) -> Result<State, String> {
|
||||
let mut config_path = path.clone().path().to_path_buf();
|
||||
config_path.push(app::config::DEFAULT_FILE_NAME);
|
||||
|
||||
@ -122,6 +122,24 @@ pub struct ListWallets {
|
||||
pub wallets: Vec<Wallet>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum UserRole {
|
||||
Owner,
|
||||
Member,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct ListWalletMembers {
|
||||
pub members: Vec<Member>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct Member {
|
||||
pub user_id: String,
|
||||
pub role: UserRole,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct Provider {
|
||||
pub uuid: String,
|
||||
|
||||
@ -468,6 +468,27 @@ impl BackendWalletClient {
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn user_wallet_membership(&self) -> Result<api::UserRole, DaemonError> {
|
||||
let list: api::ListWalletMembers = self
|
||||
.inner
|
||||
.request(
|
||||
Method::GET,
|
||||
&format!("{}/v1/wallets/{}/members", self.inner.url, self.wallet_uuid),
|
||||
)
|
||||
.await
|
||||
.send()
|
||||
.await?
|
||||
.check_success()
|
||||
.await?
|
||||
.json_or_error()
|
||||
.await?;
|
||||
list.members
|
||||
.into_iter()
|
||||
.find(|m| m.user_id == self.user_id())
|
||||
.map(|m| m.role)
|
||||
.ok_or(DaemonError::Unexpected("Membership not found".to_string()))
|
||||
}
|
||||
|
||||
pub async fn auth(&self) -> AccessTokenResponse {
|
||||
self.inner.auth.read().await.clone()
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user