| 15 | |
| 16 | #[debug_handler] |
| 17 | pub async fn upload( |
| 18 | _auth: auth::JWT, |
| 19 | Path(notes_id): Path<i32>, |
| 20 | State(ctx): State<AppContext>, |
| 21 | mut multipart: Multipart, |
| 22 | ) -> Result<Response> { |
| 23 | // Collect all uploaded files |
| 24 | let mut files = Vec::new(); |
| 25 | |
| 26 | // Iterate all files in the POST body |
| 27 | while let Some(field) = multipart.next_field().await.map_err(|err| { |
| 28 | tracing::error!(error = ?err,"could not readd multipart"); |
| 29 | Error::BadRequest("could not readd multipart".into()) |
| 30 | })? { |
| 31 | // Get the file name |
| 32 | let file_name = match field.file_name() { |
| 33 | Some(file_name) => file_name.to_string(), |
| 34 | _ => return Err(Error::BadRequest("file name not found".into())), |
| 35 | }; |
| 36 | |
| 37 | // Get the file content as bytes |
| 38 | let content = field.bytes().await.map_err(|err| { |
| 39 | tracing::error!(error = ?err,"could not readd bytes"); |
| 40 | Error::BadRequest("could not readd bytes".into()) |
| 41 | })?; |
| 42 | |
| 43 | // Create a folder to store the uploaded file |
| 44 | let now = chrono::offset::Local::now() |
| 45 | .format("%Y%m%d_%H%M%S") |
| 46 | .to_string(); |
| 47 | let uuid = uuid::Uuid::new_v4().to_string(); |
| 48 | let folder = format!("{now}_{uuid}"); |
| 49 | let upload_folder = PathBuf::from(UPLOAD_DIR).join(&folder); |
| 50 | fs::create_dir_all(&upload_folder).await?; |
| 51 | |
| 52 | // Write the file into the newly created folder |
| 53 | let path = upload_folder.join(file_name); |
| 54 | let mut f = fs::OpenOptions::new() |
| 55 | .create_new(true) |
| 56 | .write(true) |
| 57 | .open(&path) |
| 58 | .await?; |
| 59 | f.write_all(&content).await?; |
| 60 | f.flush().await?; |
| 61 | |
| 62 | // Record the file upload in database |
| 63 | let file = files::ActiveModel { |
| 64 | notes_id: ActiveValue::Set(notes_id), |
| 65 | file_path: ActiveValue::Set( |
| 66 | path.strip_prefix(UPLOAD_DIR) |
| 67 | .unwrap() |
| 68 | .to_str() |
| 69 | .unwrap() |
| 70 | .to_string(), |
| 71 | ), |
| 72 | ..Default::default() |
| 73 | } |
| 74 | .insert(&ctx.db) |