use crate::{
client::{WekanClientFactory, integrations::UpdateIntegrationRequest},
command_result::{
CommandSuccess, IntegrationSubmittedField as Field, IntegrationUpdateSuccess,
},
commands::{
authenticated::AuthenticatedContext,
client_error::map_partial_mutation_client_error_with_not_found,
},
credentials::{CredentialStore, SecretInputProvider},
error::AppError,
redaction::Redactor,
};
use clap::Args;
use secrecy::{ExposeSecret, SecretString};
#[derive(Debug, Args)]
#[command(
after_help = "Activity flags replace the complete subscription array. Empty updates send {}. Wekan writes fields sequentially and can retain earlier writes after a later failure; the returned ID does not confirm a matched change."
)]
pub struct UpdateArgs {
#[command(flatten)]
target: super::Target,
#[arg(long)]
enabled: Option<bool>,
#[arg(long)]
title: Option<String>,
#[arg(long)]
url: Option<String>,
#[arg(long, conflicts_with = "clear_token")]
token_stdin: bool,
#[arg(long)]
clear_token: bool,
#[arg(long = "activity", conflicts_with = "clear_activities")]
activities: Vec<String>,
#[arg(long)]
clear_activities: bool,
}
pub(super) async fn execute(
args: UpdateArgs,
factory: &WekanClientFactory,
store: &dyn CredentialStore,
secrets: &dyn SecretInputProvider,
) -> Result<CommandSuccess, AppError> {
let context = AuthenticatedContext::load(factory, store)?;
let token = if args.token_stdin {
let raw = secrets.read_raw_secret()?;
let value = raw.expose_secret();
let value = value
.strip_suffix("\r\n")
.or_else(|| value.strip_suffix('\n'))
.unwrap_or(value);
if value.is_empty() {
return Err(AppError::invalid_input(
"token stdin must not be empty; use --clear-token to clear the token; no request was sent",
));
}
Some(SecretString::from(value.to_owned()))
} else if args.clear_token {
Some(SecretString::from(String::new()))
} else {
None
};
let request = UpdateIntegrationRequest {
enabled: args.enabled,
title: args.title,
url: args.url,
token,
activities: if args.clear_activities {
Some(Vec::new())
} else if args.activities.is_empty() {
None
} else {
Some(args.activities)
},
};
let mut fields = Vec::new();
for (present, field) in [
(request.enabled.is_some(), Field::Enabled),
(request.title.is_some(), Field::Title),
(request.url.is_some(), Field::Url),
(request.token.is_some(), Field::Token),
(request.activities.is_some(), Field::Activities),
] {
if present {
fields.push(field);
}
}
let mut redactor = Redactor::with_secret(context.record().token());
if let Some(token) = &request.token {
redactor = redactor.and_secret(token);
}
let response = context
.client()
.update_integration(
&args.target.board_id,
&args.target.integration_id,
&request,
context.record().token(),
)
.await
.map_err(|e| {
map_partial_mutation_client_error_with_not_found(
e,
&redactor,
"integration update",
"the Wekan board was not found",
)
})?;
Ok(CommandSuccess::IntegrationUpdated(
IntegrationUpdateSuccess {
board_id: args.target.board_id,
integration_id: response.integration_id,
submitted_fields: fields,
mutation_confirmed: false,
},
))
}