Skip to main content

kick_api/models/
reward.rs

1use serde::{Deserialize, Serialize};
2
3/// Channel reward structure
4#[derive(Debug, Clone, Serialize, Deserialize)]
5pub struct ChannelReward {
6    /// Unique identifier (ULID)
7    pub id: String,
8
9    /// Reward title (max 50 characters)
10    pub title: String,
11
12    /// Reward description (max 200 characters)
13    pub description: String,
14
15    /// Cost in channel points (minimum 1)
16    pub cost: u32,
17
18    /// Whether the reward is enabled
19    #[serde(default = "default_true")]
20    pub is_enabled: bool,
21
22    /// Whether redemptions are paused
23    #[serde(default)]
24    pub is_paused: bool,
25
26    /// Whether user input is required when redeeming
27    #[serde(default)]
28    pub is_user_input_required: bool,
29
30    /// Whether redemptions skip the request queue (auto-accept)
31    #[serde(default)]
32    pub should_redemptions_skip_request_queue: bool,
33
34    /// Background color (hex color code)
35    #[serde(default = "default_color")]
36    pub background_color: String,
37}
38
39/// Request body for creating a new reward
40#[derive(Debug, Clone, Serialize, Deserialize)]
41pub struct CreateRewardRequest {
42    pub title: String,
43    pub cost: u32,
44
45    #[serde(skip_serializing_if = "Option::is_none")]
46    pub description: Option<String>,
47
48    #[serde(skip_serializing_if = "Option::is_none")]
49    pub is_enabled: Option<bool>,
50
51    #[serde(skip_serializing_if = "Option::is_none")]
52    pub is_paused: Option<bool>,
53
54    #[serde(skip_serializing_if = "Option::is_none")]
55    pub is_user_input_required: Option<bool>,
56
57    #[serde(skip_serializing_if = "Option::is_none")]
58    pub should_redemptions_skip_request_queue: Option<bool>,
59
60    #[serde(skip_serializing_if = "Option::is_none")]
61    pub background_color: Option<String>,
62}
63
64/// Request body for updating a reward
65#[derive(Debug, Clone, Serialize, Default)]
66pub struct UpdateRewardRequest {
67    #[serde(skip_serializing_if = "Option::is_none")]
68    pub title: Option<String>,
69
70    #[serde(skip_serializing_if = "Option::is_none")]
71    pub description: Option<String>,
72
73    #[serde(skip_serializing_if = "Option::is_none")]
74    pub cost: Option<u32>,
75
76    #[serde(skip_serializing_if = "Option::is_none")]
77    pub is_enabled: Option<bool>,
78
79    #[serde(skip_serializing_if = "Option::is_none")]
80    pub is_paused: Option<bool>,
81
82    #[serde(skip_serializing_if = "Option::is_none")]
83    pub is_user_input_required: Option<bool>,
84
85    #[serde(skip_serializing_if = "Option::is_none")]
86    pub should_redemptions_skip_request_queue: Option<bool>,
87
88    #[serde(skip_serializing_if = "Option::is_none")]
89    pub background_color: Option<String>,
90}
91
92/// Channel reward redemption
93#[derive(Debug, Clone, Serialize, Deserialize)]
94pub struct ChannelRewardRedemption {
95    /// Unique identifier (ULID)
96    pub id: String,
97
98    /// When the reward was redeemed (ISO 8601)
99    pub redeemed_at: String,
100
101    /// User who redeemed the reward
102    pub redeemer: RedemptionUser,
103
104    /// Redemption status
105    pub status: RedemptionStatus,
106
107    /// User-provided input (if required)
108    #[serde(skip_serializing_if = "Option::is_none")]
109    pub user_input: Option<String>,
110}
111
112/// User information in a redemption
113#[derive(Debug, Clone, Serialize, Deserialize)]
114pub struct RedemptionUser {
115    pub user_id: u64,
116}
117
118/// Redemption status
119#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
120#[serde(rename_all = "lowercase")]
121pub enum RedemptionStatus {
122    Pending,
123    Accepted,
124    Rejected,
125}
126
127/// Failed redemption (when batch operations fail)
128#[derive(Debug, Clone, Serialize, Deserialize)]
129pub struct FailedRedemption {
130    /// Redemption ID that failed
131    pub id: String,
132
133    /// Reason for failure
134    pub reason: FailureReason,
135}
136
137/// Reasons why a redemption operation failed
138#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
139#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
140pub enum FailureReason {
141    Unknown,
142    NotPending,
143    NotFound,
144    NotOwned,
145}
146
147/// Request body for accepting/rejecting redemptions
148#[derive(Debug, Clone, Serialize, Deserialize)]
149pub struct ManageRedemptionsRequest {
150    /// Redemption IDs (1-25 ULIDs)
151    pub ids: Vec<String>,
152}
153
154/// Response when accepting/rejecting redemptions
155#[derive(Debug, Clone, Deserialize)]
156pub struct ManageRedemptionsResponse {
157    /// Successfully processed redemptions
158    pub data: Vec<ChannelRewardRedemption>,
159
160    /// Failed redemptions with reasons
161    #[serde(default)]
162    pub failed: Vec<FailedRedemption>,
163}
164
165// Helper functions for serde defaults
166fn default_true() -> bool {
167    true
168}
169
170fn default_color() -> String {
171    "#00e701".to_string()
172}