@@ -37,6 +37,7 @@ async fn main() {
37
37
let app = Router :: new ( )
38
38
. route ( "/" , get ( || async move { "welcome to Image upload api" } ) )
39
39
. route ( "/upload" , post ( upload_image) )
40
+ . route ( "/upload/master" , post ( upload_image_no_timestamp) )
40
41
. layer ( cors_layer)
41
42
. layer ( Extension ( aws_s3_client) )
42
43
. layer ( axum:: middleware:: from_fn ( log_request_ip) ) ;
@@ -113,3 +114,63 @@ async fn upload_image(
113
114
// send the urls in response
114
115
Ok ( Json ( serde_json:: json!( res) ) )
115
116
}
117
+
118
+
119
+ async fn upload_image_no_timestamp (
120
+ Extension ( s3_client) : Extension < Client > ,
121
+ mut files : Multipart ,
122
+ ) -> Result < Json < serde_json:: Value > , ( StatusCode , Json < serde_json:: Value > ) > {
123
+ // get the name of aws bucket from env variable
124
+ let bucket = std:: env:: var ( "AWS_S3_BUCKET" ) . unwrap_or_else ( |_| "my-bucket-name" . to_owned ( ) ) ;
125
+ // if you have a public url for your bucket, place it as ENV variable BUCKET_URL
126
+ let bucket_url = std:: env:: var ( "BUCKET_URL" ) . unwrap_or_else ( |_| bucket. to_owned ( ) ) ;
127
+ // if a sub folder path is set in environment then get that else set a default sub path
128
+ let sub_path = std:: env:: var ( "BUCKET_SUB_PATH" ) . unwrap_or_else ( |_| "uploaded_images" . to_owned ( ) ) ;
129
+ // we are going to store the respose in HashMap as filename: url => key: value
130
+ let mut res = HashMap :: new ( ) ;
131
+ while let Some ( file) = files. next_field ( ) . await . unwrap ( ) {
132
+ // this is the name which is sent in formdata from frontend or whoever called the api, i am
133
+ // using it as category, we can get the filename from file data
134
+ let category = file. name ( ) . unwrap ( ) . to_string ( ) ;
135
+ // name of the file with extention
136
+ let name = file. file_name ( ) . unwrap ( ) . to_string ( ) ;
137
+ // file data
138
+ let data = file. bytes ( ) . await . unwrap ( ) ;
139
+ // the request can control where to save the image on AWS S3
140
+ let request_path = if category. trim ( ) . is_empty ( ) { "" . to_owned ( ) } else { format ! ( "{}/" , & category. trim_end_matches( '/' ) ) } ;
141
+ // the path of file to store on aws s3 with file name and extention
142
+ // timestamp_category_filename => 14-12-2022_01:01:01_customer_somecustomer.jpg
143
+ let key = format ! (
144
+ "{}/images/{}_{}_{}" ,
145
+ sub_path,
146
+ & request_path,
147
+ & category,
148
+ & name
149
+ ) ;
150
+
151
+ // send Putobject request to aws s3
152
+ let _resp = s3_client
153
+ . put_object ( )
154
+ . bucket ( & bucket)
155
+ . key ( & key)
156
+ . body ( data. into ( ) )
157
+ . send ( )
158
+ . await
159
+ . map_err ( |err| {
160
+ dbg ! ( err) ;
161
+ (
162
+ StatusCode :: INTERNAL_SERVER_ERROR ,
163
+ Json ( serde_json:: json!( { "err" : "an error occured during image upload" } ) ) ,
164
+ )
165
+ } ) ?;
166
+ dbg ! ( _resp) ;
167
+ res. insert (
168
+ // concatinating name and category so even if the filenames are same it will not
169
+ // conflict
170
+ format ! ( "{}_{}" , & name, & category) ,
171
+ format ! ( "{}/{}" , bucket_url, key) ,
172
+ ) ;
173
+ }
174
+ // send the urls in response
175
+ Ok ( Json ( serde_json:: json!( res) ) )
176
+ }
0 commit comments