rfcbot.rs 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. use crate::actions::FCPDecorator;
  2. use reqwest::Url;
  3. use serde::{Deserialize, Serialize};
  4. use std::collections::HashMap;
  5. #[derive(Serialize, Deserialize, Debug, Clone)]
  6. pub struct FCP {
  7. pub id: u32,
  8. pub fk_issue: u32,
  9. pub fk_initiator: u32,
  10. pub fk_initiating_comment: u32,
  11. pub disposition: Option<String>,
  12. pub fk_bot_tracking_comment: u32,
  13. pub fcp_start: Option<String>,
  14. pub fcp_closed: bool,
  15. }
  16. #[derive(Serialize, Deserialize, Debug, Clone)]
  17. pub struct Reviewer {
  18. pub id: u32,
  19. pub login: String,
  20. }
  21. #[derive(Serialize, Deserialize, Debug, Clone)]
  22. pub struct Review {
  23. pub reviewer: Reviewer,
  24. pub approved: bool,
  25. }
  26. #[derive(Serialize, Deserialize, Debug, Clone)]
  27. pub struct FCPIssue {
  28. pub id: u32,
  29. pub number: u32,
  30. pub fk_milestone: Option<String>,
  31. pub fk_user: u32,
  32. pub fk_assignee: Option<u32>,
  33. pub open: bool,
  34. pub is_pull_request: bool,
  35. pub title: String,
  36. pub body: String,
  37. pub locked: bool,
  38. pub closed_at: Option<String>,
  39. pub created_at: Option<String>,
  40. pub updated_at: Option<String>,
  41. pub labels: Vec<String>,
  42. pub repository: String,
  43. }
  44. #[derive(Serialize, Deserialize, Debug, Clone)]
  45. pub struct StatusComment {
  46. pub id: u64,
  47. pub fk_issue: u32,
  48. pub fk_user: u32,
  49. pub body: String,
  50. pub created_at: String,
  51. pub updated_at: Option<String>,
  52. pub repository: String,
  53. }
  54. #[derive(Serialize, Deserialize, Debug, Clone)]
  55. pub struct FullFCP {
  56. pub fcp: FCP,
  57. pub reviews: Vec<Review>,
  58. pub issue: FCPIssue,
  59. pub status_comment: StatusComment,
  60. }
  61. fn quote_reply(markdown: &str) -> String {
  62. if markdown.is_empty() {
  63. String::from("*No content*")
  64. } else {
  65. format!("\n\t> {}", markdown.replace("\n", "\n\t> "))
  66. }
  67. }
  68. // #[async_trait]
  69. // pub trait IssueToFCP {
  70. // async fn from_issue_fcp<'a>(
  71. // full_fcp: &FullFCP,
  72. // issue_decorator: &crate::actions::IssueDecorator,
  73. // client: &'a GithubClient,
  74. // ) -> anyhow::Result<Self>;
  75. // }
  76. // #[async_trait]
  77. // impl<'q> IssueToFCP for FCPDecorator {
  78. // async fn from_issue_fcp<'a>(
  79. // full_fcp: &FullFCP,
  80. // issue_decorator: &crate::actions::IssueDecorator,
  81. // client: &'a GithubClient,
  82. // ) -> anyhow::Result<Self> {
  83. // let bot_tracking_comment_html_url = format!(
  84. // "{}#issuecomment-{}",
  85. // issue_decorator.html_url, full_fcp.fcp.fk_bot_tracking_comment
  86. // );
  87. // let bot_tracking_comment_content = quote_reply(&full_fcp.status_comment.body);
  88. // let fk_initiating_comment = full_fcp.fcp.fk_initiating_comment;
  89. // let initiating_comment_html_url = format!(
  90. // "{}#issuecomment-{}",
  91. // issue_decorator.html_url, fk_initiating_comment,
  92. // );
  93. // // TODO: get from GitHub
  94. // let url = format!(
  95. // "{}/issues/comments/{}",
  96. // issue_decorator.html_url, fk_initiating_comment
  97. // );
  98. // let init_comment_content = client._send_req(client.get(&url)).await?.json().await?;
  99. // let initiating_comment_content = quote_reply(&init_comment_content);
  100. // Self {
  101. // // shared properties with IssueDecorator
  102. // number: issue_decorator.number.clone(),
  103. // title: issue_decorator.title.clone(),
  104. // html_url: issue_decorator.html_url.clone(),
  105. // repo_name: issue_decorator.repo_name.clone(),
  106. // labels: issue_decorator.labels.clone(),
  107. // assignees: issue_decorator.assignees.clone(),
  108. // updated_at: issue_decorator.updated_at.clone(),
  109. // // additional properties from FullFCP (from rfcbot)
  110. // bot_tracking_comment_html_url,
  111. // bot_tracking_comment_content,
  112. // initiating_comment_html_url,
  113. // initiating_comment_content,
  114. // }
  115. // }
  116. // }
  117. impl FCPDecorator {
  118. pub fn from_issue_fcp(
  119. full_fcp: &FullFCP,
  120. issue_decorator: &crate::actions::IssueDecorator,
  121. ) -> Self {
  122. let bot_tracking_comment_html_url = format!(
  123. "{}#issuecomment-{}",
  124. issue_decorator.html_url, full_fcp.fcp.fk_bot_tracking_comment
  125. );
  126. let bot_tracking_comment_content = quote_reply(&full_fcp.status_comment.body);
  127. let initiating_comment_html_url = format!(
  128. "{}#issuecomment-{}",
  129. issue_decorator.html_url, full_fcp.fcp.fk_initiating_comment
  130. );
  131. // TODO: get from GitHub
  132. let initiating_comment_content = quote_reply(&String::new());
  133. Self {
  134. // shared properties with IssueDecorator
  135. number: issue_decorator.number.clone(),
  136. title: issue_decorator.title.clone(),
  137. html_url: issue_decorator.html_url.clone(),
  138. repo_name: issue_decorator.repo_name.clone(),
  139. labels: issue_decorator.labels.clone(),
  140. assignees: issue_decorator.assignees.clone(),
  141. updated_at: issue_decorator.updated_at.clone(),
  142. // additional properties from FullFCP (from rfcbot)
  143. bot_tracking_comment_html_url,
  144. bot_tracking_comment_content,
  145. initiating_comment_html_url,
  146. initiating_comment_content,
  147. }
  148. }
  149. }
  150. // pub struct FCPCollection {
  151. // pub fcps: Box<dyn HashMap<String, FullFCP> + Send + Sync>,
  152. // }
  153. // // pub trait FCPQuery {
  154. // // pub fn get<'a>(&'a self) -> anyhow::Result<HashMap<String, FullFCP>>;
  155. // // }
  156. // impl FCPCollection {
  157. // pub async fn get_all_fcps(&self) -> anyhow::Result<()> {
  158. // let url = Url::parse(&"https://rfcbot.rs/api/all")?;
  159. // let res = reqwest::get(url).await?.json::<Vec<FullFCP>>().await?;
  160. // let mut map: HashMap<String, FullFCP> = HashMap::new();
  161. // for full_fcp in res.into_iter() {
  162. // map.insert(
  163. // format!(
  164. // "{}:{}:{}",
  165. // full_fcp.issue.repository.clone(),
  166. // full_fcp.issue.number.clone(),
  167. // full_fcp.issue.title.clone(),
  168. // ),
  169. // full_fcp,
  170. // );
  171. // }
  172. // self.fcps = Box::new(map);
  173. // Ok(())
  174. // }
  175. // }
  176. pub async fn get_all_fcps() -> anyhow::Result<HashMap<String, FullFCP>> {
  177. let url = Url::parse(&"https://rfcbot.rs/api/all")?;
  178. let res = reqwest::get(url).await?.json::<Vec<FullFCP>>().await?;
  179. let mut map: HashMap<String, FullFCP> = HashMap::new();
  180. for full_fcp in res.into_iter() {
  181. map.insert(
  182. format!(
  183. "{}:{}:{}",
  184. full_fcp.issue.repository.clone(),
  185. full_fcp.issue.number.clone(),
  186. full_fcp.issue.title.clone(),
  187. ),
  188. full_fcp,
  189. );
  190. }
  191. Ok(map)
  192. }