use std::collections::HashMap;
use serde::{Deserialize, Serialize};
use crate::data::{Comment, Karma, Update};
use crate::error::QueryError;
use crate::request::{RequestMethod, SingleRequest};
#[derive(Debug, Serialize)]
struct CommentData<'a> {
update: &'a str,
text: Option<&'a str>,
karma: Karma,
csrf_token: &'a str,
#[serde(flatten)]
feedback: HashMap<String, String>,
}
#[derive(Debug, Serialize)]
pub struct BugFeedbackData {
bug_id: u32,
karma: Karma,
}
impl BugFeedbackData {
pub fn new(bug_id: u32, karma: Karma) -> Self {
BugFeedbackData { bug_id, karma }
}
}
#[derive(Debug, Serialize)]
pub struct TestCaseFeedbackData<'a> {
testcase_name: &'a str,
karma: Karma,
}
impl<'a> TestCaseFeedbackData<'a> {
pub fn new(testcase_name: &'a str, karma: Karma) -> Self {
TestCaseFeedbackData { testcase_name, karma }
}
}
#[derive(Debug, Deserialize)]
pub struct NewComment {
pub comment: Comment,
pub caveats: Vec<HashMap<String, String>>,
#[serde(skip)]
#[allow(dead_code)]
pub(crate) private: (),
}
#[derive(Debug)]
pub struct CommentCreator<'a> {
update: &'a str,
text: Option<&'a str>,
karma: Option<Karma>,
bug_feedback: Option<&'a [BugFeedbackData]>,
testcase_feedback: Option<&'a [TestCaseFeedbackData<'a>]>,
}
impl<'a> CommentCreator<'a> {
pub fn new(update: &'a str) -> Self {
CommentCreator {
update,
text: None,
karma: None,
bug_feedback: None,
testcase_feedback: None,
}
}
#[must_use]
pub fn text(mut self, text: &'a str) -> Self {
self.text = Some(text);
self
}
#[must_use]
pub fn karma(mut self, karma: Karma) -> Self {
self.karma = Some(karma);
self
}
#[must_use]
pub fn bug_feedback(mut self, feedbacks: &'a [BugFeedbackData]) -> Self {
self.bug_feedback = Some(feedbacks);
self
}
#[must_use]
pub fn testcase_feedback(mut self, feedbacks: &'a [TestCaseFeedbackData<'a>]) -> Self {
self.testcase_feedback = Some(feedbacks);
self
}
}
impl<'a> SingleRequest<NewComment, NewComment> for CommentCreator<'a> {
fn method(&self) -> RequestMethod {
RequestMethod::POST
}
fn path(&self) -> Result<String, QueryError> {
Ok(String::from("/comments/"))
}
fn body(&self, csrf_token: Option<String>) -> Result<Option<String>, QueryError> {
let mut feedback: HashMap<String, String> = HashMap::new();
let karma_string = |k: Karma| match k {
Karma::Positive => String::from("1"),
Karma::Neutral => String::from("0"),
Karma::Negative => String::from("-1"),
};
if let Some(items) = &self.bug_feedback {
for (pos, item) in items.iter().enumerate() {
feedback.insert(format!("bug_feedback.{pos}.bug_id"), item.bug_id.to_string());
feedback.insert(format!("bug_feedback.{pos}.karma"), karma_string(item.karma));
}
};
if let Some(items) = &self.testcase_feedback {
for (pos, item) in items.iter().enumerate() {
feedback.insert(
format!("testcase_feedback.{pos}.testcase_name"),
item.testcase_name.to_string(),
);
feedback.insert(format!("testcase_feedback.{pos}.karma"), karma_string(item.karma));
}
};
let new_comment = CommentData {
update: self.update,
text: self.text,
karma: self.karma.unwrap_or(Karma::Neutral),
feedback,
csrf_token: csrf_token.as_ref().unwrap_or_else(|| unreachable!()),
};
Ok(Some(
serde_json::to_string(&new_comment).map_err(|error| QueryError::SerializationError { error })?,
))
}
fn parse(&self, string: &str) -> Result<NewComment, QueryError> {
let new_comment: NewComment = serde_json::from_str(string)?;
Ok(new_comment)
}
fn extract(&self, page: NewComment) -> NewComment {
page
}
}
impl Update {
pub fn comment(&self) -> CommentCreator {
CommentCreator::new(self.alias.as_str())
}
}