Skip to main content

ironflow_api/entities/
schedule.rs

1//! Schedule request and response DTOs.
2
3use chrono::{DateTime, Utc};
4use serde::{Deserialize, Serialize};
5use serde_json::Value;
6use uuid::Uuid;
7use validator::Validate;
8
9use ironflow_store::entities::{Schedule, ScheduleSource};
10
11/// Schedule list/detail response.
12#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
13#[derive(Debug, Serialize)]
14pub struct ScheduleResponse {
15    /// Schedule ID.
16    pub id: Uuid,
17    /// Name of the workflow to trigger.
18    pub workflow_name: String,
19    /// Cron expression.
20    pub cron_expression: String,
21    /// JSON payload passed to the workflow.
22    pub inputs: Value,
23    /// Where this schedule was created (`handler` or `api`).
24    pub source: ScheduleSource,
25    /// When the schedule was disabled. `None` means active.
26    pub disabled_at: Option<DateTime<Utc>>,
27    /// When the schedule last created a run.
28    pub last_triggered_at: Option<DateTime<Utc>>,
29    /// When the schedule will next fire. Always set on an active schedule.
30    pub next_trigger_at: Option<DateTime<Utc>>,
31    /// Why Ironflow disabled the schedule on its own (e.g. its next trigger
32    /// cannot be computed). `None` when paused by a user or never disabled.
33    pub last_error: Option<String>,
34    /// User who created the schedule. `None` for handler-declared schedules.
35    pub created_by_user_id: Option<Uuid>,
36    /// When the schedule was created.
37    pub created_at: DateTime<Utc>,
38    /// When the schedule was last updated.
39    pub updated_at: DateTime<Utc>,
40}
41
42impl From<Schedule> for ScheduleResponse {
43    fn from(s: Schedule) -> Self {
44        Self {
45            id: s.id,
46            workflow_name: s.workflow_name,
47            cron_expression: s.cron_expression,
48            inputs: s.inputs,
49            source: s.source,
50            disabled_at: s.disabled_at,
51            last_triggered_at: s.last_triggered_at,
52            next_trigger_at: s.next_trigger_at,
53            last_error: s.last_error,
54            created_by_user_id: s.created_by_user_id,
55            created_at: s.created_at,
56            updated_at: s.updated_at,
57        }
58    }
59}
60
61/// Create schedule request body.
62#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
63#[derive(Debug, Deserialize, Validate)]
64pub struct CreateScheduleRequest {
65    /// Name of the workflow to trigger.
66    #[validate(length(min = 1, message = "workflow_name must not be empty"))]
67    pub workflow_name: String,
68    /// Cron expression (6-field format, e.g. `"0 */5 * * * *"`).
69    #[validate(length(min = 1, message = "cron_expression must not be empty"))]
70    pub cron_expression: String,
71    /// JSON payload for the workflow. Defaults to `{}`.
72    #[serde(default = "default_inputs")]
73    pub inputs: Value,
74}
75
76fn default_inputs() -> Value {
77    Value::Object(serde_json::Map::new())
78}
79
80/// Update schedule request body. All fields optional.
81#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
82#[derive(Debug, Deserialize)]
83pub struct UpdateScheduleRequest {
84    /// New cron expression.
85    pub cron_expression: Option<String>,
86    /// New inputs payload.
87    pub inputs: Option<Value>,
88}