feat: user avatar as public asset

This commit is contained in:
Matthieu Bessat 2024-12-04 18:25:56 +01:00
parent f98a102854
commit 4763915812
17 changed files with 172 additions and 21 deletions

View file

@ -18,6 +18,8 @@ chrono = { workspace = true }
toml = { workspace = true }
sqlx = { workspace = true }
dotenvy = { workspace = true }
sha2 = { workspace = true }
hex-literal = { workspace = true }
uuid = { workspace = true }
url = { workspace = true }

View file

@ -1,3 +1,4 @@
pub mod config;
pub mod user;
pub mod user_asset;
pub mod authorization;

View file

@ -23,7 +23,7 @@ struct User {
full_name: Option<String>,
email: Option<String>,
website: Option<String>,
picture: Option<Vec<u8>>, // embeded blob to store profile pic
avatar_asset_id: Option<String>,
password_hash: Option<String>, // argon2 password hash
status: UserStatus,
roles: Json<Vec<String>>,
@ -43,7 +43,7 @@ impl User {
full_name: None,
email: None,
website: None,
picture: None,
avatar_asset_id: None,
password_hash: None,
status: UserStatus::Disabled,
roles: Json(Vec::new()),

View file

@ -0,0 +1,41 @@
use fully_pub::fully_pub;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use uuid::Uuid;
use sha2::{Sha256, Digest};
use super::user::User;
#[derive(sqlx::FromRow, Deserialize, Serialize, Debug)]
#[fully_pub]
struct UserAsset {
/// uuid
id: String,
user_id: String,
mime_type: String,
fingerprint: String,
name: Option<String>,
content: Vec<u8>,
created_at: DateTime<Utc>
}
impl UserAsset {
pub fn new(
user: &User,
content: Vec<u8>,
mime_type: String,
name: Option<String>
) -> UserAsset {
let digest = Sha256::digest(&content);
UserAsset {
id: Uuid::new_v4().to_string(),
user_id: user.id.clone(),
fingerprint: format!("{:x}", digest),
mime_type,
content,
name,
created_at: Utc::now()
}
}
}

View file

@ -1,6 +1,6 @@
// user repositories
use crate::models::user::User;
use crate::models::{user::User, user_asset::UserAsset};
use super::storage::Storage;
use anyhow::{Result, Context};
@ -19,3 +19,30 @@ pub async fn get_users(storage: &Storage) -> Result<Vec<User>> {
.await
.context("To get users.")
}
pub async fn create_user_asset(storage: &Storage, asset: UserAsset) -> Result<()> {
sqlx::query("INSERT INTO user_assets
(id, user_id, mime_type, fingerprint, content, created_at)
VALUES ($1, $2, $3, $4, $5, $6)
")
.bind(&asset.id)
.bind(&asset.user_id)
.bind(&asset.mime_type)
.bind(&asset.fingerprint)
.bind(&asset.content)
.bind(&asset.created_at)
.execute(&storage.0)
.await
.context("While inserting user asset.")?;
// .bind(details_update.avatar.contents.to_vec())
Ok(())
}
pub async fn get_user_asset_by_id(storage: &Storage, id: &str) -> Result<UserAsset> {
sqlx::query_as("SELECT * FROM user_assets WHERE id = $1")
.bind(id)
.fetch_one(&storage.0)
.await
.context("To get user asset by id.")
}