From 9a988714f05312064bcfdb18d82e69427b0662b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Imobach=20Gonz=C3=A1lez=20Sosa?= Date: Wed, 8 Jan 2025 11:53:26 +0000 Subject: [PATCH] fix(rust): handle registration errors properly --- rust/agama-lib/src/product/http_client.rs | 21 +++++++++++++++++++-- rust/agama-lib/src/product/store.rs | 13 ++----------- rust/agama-lib/src/software/model.rs | 8 ++++++++ rust/agama-server/src/software/web.rs | 23 +++++++++-------------- 4 files changed, 38 insertions(+), 27 deletions(-) diff --git a/rust/agama-lib/src/product/http_client.rs b/rust/agama-lib/src/product/http_client.rs index 424a8b49f9..29a36f3b3a 100644 --- a/rust/agama-lib/src/product/http_client.rs +++ b/rust/agama-lib/src/product/http_client.rs @@ -18,6 +18,7 @@ // To contact SUSE LLC about this file by physical or electronic mail, you may // find current contact information at www.suse.com. +use crate::software::model::RegistrationError; use crate::software::model::RegistrationInfo; use crate::software::model::RegistrationParams; use crate::software::model::SoftwareConfig; @@ -64,13 +65,29 @@ impl ProductHTTPClient { } /// register product - pub async fn register(&self, key: &str, email: &str) -> Result<(u32, String), ServiceError> { + pub async fn register(&self, key: &str, email: &str) -> Result<(), ServiceError> { // note RegistrationParams != RegistrationInfo, fun! let params = RegistrationParams { key: key.to_owned(), email: email.to_owned(), }; + let result = self + .client + .post_void("/software/registration", ¶ms) + .await; - self.client.post("/software/registration", ¶ms).await + let Err(error) = result else { + return Ok(()); + }; + + let message = match error { + ServiceError::BackendError(_, details) => { + let details: RegistrationError = serde_json::from_str(&details).unwrap(); + format!("{} (error code: {})", details.message, details.id) + } + _ => format!("Could not register the product: #{error:?}"), + }; + + Err(ServiceError::FailedRegistration(message)) } } diff --git a/rust/agama-lib/src/product/store.rs b/rust/agama-lib/src/product/store.rs index d43a6166c4..c1a3f42297 100644 --- a/rust/agama-lib/src/product/store.rs +++ b/rust/agama-lib/src/product/store.rs @@ -68,17 +68,8 @@ impl ProductStore { } } if let Some(reg_code) = &settings.registration_code { - let (result, message); - if let Some(email) = &settings.registration_email { - (result, message) = self.product_client.register(reg_code, email).await?; - } else { - (result, message) = self.product_client.register(reg_code, "").await?; - } - // FIXME: name the magic numbers. 3 is Registration not required - // FIXME: well don't register when not required (no regcode in profile) - if result != 0 && result != 3 { - return Err(ServiceError::FailedRegistration(message)); - } + let email = settings.registration_email.as_deref().unwrap_or(""); + self.product_client.register(reg_code, email).await?; probe = true; } diff --git a/rust/agama-lib/src/software/model.rs b/rust/agama-lib/src/software/model.rs index 32618542f1..8556dae11d 100644 --- a/rust/agama-lib/src/software/model.rs +++ b/rust/agama-lib/src/software/model.rs @@ -71,6 +71,14 @@ pub enum RegistrationRequirement { Mandatory = 2, } +#[derive(Clone, Serialize, Deserialize, utoipa::ToSchema)] +pub struct RegistrationError { + /// ID of error. See dbus API for possible values + pub id: u32, + /// human readable error string intended to be displayed to user + pub message: String, +} + /// Software resolvable type (package or pattern). #[derive(Deserialize, Serialize, strum::Display, utoipa::ToSchema)] #[strum(serialize_all = "camelCase")] diff --git a/rust/agama-server/src/software/web.rs b/rust/agama-server/src/software/web.rs index f800c75cab..40d49be018 100644 --- a/rust/agama-server/src/software/web.rs +++ b/rust/agama-server/src/software/web.rs @@ -37,7 +37,10 @@ use agama_lib::{ error::ServiceError, product::{proxies::RegistrationProxy, Product, ProductClient}, software::{ - model::{RegistrationInfo, RegistrationParams, ResolvableParams, SoftwareConfig}, + model::{ + RegistrationError, RegistrationInfo, RegistrationParams, ResolvableParams, + SoftwareConfig, + }, proxies::{Software1Proxy, SoftwareProductProxy}, Pattern, SelectedBy, SoftwareClient, UnknownSelectedBy, }, @@ -49,7 +52,7 @@ use axum::{ routing::{get, post, put}, Json, Router, }; -use serde::{Deserialize, Serialize}; +use serde::Serialize; use std::collections::HashMap; use tokio_stream::{Stream, StreamExt}; @@ -248,14 +251,6 @@ async fn get_registration( Ok(Json(result)) } -#[derive(Clone, Serialize, Deserialize, utoipa::ToSchema)] -pub struct FailureDetails { - /// ID of error. See dbus API for possible values - id: u32, - /// human readable error string intended to be displayed to user - message: String, -} - /// Register product /// /// * `state`: service state. @@ -265,7 +260,7 @@ pub struct FailureDetails { context_path = "/api/software", responses( (status = 204, description = "registration successfull"), - (status = 422, description = "Registration failed. Details are in body", body = FailureDetails), + (status = 422, description = "Registration failed. Details are in body", body = RegistrationError), (status = 400, description = "The D-Bus service could not perform the action") ) )] @@ -274,10 +269,10 @@ async fn register( Json(config): Json, ) -> Result { let (id, message) = state.product.register(&config.key, &config.email).await?; - let details = FailureDetails { id, message }; if id == 0 { Ok((StatusCode::NO_CONTENT, ().into_response())) } else { + let details = RegistrationError { id, message }; Ok(( StatusCode::UNPROCESSABLE_ENTITY, Json(details).into_response(), @@ -294,13 +289,13 @@ async fn register( context_path = "/api/software", responses( (status = 200, description = "deregistration successfull"), - (status = 422, description = "De-registration failed. Details are in body", body = FailureDetails), + (status = 422, description = "De-registration failed. Details are in body", body = RegistrationError), (status = 400, description = "The D-Bus service could not perform the action") ) )] async fn deregister(State(state): State>) -> Result { let (id, message) = state.product.deregister().await?; - let details = FailureDetails { id, message }; + let details = RegistrationError { id, message }; if id == 0 { Ok((StatusCode::NO_CONTENT, ().into_response())) } else {