feat: Identity JSON sync mechanism
- storage.rs: add local_profile field, check disk for profile.jpg in save_identity_file_by_pool - tmdb_api.rs: trigger JSON sync after TMDb probe - identity_api.rs: upload_profile_image triggers JSON sync - identity_binding.rs: bind/unbind/merge trigger JSON sync - get_identity_json: replace DB fallback with Lazy Sync (generates JSON from DB if missing) - Fixes missing/obsolete JSON files for all identity mutations
This commit is contained in:
@@ -18,6 +18,9 @@ pub struct IdentityFile {
|
||||
pub status: Option<String>,
|
||||
pub tmdb_id: Option<i32>,
|
||||
pub tmdb_profile: Option<String>,
|
||||
/// Local profile image filename (e.g., "profile.jpg") if uploaded by user.
|
||||
/// Overrides tmdb_profile if present.
|
||||
pub local_profile: Option<String>,
|
||||
pub metadata: serde_json::Value,
|
||||
pub file_bindings: Vec<FileBinding>,
|
||||
pub created_at: String,
|
||||
@@ -187,7 +190,7 @@ pub async fn save_identity_file_by_pool(pool: &sqlx::PgPool, uuid: &str) -> Resu
|
||||
let clean = uuid.replace('-', "");
|
||||
let record = sqlx::query_as::<_, crate::core::db::IdentityDetailRecord>(
|
||||
&format!(
|
||||
"SELECT id, uuid::text, name, identity_type, source, status, metadata, reference_data, \
|
||||
"SELECT id, uuid::text, COALESCE(real_name, actor_name, name) AS name, identity_type, source, status, metadata, reference_data, \
|
||||
NULL::real[] as voice_embedding, NULL::real[] as identity_embedding, \
|
||||
face_embedding::real[] as face_embedding, \
|
||||
tmdb_id, tmdb_profile, created_at::timestamptz as created_at, NULL::timestamptz as updated_at \
|
||||
@@ -222,6 +225,14 @@ pub async fn save_identity_file_by_pool(pool: &sqlx::PgPool, uuid: &str) -> Resu
|
||||
})
|
||||
.collect();
|
||||
|
||||
// Check for local profile image
|
||||
let profile_path = identity_dir(&clean).join("profile.jpg");
|
||||
let local_profile = if profile_path.exists() {
|
||||
Some("profile.jpg".to_string())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let fmt_time = |dt: Option<chrono::DateTime<chrono::Utc>>| -> String {
|
||||
dt.map(|d| d.to_rfc3339())
|
||||
.unwrap_or_else(|| chrono::Utc::now().to_rfc3339())
|
||||
@@ -236,6 +247,7 @@ pub async fn save_identity_file_by_pool(pool: &sqlx::PgPool, uuid: &str) -> Resu
|
||||
status: record.status,
|
||||
tmdb_id: record.tmdb_id,
|
||||
tmdb_profile: record.tmdb_profile,
|
||||
local_profile,
|
||||
metadata: record.metadata,
|
||||
file_bindings,
|
||||
created_at: fmt_time(record.created_at),
|
||||
@@ -349,6 +361,15 @@ pub async fn save_identity_file(db: &PostgresDb, uuid: &str) -> Result<()> {
|
||||
})
|
||||
.collect();
|
||||
|
||||
// Check for local profile image
|
||||
let clean = uuid.replace('-', "");
|
||||
let profile_path = identity_dir(&clean).join("profile.jpg");
|
||||
let local_profile = if profile_path.exists() {
|
||||
Some("profile.jpg".to_string())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let fmt_time = |dt: Option<chrono::DateTime<chrono::Utc>>| -> String {
|
||||
dt.map(|d| d.to_rfc3339())
|
||||
.unwrap_or_else(|| chrono::Utc::now().to_rfc3339())
|
||||
@@ -363,6 +384,7 @@ pub async fn save_identity_file(db: &PostgresDb, uuid: &str) -> Result<()> {
|
||||
status: record.status,
|
||||
tmdb_id: record.tmdb_id,
|
||||
tmdb_profile: record.tmdb_profile,
|
||||
local_profile,
|
||||
metadata: record.metadata,
|
||||
file_bindings,
|
||||
created_at: fmt_time(record.created_at),
|
||||
|
||||
Reference in New Issue
Block a user