Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions rust/agama-server/src/questions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
97 changes: 90 additions & 7 deletions rust/agama-server/src/questions/web.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<Option<Answer>, 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))
Expand Down Expand Up @@ -216,15 +261,15 @@ 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,
with_password: Option<PasswordAnswer>,
}

/// 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,
Expand All @@ -243,7 +288,8 @@ pub async fn questions_service(dbus: zbus::Connection) -> Result<Router, Service
let state = QuestionsState { questions };
let router = Router::new()
.route("/", get(list_questions).post(create_question))
.route("/:id/answer", put(answer))
.route("/:id", delete(delete_question))
.route("/:id/answer", get(get_answer).put(answer_question))
.with_state(state);
Ok(router)
}
Expand Down Expand Up @@ -287,6 +333,27 @@ async fn list_questions(
Ok(Json(state.questions.questions().await?))
}

/// Get answer to question.
///
/// * `state`: service state.
/// * `questions_id`: id of question
#[utoipa::path(put, path = "/questions/:id/answer", responses(
(status = 200, description = "Answer"),
(status = 400, description = "The D-Bus service could not perform the action"),
(status = 404, description = "Answer was not yet provided"),
))]
async fn get_answer(
State(state): State<QuestionsState<'_>>,
Path(question_id): Path<u32>,
) -> Result<Response, Error> {
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.
Expand All @@ -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<QuestionsState<'_>>,
Path(question_id): Path<u32>,
Json(answer): Json<Answer>,
) -> 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<QuestionsState<'_>>,
Path(question_id): Path<u32>,
) -> Result<(), Error> {
let res = state.questions.delete(question_id).await;
Ok(res?)
}

/// Create new question.
Expand Down
5 changes: 4 additions & 1 deletion rust/agama-server/src/web/docs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
9 changes: 8 additions & 1 deletion rust/package/agama.changes
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
-------------------------------------------------------------------
Wed Jul 10 20:11:39 UTC 2024 - Josef Reidinger <jreidinger@suse.com>

- 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 <jreidinger@suse.com>

- 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 <jlopez@suse.com>
Expand Down