From 7af3d316d6bf4f2f7c81d0773ebcf0d515f6d954 Mon Sep 17 00:00:00 2001 From: Josef Reidinger Date: Wed, 10 Jul 2024 17:01:39 +0200 Subject: [PATCH 1/5] implement deleting question --- rust/agama-server/src/questions.rs | 1 + rust/agama-server/src/questions/web.rs | 35 +++++++++++++++++++++++--- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/rust/agama-server/src/questions.rs b/rust/agama-server/src/questions.rs index 64b510623d..11c6f68e7c 100644 --- a/rust/agama-server/src/questions.rs +++ b/rust/agama-server/src/questions.rs @@ -221,6 +221,7 @@ impl Questions { } /// Removes question at given object path + /// TODO: use id as parameter ( need at first check other users of method ) async fn delete(&mut self, question: ObjectPath<'_>) -> zbus::fdo::Result<()> { // TODO: error checking let id: u32 = question.rsplit('/').next().unwrap().parse().unwrap(); diff --git a/rust/agama-server/src/questions/web.rs b/rust/agama-server/src/questions/web.rs index 2866ddfca6..079f4b28e6 100644 --- a/rust/agama-server/src/questions/web.rs +++ b/rust/agama-server/src/questions/web.rs @@ -13,7 +13,7 @@ use agama_lib::{ use anyhow::Context; use axum::{ extract::{Path, State}, - routing::{get, put}, + routing::{delete, get, put}, Json, Router, }; use regex::Regex; @@ -145,6 +145,18 @@ impl<'a> QuestionsClient<'a> { Ok(result) } + pub async fn delete(&self, id: u32) -> Result<(), ServiceError> { + let question_path = ObjectPath::from( + ObjectPath::try_from(format!("/org/opensuse/Agama1/Questions/{}", id)) + .context("Failed to create dbus path")?, + ); + + self.questions_proxy + .delete(&question_path) + .await + .map_err(|e| e.into()) + } + pub async fn answer(&self, id: u32, answer: Answer) -> Result<(), ServiceError> { let question_path = OwnedObjectPath::from( ObjectPath::try_from(format!("/org/opensuse/Agama1/Questions/{}", id)) @@ -243,6 +255,7 @@ pub async fn questions_service(dbus: zbus::Connection) -> Result, Json(answer): Json, ) -> Result<(), Error> { - state.questions.answer(question_id, answer).await?; - Ok(()) + let res = state.questions.answer(question_id, answer).await; + Ok(res?) +} + +/// Deletes question. +/// +/// * `state`: service state. +/// * `questions_id`: id of question +#[utoipa::path(delete, path = "/questions/:id", responses( + (status = 200, description = "question deleted"), + (status = 400, description = "The D-Bus service could not perform the action") +))] +async fn delete_question( + State(state): State>, + Path(question_id): Path, +) -> Result<(), Error> { + let res = state.questions.delete(question_id).await; + Ok(res?) } /// Create new question. From 1e2a6d7c22dfc5ca05b6e7920f0ca88d4a611fef Mon Sep 17 00:00:00 2001 From: Josef Reidinger Date: Wed, 10 Jul 2024 22:11:28 +0200 Subject: [PATCH 2/5] implement get_answer --- rust/agama-server/src/questions/web.rs | 65 ++++++++++++++++++++++++-- rust/agama-server/src/web/docs.rs | 5 +- 2 files changed, 66 insertions(+), 4 deletions(-) diff --git a/rust/agama-server/src/questions/web.rs b/rust/agama-server/src/questions/web.rs index 079f4b28e6..d80fab5804 100644 --- a/rust/agama-server/src/questions/web.rs +++ b/rust/agama-server/src/questions/web.rs @@ -13,7 +13,9 @@ use agama_lib::{ use anyhow::Context; use axum::{ extract::{Path, State}, - routing::{delete, get, put}, + http::StatusCode, + response::{IntoResponse, Response}, + routing::{delete, get}, Json, Router, }; use regex::Regex; @@ -157,6 +159,42 @@ impl<'a> QuestionsClient<'a> { .map_err(|e| e.into()) } + pub async fn get_answer(&self, id: u32) -> Result, ServiceError> { + let question_path = OwnedObjectPath::from( + ObjectPath::try_from(format!("/org/opensuse/Agama1/Questions/{}", id)) + .context("Failed to create dbus path")?, + ); + let mut result = Answer { + generic: GenericAnswer { + answer: String::new(), + }, + with_password: None, + }; + let dbus_password_res = QuestionWithPasswordProxy::builder(&self.connection) + .path(&question_path)? + .cache_properties(zbus::CacheProperties::No) + .build() + .await; + if let Ok(dbus_password) = dbus_password_res { + result.with_password = Some(PasswordAnswer { + password: dbus_password.password().await?, + }); + } + + let dbus_generic = GenericQuestionProxy::builder(&self.connection) + .path(&question_path)? + .cache_properties(zbus::CacheProperties::No) + .build() + .await?; + let answer = dbus_generic.answer().await?; + if answer.is_empty() { + Ok(None) + } else { + result.generic.answer = answer; + Ok(Some(result)) + } + } + pub async fn answer(&self, id: u32, answer: Answer) -> Result<(), ServiceError> { let question_path = OwnedObjectPath::from( ObjectPath::try_from(format!("/org/opensuse/Agama1/Questions/{}", id)) @@ -256,7 +294,7 @@ pub async fn questions_service(dbus: zbus::Connection) -> Result>, + Path(question_id): Path, +) -> Result { + let res = state.questions.get_answer(question_id).await?; + if let Some(answer) = res { + Ok(Json(answer).into_response()) + } else { + Ok(StatusCode::NOT_FOUND.into_response()) + } +} + /// Provide answer to question. /// /// * `state`: service state. @@ -309,7 +368,7 @@ async fn list_questions( (status = 200, description = "answer question"), (status = 400, description = "The D-Bus service could not perform the action") ))] -async fn answer( +async fn answer_question( State(state): State>, Path(question_id): Path, Json(answer): Json, diff --git a/rust/agama-server/src/web/docs.rs b/rust/agama-server/src/web/docs.rs index b0748c314b..dcaa1b0680 100644 --- a/rust/agama-server/src/web/docs.rs +++ b/rust/agama-server/src/web/docs.rs @@ -20,7 +20,10 @@ use utoipa::OpenApi; crate::network::web::devices, crate::network::web::disconnect, crate::network::web::update_connection, - crate::questions::web::answer, + crate::questions::web::answer_question, + crate::questions::web::get_answer, + crate::questions::web::delete_question, + crate::questions::web::create_question, crate::questions::web::list_questions, crate::software::web::get_config, crate::software::web::patterns, From e115f30300800c3621715bf1380a32165fab24dd Mon Sep 17 00:00:00 2001 From: Josef Reidinger Date: Wed, 10 Jul 2024 22:14:07 +0200 Subject: [PATCH 3/5] changes --- rust/package/agama.changes | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/rust/package/agama.changes b/rust/package/agama.changes index e139a29486..f825ec58f1 100644 --- a/rust/package/agama.changes +++ b/rust/package/agama.changes @@ -1,8 +1,15 @@ +------------------------------------------------------------------- +Wed Jul 10 20:11:39 UTC 2024 - Josef Reidinger + +- Add to HTTP API method DELETE for question to remove question +- Add to HTTP API method GET for answer to get answer for question + (gh#openSUSE/agama#1453) + ------------------------------------------------------------------- Wed Jul 10 10:01:18 UTC 2024 - Josef Reidinger - Add to HTTP API method POST for question to ask new question - (gh#openSUSE/agam#1451) + (gh#openSUSE/agama#1451) ------------------------------------------------------------------- Fri Jul 5 13:17:17 UTC 2024 - José Iván López González From ab0945d25267f394bb14293734a94c65f426d5cb Mon Sep 17 00:00:00 2001 From: Josef Reidinger Date: Thu, 11 Jul 2024 10:45:32 +0200 Subject: [PATCH 4/5] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Imobach González Sosa --- rust/package/agama.changes | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rust/package/agama.changes b/rust/package/agama.changes index f825ec58f1..7b185bc5e5 100644 --- a/rust/package/agama.changes +++ b/rust/package/agama.changes @@ -1,8 +1,8 @@ ------------------------------------------------------------------- Wed Jul 10 20:11:39 UTC 2024 - Josef Reidinger -- Add to HTTP API method DELETE for question to remove question -- Add to HTTP API method GET for answer to get answer for question +- Add to HTTP API a method to remove questions +- Add to HTTP API method to get the answer to a question (gh#openSUSE/agama#1453) ------------------------------------------------------------------- From de8e3bc8edd1ca1d89ea5134c861124e8428579c Mon Sep 17 00:00:00 2001 From: Josef Reidinger Date: Thu, 11 Jul 2024 10:53:07 +0200 Subject: [PATCH 5/5] use default trait --- rust/agama-server/src/questions/web.rs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/rust/agama-server/src/questions/web.rs b/rust/agama-server/src/questions/web.rs index d80fab5804..19b4463091 100644 --- a/rust/agama-server/src/questions/web.rs +++ b/rust/agama-server/src/questions/web.rs @@ -164,12 +164,7 @@ impl<'a> QuestionsClient<'a> { ObjectPath::try_from(format!("/org/opensuse/Agama1/Questions/{}", id)) .context("Failed to create dbus path")?, ); - let mut result = Answer { - generic: GenericAnswer { - answer: String::new(), - }, - with_password: None, - }; + let mut result = Answer::default(); let dbus_password_res = QuestionWithPasswordProxy::builder(&self.connection) .path(&question_path)? .cache_properties(zbus::CacheProperties::No) @@ -266,7 +261,7 @@ pub struct GenericQuestion { #[serde(rename_all = "camelCase")] pub struct QuestionWithPassword {} -#[derive(Clone, Serialize, Deserialize, utoipa::ToSchema)] +#[derive(Default, Clone, Serialize, Deserialize, utoipa::ToSchema)] #[serde(rename_all = "camelCase")] pub struct Answer { generic: GenericAnswer, @@ -274,7 +269,7 @@ pub struct Answer { } /// Answer needed for GenericQuestion -#[derive(Clone, Serialize, Deserialize, utoipa::ToSchema)] +#[derive(Default, Clone, Serialize, Deserialize, utoipa::ToSchema)] #[serde(rename_all = "camelCase")] pub struct GenericAnswer { answer: String,