1use std::env;
7
8use reqwest::{
9 header::{self, HeaderMap, HeaderName, HeaderValue},
10 Method, StatusCode,
11};
12use tracing::error;
13
14const REST_BASE: &str = "/rest/api/2";
15
16use crate::{error::Error, Rujira};
17
18pub mod issue;
19pub mod myself;
20pub mod project;
21
22static APP_USER_AGENT: &str = concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION"),);
23
24#[derive(Default)]
26pub struct Rq {
27 bot: Rujira,
28 uri: String,
29 payload: serde_json::Value,
30 method: Method,
31 headers: HeaderMap,
32 params: Vec<(String, String)>,
33}
34
35#[derive(Debug, Default, Clone)]
37pub struct Rs {
38 pub data: serde_json::Value,
39 pub raw: String,
40 pub status: StatusCode,
41}
42
43impl Rq {
44 pub fn new(bot: Rujira) -> Self {
45 Self {
46 bot,
47 method: Method::GET,
48 ..Default::default()
49 }
50 }
51
52 pub fn uri(self, uri: &str) -> Self {
53 let uri = uri.to_owned();
54 Self { uri, ..self }
55 }
56
57 pub fn method(self, method: Method) -> Self {
58 Self { method, ..self }
59 }
60
61 pub fn add_header(mut self, header: &[u8], value: &str) -> Self {
62 let Ok(hdr) = HeaderName::from_bytes(header) else {
63 tracing::error!(
64 header = ?String::from_utf8_lossy(header),
65 "Invalid header name"
66 );
67 return self;
68 };
69 let val = HeaderValue::from_str(value).unwrap();
70 self.headers.insert(hdr, val);
71 self
72 }
73
74 pub fn add_params(mut self, params: Vec<(&str, &str)>) -> Self {
75 let params = params
76 .iter()
77 .map(|(k, v)| (k.to_string(), v.to_string()))
78 .collect();
79 self.params = params;
80 self
81 }
82
83 pub fn load_payload(mut self, value: serde_json::Value) -> Self {
84 for (key, value) in value.as_object().unwrap() {
85 self.payload[key] = value.clone();
86 }
87 self
88 }
89
90 pub fn add_payload(mut self, key: &str, value: serde_json::Value) -> Self {
91 self.payload[key] = value;
92 self
93 }
94
95 pub fn apply_if<T, F>(self, val: Option<T>, fun: F) -> Self
96 where
97 Self: Sized,
98 F: FnOnce(Self, T) -> Self,
99 {
100 if let Some(val) = val {
101 fun(self, val)
102 } else {
103 self
104 }
105 }
106
107 pub async fn apply(self) -> Result<Rs, Error> {
108 let mut headers = header::HeaderMap::new();
109 let hdr = format!("Bearer {}", self.bot.token);
110 let mut auth_value = header::HeaderValue::from_str(&hdr).map_err(Error::InvalidHeader)?;
111 auth_value.set_sensitive(true);
112 headers.insert(header::AUTHORIZATION, auth_value);
113 let client = reqwest::Client::builder()
114 .user_agent(APP_USER_AGENT)
115 .default_headers(headers)
116 .build()
117 .map_err(Error::AnyReqwestError)?;
118 let url = format!("{}{}", self.bot.url.as_ref(), self.uri);
119 let req = match self.method {
120 Method::GET => client.get(url),
121 Method::POST => client.post(url),
122 Method::DELETE => client.delete(url),
123 Method::PUT => client.put(url),
124 _ => return Err(Error::UnsupportedMethod),
125 };
126 let req = req
127 .headers(self.headers)
128 .query(&self.params)
129 .json(&self.payload);
130 let res = req.send().await.map_err(Error::AnyReqwestError)?;
131 if !res.status().is_success() {
132 error!(?res, code = ?res.status());
133 let raw = res.text().await.map_err(Error::AnyReqwestError)?;
134 return Ok(Rs {
135 raw,
136 ..Default::default()
137 });
138 }
139 let data = res.text().await.map_err(Error::AnyReqwestError)?;
140 let Ok(data) = serde_json::from_str(&data) else {
141 return Ok(Rs {
142 raw: data,
143 ..Default::default()
144 });
145 };
146 Ok(Rs {
147 data,
148 ..Default::default()
149 })
150 }
151}