Skip to main content

awa_ui/handlers/
batch_ops.rs

1use awa_model::batch_operations::{
2    self, BatchOperation, BatchOperationFilter, BatchOperationKind, BatchOperationPreview,
3    BatchOperationSpec, BatchOperationState, ListBatchOperationsFilter, SubmitBatchOperation,
4};
5use axum::extract::{Path, Query, State};
6use axum::Json;
7use serde::Deserialize;
8use uuid::Uuid;
9
10use crate::error::ApiError;
11use crate::state::AppState;
12
13#[derive(Debug, Deserialize)]
14pub struct BatchOperationPayload {
15    pub op_kind: BatchOperationKind,
16    pub filter: BatchOperationFilter,
17    pub spec: serde_json::Value,
18    #[serde(default)]
19    pub submitted_by: Option<String>,
20    #[serde(default)]
21    pub all: bool,
22}
23
24impl BatchOperationPayload {
25    fn decode_spec(
26        self,
27    ) -> Result<
28        (
29            BatchOperationSpec,
30            BatchOperationFilter,
31            Option<String>,
32            bool,
33        ),
34        ApiError,
35    > {
36        let spec = match self.op_kind {
37            BatchOperationKind::SetPriority => {
38                #[derive(Deserialize)]
39                struct SetPrioritySpec {
40                    priority: i16,
41                }
42                let spec: SetPrioritySpec = serde_json::from_value(self.spec)?;
43                BatchOperationSpec::SetPriority {
44                    priority: spec.priority,
45                }
46            }
47            BatchOperationKind::MoveQueue => {
48                #[derive(Deserialize)]
49                struct MoveQueueSpec {
50                    queue: String,
51                    priority: Option<i16>,
52                }
53                let spec: MoveQueueSpec = serde_json::from_value(self.spec)?;
54                BatchOperationSpec::MoveQueue {
55                    queue: spec.queue,
56                    priority: spec.priority,
57                }
58            }
59        };
60        Ok((spec, self.filter, self.submitted_by, self.all))
61    }
62}
63
64#[derive(Debug, Deserialize)]
65pub struct ListBatchOperationsParams {
66    pub state: Option<BatchOperationState>,
67    pub limit: Option<i64>,
68}
69
70#[derive(Debug, Deserialize)]
71pub struct PatchBatchOperationPayload {
72    pub state: BatchOperationState,
73}
74
75pub async fn preview_batch_operation(
76    State(state): State<AppState>,
77    Json(payload): Json<BatchOperationPayload>,
78) -> Result<Json<BatchOperationPreview>, ApiError> {
79    state.require_writable()?;
80    let (spec, filter, _, _) = payload.decode_spec()?;
81    let preview = batch_operations::preview_batch_operation(&state.pool, spec, filter).await?;
82    Ok(Json(preview))
83}
84
85pub async fn submit_batch_operation(
86    State(state): State<AppState>,
87    Json(payload): Json<BatchOperationPayload>,
88) -> Result<Json<BatchOperation>, ApiError> {
89    state.require_writable()?;
90    let (spec, filter, submitted_by, all) = payload.decode_spec()?;
91    let operation = batch_operations::submit_batch_operation(
92        &state.pool,
93        SubmitBatchOperation {
94            spec,
95            filter,
96            submitted_by,
97            allow_all: all,
98        },
99    )
100    .await?;
101    state.invalidate_dashboard_caches();
102    Ok(Json(operation))
103}
104
105pub async fn list_batch_operations(
106    State(state): State<AppState>,
107    Query(params): Query<ListBatchOperationsParams>,
108) -> Result<Json<Vec<BatchOperation>>, ApiError> {
109    let operations = batch_operations::list_batch_operations(
110        &state.pool,
111        &ListBatchOperationsFilter {
112            state: params.state,
113            limit: params.limit,
114        },
115    )
116    .await?;
117    Ok(Json(operations))
118}
119
120pub async fn get_batch_operation(
121    State(state): State<AppState>,
122    Path(id): Path<Uuid>,
123) -> Result<Json<BatchOperation>, ApiError> {
124    Ok(Json(
125        batch_operations::get_batch_operation(&state.pool, id).await?,
126    ))
127}
128
129pub async fn patch_batch_operation(
130    State(state): State<AppState>,
131    Path(id): Path<Uuid>,
132    Json(payload): Json<PatchBatchOperationPayload>,
133) -> Result<Json<BatchOperation>, ApiError> {
134    state.require_writable()?;
135    match payload.state {
136        BatchOperationState::Cancelling => Ok(Json(
137            batch_operations::request_batch_operation_cancellation(&state.pool, id).await?,
138        )),
139        _ => Err(awa_model::AwaError::Validation(
140            "only state=cancelling is supported for batch operation PATCH".to_string(),
141        )
142        .into()),
143    }
144}