Can upload files
This commit is contained in:
125
moneymgr_backend/src/services/files_service.rs
Normal file
125
moneymgr_backend/src/services/files_service.rs
Normal file
@ -0,0 +1,125 @@
|
||||
use crate::connections::db_connection::db;
|
||||
use crate::connections::s3_connection;
|
||||
use crate::models::files::{File, FileID, NewFile};
|
||||
use crate::models::users::UserID;
|
||||
use crate::schema::files;
|
||||
use crate::utils::crypt_utils::sha512;
|
||||
use crate::utils::time_utils::time;
|
||||
use diesel::prelude::*;
|
||||
use mime_guess::Mime;
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
enum FilesServiceError {
|
||||
#[error("UnknownMimeType!")]
|
||||
UnknownMimeType,
|
||||
}
|
||||
|
||||
pub async fn create_file_with_file_name(
|
||||
user_id: UserID,
|
||||
file_name: &str,
|
||||
bytes: &[u8],
|
||||
) -> anyhow::Result<File> {
|
||||
let mime = mime_guess::from_path(file_name)
|
||||
.first()
|
||||
.ok_or(FilesServiceError::UnknownMimeType)?;
|
||||
|
||||
create_file_with_mimetype(user_id, file_name, &mime, bytes).await
|
||||
}
|
||||
|
||||
pub async fn create_file_with_mimetype(
|
||||
user_id: UserID,
|
||||
file_name: &str,
|
||||
mime_type: &Mime,
|
||||
bytes: &[u8],
|
||||
) -> anyhow::Result<File> {
|
||||
let sha512 = sha512(bytes);
|
||||
|
||||
if let Ok(f) = get_file_with_hash(user_id, &sha512) {
|
||||
return Ok(f);
|
||||
}
|
||||
|
||||
let file = NewFile {
|
||||
time_create: time() as i64,
|
||||
mime_type: mime_type.as_ref(),
|
||||
sha512: &sha512,
|
||||
file_size: bytes.len() as i32,
|
||||
file_name,
|
||||
user_id: user_id.0,
|
||||
};
|
||||
|
||||
s3_connection::upload_file(&file.file_path(), bytes).await?;
|
||||
|
||||
let res = diesel::insert_into(files::table)
|
||||
.values(&file)
|
||||
.get_result(&mut db()?)?;
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
pub fn get_file_with_hash(user_id: UserID, sha512: &str) -> anyhow::Result<File> {
|
||||
Ok(files::table
|
||||
.filter(
|
||||
files::dsl::sha512
|
||||
.eq(sha512)
|
||||
.and(files::dsl::user_id.eq(user_id.0)),
|
||||
)
|
||||
.first(&mut db()?)?)
|
||||
}
|
||||
|
||||
pub fn get_file_with_id(id: FileID) -> anyhow::Result<File> {
|
||||
Ok(files::table
|
||||
.filter(files::dsl::id.eq(id.0))
|
||||
.first(&mut db()?)?)
|
||||
}
|
||||
|
||||
pub async fn get_file_content_by_id(id: FileID) -> anyhow::Result<Vec<u8>> {
|
||||
let file = get_file_with_id(id)?;
|
||||
get_file_content(&file).await
|
||||
}
|
||||
|
||||
pub async fn get_file_content(file: &File) -> anyhow::Result<Vec<u8>> {
|
||||
s3_connection::get_file(&file.file_path()).await
|
||||
}
|
||||
|
||||
/// Delete the file if it is not referenced anymore in the database. Returns true
|
||||
/// if the file was actually deleted, false otherwise
|
||||
pub async fn delete_file_if_unused(id: FileID) -> anyhow::Result<bool> {
|
||||
let file = get_file_with_id(id)?;
|
||||
|
||||
let res = diesel::delete(files::dsl::files.filter(files::dsl::id.eq(file.id().0)))
|
||||
.execute(&mut db()?);
|
||||
|
||||
match res {
|
||||
Ok(_) => {
|
||||
s3_connection::delete_file_if_exists(&file.file_path()).await?;
|
||||
log::info!("File {:?} was deleted", file.id());
|
||||
|
||||
Ok(true)
|
||||
}
|
||||
Err(e) => {
|
||||
log::info!(
|
||||
"File {:?} could not be deleted, it must be used somewhere: {e}",
|
||||
file.id()
|
||||
);
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the entire list of file
|
||||
pub async fn get_entire_list() -> anyhow::Result<Vec<File>> {
|
||||
Ok(files::table.get_results(&mut db()?)?)
|
||||
}
|
||||
|
||||
/// Remove unused files
|
||||
pub async fn run_garbage_collector() -> anyhow::Result<usize> {
|
||||
let mut count_deleted = 0;
|
||||
|
||||
for file in get_entire_list().await? {
|
||||
if delete_file_if_unused(file.id()).await? {
|
||||
count_deleted += 1;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(count_deleted)
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
pub mod accounts_service;
|
||||
pub mod files_service;
|
||||
pub mod tokens_service;
|
||||
pub mod users_service;
|
||||
|
@ -17,7 +17,7 @@ pub struct NewTokenInfo {
|
||||
pub right_account: bool,
|
||||
pub right_movement: bool,
|
||||
pub right_inbox: bool,
|
||||
pub right_attachment: bool,
|
||||
pub right_file: bool,
|
||||
pub right_auth: bool,
|
||||
}
|
||||
|
||||
@ -38,7 +38,7 @@ pub async fn create(new_token: NewTokenInfo) -> anyhow::Result<Token> {
|
||||
right_account: new_token.right_account,
|
||||
right_movement: new_token.right_movement,
|
||||
right_inbox: new_token.right_inbox,
|
||||
right_attachment: new_token.right_attachment,
|
||||
right_file: new_token.right_file,
|
||||
};
|
||||
|
||||
let res = diesel::insert_into(tokens::table)
|
||||
|
Reference in New Issue
Block a user