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..19b4463091 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::{get, put}, + http::StatusCode, + response::{IntoResponse, Response}, + routing::{delete, get}, Json, Router, }; use regex::Regex; @@ -145,6 +147,49 @@ 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 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::default(); + 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)) @@ -216,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, @@ -224,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, @@ -243,7 +288,8 @@ 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. @@ -296,13 +363,29 @@ 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, ) -> 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. 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, diff --git a/rust/package/agama.changes b/rust/package/agama.changes index 4e45ff2716..7b185bc5e5 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 a method to remove questions +- Add to HTTP API method to get the answer to a 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/agama#1451) + (gh#openSUSE/agama#1451) ------------------------------------------------------------------- Fri Jul 5 13:17:17 UTC 2024 - José Iván López González