1mod crud;
9#[cfg(test)]
10mod tests;
11
12use std::path::PathBuf;
13
14use anyhow::Result;
15use clap::Subcommand;
16use serde::Serialize;
17
18use crate::commands::interactive;
19use crate::output::OutputFormat;
20use raps_acc::RfiClient;
21use raps_dm::DataManagementClient;
22
23#[derive(Debug, Subcommand)]
24pub enum RfiCommands {
25 List {
27 project_id: Option<String>,
29
30 #[arg(long)]
32 status: Option<String>,
33
34 #[arg(long)]
36 since: Option<String>,
37
38 #[arg(long, hide = true)]
40 hub_id: Option<String>,
41 },
42
43 Get {
45 project_id: Option<String>,
47
48 rfi_id: Option<String>,
50
51 #[arg(long, hide = true)]
53 hub_id: Option<String>,
54 },
55
56 Create {
58 project_id: Option<String>,
60
61 #[arg(long)]
63 title: Option<String>,
64
65 #[arg(long)]
67 question: Option<String>,
68
69 #[arg(long, default_value = "normal")]
71 priority: String,
72
73 #[arg(long)]
75 due_date: Option<String>,
76
77 #[arg(long)]
79 assigned_to: Option<String>,
80
81 #[arg(long)]
83 location: Option<String>,
84
85 #[arg(long)]
87 discipline: Option<String>,
88
89 #[arg(long, value_name = "FILE")]
91 from_csv: Option<PathBuf>,
92
93 #[arg(long, hide = true)]
95 hub_id: Option<String>,
96 },
97
98 Update {
100 project_id: Option<String>,
102
103 rfi_id: Option<String>,
105
106 #[arg(long)]
108 title: Option<String>,
109
110 #[arg(long)]
112 question: Option<String>,
113
114 #[arg(long)]
116 answer: Option<String>,
117
118 #[arg(long)]
120 status: Option<String>,
121
122 #[arg(long)]
124 priority: Option<String>,
125
126 #[arg(long)]
128 due_date: Option<String>,
129
130 #[arg(long)]
132 assigned_to: Option<String>,
133
134 #[arg(long)]
136 location: Option<String>,
137
138 #[arg(long, hide = true)]
140 hub_id: Option<String>,
141 },
142
143 Delete {
145 project_id: Option<String>,
147
148 rfi_id: Option<String>,
150
151 #[arg(long, hide = true)]
153 hub_id: Option<String>,
154 },
155}
156
157impl RfiCommands {
158 pub async fn execute(
159 self,
160 client: &RfiClient,
161 dm_client: &DataManagementClient,
162 output_format: OutputFormat,
163 ) -> Result<()> {
164 match self {
165 RfiCommands::List {
166 project_id,
167 status,
168 since,
169 hub_id,
170 } => {
171 let (p_id, _) = resolve_rfi_args(
172 dm_client,
173 client,
174 hub_id,
175 project_id,
176 Some("ignore".to_string()),
177 )
178 .await?;
179 crud::list_rfis(client, &p_id, status.as_deref(), since, output_format).await
180 }
181 RfiCommands::Get {
182 project_id,
183 rfi_id,
184 hub_id,
185 } => {
186 let (p_id, r_id) =
187 resolve_rfi_args(dm_client, client, hub_id, project_id, rfi_id).await?;
188 crud::get_rfi(client, &p_id, &r_id, output_format).await
189 }
190 RfiCommands::Create {
191 project_id,
192 title,
193 question,
194 priority,
195 due_date,
196 assigned_to,
197 location,
198 discipline,
199 from_csv,
200 hub_id,
201 } => {
202 let (p_id, _) = resolve_rfi_args(
203 dm_client,
204 client,
205 hub_id,
206 project_id,
207 Some("ignore".to_string()),
208 )
209 .await?;
210 crud::create_rfi(
211 client,
212 &p_id,
213 title,
214 question,
215 &priority,
216 due_date,
217 assigned_to,
218 location,
219 discipline,
220 from_csv,
221 output_format,
222 )
223 .await
224 }
225 RfiCommands::Update {
226 project_id,
227 rfi_id,
228 title,
229 question,
230 answer,
231 status,
232 priority,
233 due_date,
234 assigned_to,
235 location,
236 hub_id,
237 } => {
238 let (p_id, r_id) =
239 resolve_rfi_args(dm_client, client, hub_id, project_id, rfi_id).await?;
240 crud::update_rfi(
241 client,
242 &p_id,
243 &r_id,
244 title,
245 question,
246 answer,
247 status,
248 priority,
249 due_date,
250 assigned_to,
251 location,
252 output_format,
253 )
254 .await
255 }
256 RfiCommands::Delete {
257 project_id,
258 rfi_id,
259 hub_id,
260 } => {
261 let (p_id, r_id) =
262 resolve_rfi_args(dm_client, client, hub_id, project_id, rfi_id).await?;
263 crud::delete_rfi(client, &p_id, &r_id, output_format).await
264 }
265 }
266 }
267}
268
269async fn resolve_rfi_args(
274 dm_client: &DataManagementClient,
275 rfi_client: &RfiClient,
276 opt_hub_id: Option<String>,
277 opt_project_id: Option<String>,
278 opt_rfi_id: Option<String>,
279) -> Result<(String, String)> {
280 let hub_id = match (&opt_hub_id, &opt_project_id, &opt_rfi_id) {
281 (Some(h), _, _) => h.clone(),
282 (None, Some(_), Some(_)) => String::new(), (None, _, _) => interactive::prompt_for_hub(dm_client).await?,
284 };
285
286 let project_id = match opt_project_id {
287 Some(p) => p,
288 None => interactive::prompt_for_project(dm_client, &hub_id).await?,
289 };
290
291 let rfi_id = match opt_rfi_id {
292 Some(r) if r == "ignore" => String::new(),
293 Some(r) => r,
294 None => interactive::prompt_for_rfi(rfi_client, &project_id).await?,
295 };
296
297 Ok((project_id, rfi_id))
298}
299
300#[derive(Serialize)]
301pub(super) struct RfiOutput {
302 pub(super) id: String,
303 pub(super) number: Option<String>,
304 pub(super) title: String,
305 pub(super) status: String,
306 pub(super) priority: Option<String>,
307 pub(super) question: Option<String>,
308 pub(super) answer: Option<String>,
309 pub(super) due_date: Option<String>,
310 pub(super) assigned_to_name: Option<String>,
311 pub(super) created_at: Option<String>,
312}
313
314pub(super) fn truncate_str(s: &str, max_len: usize) -> String {
315 if s.len() <= max_len {
316 s.to_string()
317 } else {
318 format!("{}...", &s[..max_len - 3])
319 }
320}