7
7
//! [slack api docs 🔗]: https://api.slack.com/reference/block-kit/blocks#file
8
8
//! [remote file 🔗]: https://api.slack.com/messaging/files/remote
9
9
10
+ use std:: borrow:: Cow ;
11
+
10
12
use serde:: { Deserialize , Serialize } ;
11
13
use validator:: Validate ;
12
14
@@ -21,15 +23,22 @@ use crate::val_helpr::ValidationResult;
21
23
/// [slack api docs 🔗]: https://api.slack.com/reference/block-kit/blocks#file
22
24
/// [remote file 🔗]: https://api.slack.com/messaging/files/remote
23
25
#[ derive( Clone , Debug , Deserialize , Hash , PartialEq , Serialize , Validate ) ]
24
- pub struct Contents {
25
- external_id : String ,
26
- source : String ,
26
+ pub struct File < ' a > {
27
+ external_id : Cow < ' a , str > ,
28
+ source : Cow < ' a , str > ,
27
29
#[ serde( skip_serializing_if = "Option::is_none" ) ]
28
- #[ validate( length ( max = 255 ) ) ]
29
- block_id : Option < String > ,
30
+ #[ validate( custom = "super::validate_block_id" ) ]
31
+ block_id : Option < Cow < ' a , str > > ,
30
32
}
31
33
32
- impl Contents {
34
+ impl < ' a > File < ' a > {
35
+ /// Build a new File block.
36
+ ///
37
+ /// For example, see docs for FileBuilder.
38
+ pub fn builder ( ) -> build:: FileBuilderInit < ' a > {
39
+ build:: FileBuilderInit :: new ( )
40
+ }
41
+
33
42
/// Create a file block from a [remote file 🔗]'s external ID.
34
43
///
35
44
/// # Arguments
@@ -51,14 +60,15 @@ impl Contents {
51
60
/// # pub fn main() -> Result<(), Box<dyn Error>> {
52
61
/// let file_id = upload_file_to_slack("https://www.cheese.com/cheese-wheel.png");
53
62
///
54
- /// let block = blocks::file::Contents ::from_external_id(file_id);
63
+ /// let block = blocks::File ::from_external_id(file_id);
55
64
///
56
65
/// // < send to slack API >
57
66
/// # Ok(())
58
67
/// # }
59
68
/// ```
60
- pub fn from_external_id ( external_file_id : impl AsRef < str > ) -> Self {
61
- Self { external_id : external_file_id. as_ref ( ) . into ( ) ,
69
+ #[ deprecated( since = "0.19.3" , note = "use File::builder" ) ]
70
+ pub fn from_external_id ( external_file_id : impl Into < Cow < ' a , str > > ) -> Self {
71
+ Self { external_id : external_file_id. into ( ) ,
62
72
source : "remote" . into ( ) ,
63
73
block_id : None }
64
74
}
@@ -86,15 +96,16 @@ impl Contents {
86
96
/// # pub fn main() -> Result<(), Box<dyn Error>> {
87
97
/// let file_id = upload_file_to_slack("https://www.cheese.com/cheese-wheel.png");
88
98
///
89
- /// let block = blocks::file::Contents ::from_external_id(file_id)
99
+ /// let block = blocks::File ::from_external_id(file_id)
90
100
/// .with_block_id("my_file_in_a_block_1234");
91
101
///
92
102
/// // < send to slack API >
93
103
/// # Ok(())
94
104
/// # }
95
105
/// ```
96
- pub fn with_block_id ( mut self , block_id : impl AsRef < str > ) -> Self {
97
- self . block_id = Some ( block_id. as_ref ( ) . to_string ( ) ) ;
106
+ #[ deprecated( since = "0.19.3" , note = "use File::builder" ) ]
107
+ pub fn with_block_id ( mut self , block_id : impl Into < Cow < ' a , str > > ) -> Self {
108
+ self . block_id = Some ( block_id. into ( ) ) ;
98
109
self
99
110
}
100
111
@@ -112,10 +123,8 @@ impl Contents {
112
123
/// # pub fn main() -> Result<(), Box<dyn Error>> {
113
124
/// let long_string = std::iter::repeat(' ').take(256).collect::<String>();
114
125
///
115
- /// let block = blocks::file
116
- /// ::Contents
117
- /// ::from_external_id("file_id")
118
- /// .with_block_id(long_string);
126
+ /// let block =
127
+ /// blocks::File::from_external_id("file_id").with_block_id(long_string);
119
128
///
120
129
/// assert_eq!(true, matches!(block.validate(), Err(_)));
121
130
///
@@ -127,3 +136,128 @@ impl Contents {
127
136
Validate :: validate ( self )
128
137
}
129
138
}
139
+
140
+ /// File block builder
141
+ pub mod build {
142
+ use std:: marker:: PhantomData ;
143
+
144
+ use super :: * ;
145
+ use crate :: build:: * ;
146
+
147
+ /// Compile-time markers for builder methods
148
+ #[ allow( non_camel_case_types) ]
149
+ pub mod method {
150
+ /// FileBuilder.external_id
151
+ #[ derive( Clone , Copy , Debug ) ]
152
+ pub struct external_id ;
153
+ }
154
+
155
+ /// Initial state for `FileBuilder`
156
+ pub type FileBuilderInit < ' a > =
157
+ FileBuilder < ' a , RequiredMethodNotCalled < method:: external_id > > ;
158
+
159
+ /// Build an File block
160
+ ///
161
+ /// Allows you to construct safely, with compile-time checks
162
+ /// on required setter methods.
163
+ ///
164
+ /// # Required Methods
165
+ /// `FileBuilder::build()` is only available if these methods have been called:
166
+ /// - `external_id`
167
+ /// - `source`
168
+ ///
169
+ /// # Example
170
+ /// ```
171
+ /// use slack_blocks::{blocks::File, elems::Image, text::ToSlackPlaintext};
172
+ ///
173
+ /// let my_file_id: String = {
174
+ /// // use Slack Web API: files.remote.add to upload a file
175
+ /// # "foo".into()
176
+ /// };
177
+ ///
178
+ /// let block = File::builder().external_id(my_file_id).build();
179
+ /// ```
180
+ #[ derive( Debug ) ]
181
+ pub struct FileBuilder < ' a , ExternalId > {
182
+ external_id : Option < Cow < ' a , str > > ,
183
+ source : Option < Cow < ' a , str > > ,
184
+ block_id : Option < Cow < ' a , str > > ,
185
+ state : PhantomData < ExternalId > ,
186
+ }
187
+
188
+ impl < ' a , Ext > FileBuilder < ' a , Ext > {
189
+ /// Create a new FileBuilder
190
+ pub fn new ( ) -> Self {
191
+ Self { external_id : None ,
192
+ source : None ,
193
+ block_id : None ,
194
+ state : PhantomData :: < _ > }
195
+ }
196
+
197
+ /// Set `external_id` (**Required**)
198
+ ///
199
+ /// The external unique ID for a [remote file 🔗].
200
+ ///
201
+ /// [remote file 🔗]: https://api.slack.com/messaging/files/remote
202
+ pub fn external_id < S > ( self ,
203
+ external_id : S )
204
+ -> FileBuilder < ' a , Set < method:: external_id > >
205
+ where S : Into < Cow < ' a , str > >
206
+ {
207
+ FileBuilder { external_id : Some ( external_id. into ( ) ) ,
208
+ source : self . source ,
209
+ block_id : self . block_id ,
210
+ state : PhantomData :: < _ > }
211
+ }
212
+
213
+ /// Set `block_id` (Optional)
214
+ ///
215
+ /// A string acting as a unique identifier for a block.
216
+ ///
217
+ /// You can use this `block_id` when you receive an interaction payload
218
+ /// to [identify the source of the action 🔗].
219
+ ///
220
+ /// If not specified, a `block_id` will be generated.
221
+ ///
222
+ /// Maximum length for this field is 255 characters.
223
+ ///
224
+ /// [identify the source of the action 🔗]: https://api.slack.com/interactivity/handling#payloads
225
+ pub fn block_id < S > ( mut self , block_id : S ) -> Self
226
+ where S : Into < Cow < ' a , str > >
227
+ {
228
+ self . block_id = Some ( block_id. into ( ) ) ;
229
+ self
230
+ }
231
+ }
232
+
233
+ impl < ' a > FileBuilder < ' a , Set < method:: external_id > > {
234
+ /// All done building, now give me a darn actions block!
235
+ ///
236
+ /// > `no method name 'build' found for struct 'FileBuilder<...>'`?
237
+ /// Make sure all required setter methods have been called. See docs for `FileBuilder`.
238
+ ///
239
+ /// ```compile_fail
240
+ /// use slack_blocks::blocks::File;
241
+ ///
242
+ /// let foo = File::builder().build(); // Won't compile!
243
+ /// ```
244
+ ///
245
+ /// ```
246
+ /// use slack_blocks::{blocks::File,
247
+ /// compose::text::ToSlackPlaintext,
248
+ /// elems::Image};
249
+ ///
250
+ /// let my_file_id: String = {
251
+ /// // use Slack Web API: files.remote.add to upload a file
252
+ /// # "foo".into()
253
+ /// };
254
+ ///
255
+ /// let block = File::builder().external_id(my_file_id).build();
256
+ /// ```
257
+ pub fn build ( self ) -> File < ' a > {
258
+ File { external_id : self . external_id . unwrap ( ) ,
259
+ source : "remote" . into ( ) ,
260
+ block_id : self . block_id }
261
+ }
262
+ }
263
+ }
0 commit comments