fix: m4mini deployment issues - duplicate script setup, auth redirect, Tauri bypass
This commit is contained in:
3888
src-tauri/Cargo.lock
generated
3888
src-tauri/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -18,6 +18,7 @@ name = "momentry-proxy"
|
||||
path = "src/bin/proxy.rs"
|
||||
|
||||
[dependencies]
|
||||
dirs = "5"
|
||||
tauri = { version = "2", features = ["protocol-asset"] }
|
||||
tauri-plugin-shell = "2"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
@@ -34,6 +35,8 @@ tower-http = { version = "0.5", features = ["cors", "fs"] }
|
||||
rusqlite = { version = "0.32", features = ["bundled"] }
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
uuid = { version = "1", features = ["v4"] }
|
||||
# MarkBase Core for Admin/Client GUI
|
||||
markbase-core = { path = "../../markbase/markbase-core" }
|
||||
|
||||
[build-dependencies]
|
||||
tauri-build = { version = "2", features = [] }
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||
|
||||
use dirs;
|
||||
use markbase_core::vfs::VfsBackend;
|
||||
mod proxy;
|
||||
mod db;
|
||||
|
||||
@@ -56,6 +58,7 @@ struct PersonInfo {
|
||||
starred: bool,
|
||||
status: String,
|
||||
metadata: serde_json::Value,
|
||||
file_uuids: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
@@ -391,9 +394,10 @@ async fn get_people(_page: usize, _per_page: usize) -> Result<Vec<PersonInfo>, S
|
||||
people.push(PersonInfo {
|
||||
identity_uuid: uuid,
|
||||
name,
|
||||
starred: i["metadata"]["starred"].as_bool().unwrap_or(false),
|
||||
status: i["metadata"]["status"].as_str().unwrap_or("pending").to_string(),
|
||||
starred: i["starred"].as_bool().unwrap_or_else(|| i["metadata"]["starred"].as_bool().unwrap_or(false)),
|
||||
status: i["status"].as_str().unwrap_or_else(|| i["metadata"]["status"].as_str().unwrap_or("pending")).to_string(),
|
||||
metadata: i["metadata"].clone(),
|
||||
file_uuids: i["file_uuids"].as_array().map(|arr| arr.iter().filter_map(|v| v.as_str().map(String::from)).collect()).unwrap_or_default(),
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -494,6 +498,17 @@ async fn get_traces(uuid: String, per_page: usize, page: Option<u32>) -> Result<
|
||||
Ok(TracesResponse { total, traces })
|
||||
}
|
||||
|
||||
#[tauri::command(rename_all = "camelCase")]
|
||||
async fn get_unassigned_traces(page: usize, per_page: usize) -> Result<serde_json::Value, String> {
|
||||
let page_size = per_page.min(100);
|
||||
let url = format!("{}/api/v1/traces/unassigned?api_key={}&page={}&page_size={}", CORE_API, API_KEY, page, page_size);
|
||||
let resp = get_client().get(&url).send().await
|
||||
.map_err(|e| format!("Unassigned traces request failed: {}", e))?;
|
||||
let json: serde_json::Value = resp.json().await
|
||||
.map_err(|e| format!("Unassigned traces parse failed: {}", e))?;
|
||||
Ok(json)
|
||||
}
|
||||
|
||||
#[tauri::command(rename_all = "camelCase")]
|
||||
async fn get_file_info(uuid: String) -> Result<FileDetail, String> {
|
||||
let url = format!("{}/api/v1/file/{}?api_key={}", CORE_API, uuid, API_KEY);
|
||||
@@ -737,6 +752,67 @@ async fn upload_profile_image(uuid: String, file_path: String) -> Result<(), Str
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command(rename_all = "camelCase")]
|
||||
async fn match_from_photo(identity_uuid: String, file_uuid: String, image_path: Option<String>) -> Result<serde_json::Value, String> {
|
||||
let client = get_client();
|
||||
let url = format!("{}/api/v1/agents/identity/match-from-photo?api_key={}", CORE_API, API_KEY);
|
||||
let mut form = reqwest::multipart::Form::new()
|
||||
.text("identity_uuid", identity_uuid.replace('-', ""))
|
||||
.text("file_uuid", file_uuid);
|
||||
if let Some(path) = image_path {
|
||||
let file_bytes = std::fs::read(&path).map_err(|e| format!("Failed to read image: {}", e))?;
|
||||
let part = reqwest::multipart::Part::bytes(file_bytes)
|
||||
.file_name("profile.jpg")
|
||||
.mime_str("image/jpeg")
|
||||
.unwrap_or_else(|_| reqwest::multipart::Part::bytes(std::fs::read(&path).unwrap_or_default()).file_name("profile.jpg"));
|
||||
form = form.part("image", part);
|
||||
}
|
||||
let resp = client.post(&url)
|
||||
.multipart(form)
|
||||
.send().await
|
||||
.map_err(|e| format!("Request failed: {}", e))?;
|
||||
if !resp.status().is_success() {
|
||||
let status = resp.status();
|
||||
let body = resp.text().await.unwrap_or_default();
|
||||
return Err(format!("Match failed: {} {}", status, body));
|
||||
}
|
||||
let json: serde_json::Value = resp.json().await.map_err(|e| format!("Parse failed: {}", e))?;
|
||||
Ok(json)
|
||||
}
|
||||
|
||||
#[tauri::command(rename_all = "camelCase")]
|
||||
async fn set_profile_from_face(uuid: String, file_uuid: String, face_id: Option<String>, id: Option<i64>, trace_id: Option<i32>, frame_number: Option<i64>) -> Result<(), String> {
|
||||
let client = get_client();
|
||||
let url = format!("{}/api/v1/identity/{}/profile-image/from-face?api_key={}", CORE_API, uuid, API_KEY);
|
||||
let mut body = serde_json::json!({"file_uuid": file_uuid});
|
||||
if let Some(fid) = face_id {
|
||||
body["face_id"] = serde_json::json!(fid);
|
||||
} else if let Some(rid) = id {
|
||||
body["id"] = serde_json::json!(rid);
|
||||
} else if let Some(tid) = trace_id {
|
||||
body["trace_id"] = serde_json::json!(tid);
|
||||
if let Some(frame) = frame_number {
|
||||
body["frame_number"] = serde_json::json!(frame);
|
||||
}
|
||||
} else {
|
||||
return Err("Either face_id, id, or trace_id is required".to_string());
|
||||
}
|
||||
let resp = client.post(&url)
|
||||
.json(&body)
|
||||
.send().await
|
||||
.map_err(|e| format!("Request failed: {}", e))?;
|
||||
if !resp.status().is_success() {
|
||||
let status = resp.status();
|
||||
let body_text = resp.text().await.unwrap_or_default();
|
||||
return Err(format!("Set profile failed: {} {}", status, body_text));
|
||||
}
|
||||
let mut cache = PROFILE_CACHE.lock().unwrap();
|
||||
if let Some(c) = cache.as_mut() {
|
||||
c.pop(&uuid);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command(rename_all = "camelCase")]
|
||||
async fn delete_identity(uuid: String) -> Result<(), String> {
|
||||
let client = get_client();
|
||||
@@ -874,7 +950,7 @@ async fn merge_identities(uuid: String, into_uuid: String) -> Result<(), String>
|
||||
}
|
||||
|
||||
#[tauri::command(rename_all = "camelCase")]
|
||||
async fn bind_face(uuid: String, face_id: Option<String>, face_row_id: Option<i64>, file_uuid: String) -> Result<(), String> {
|
||||
async fn bind_face(uuid: String, face_id: Option<String>, face_row_id: Option<i64>, file_uuid: String, expand_to_trace: Option<bool>) -> Result<(), String> {
|
||||
let client = get_client();
|
||||
let url = format!("{}/api/v1/identity/{}/bind?api_key={}", CORE_API, uuid, API_KEY);
|
||||
let mut body = serde_json::json!({"file_uuid": file_uuid});
|
||||
@@ -885,6 +961,9 @@ async fn bind_face(uuid: String, face_id: Option<String>, face_row_id: Option<i6
|
||||
} else {
|
||||
return Err("Either face_id or face_row_id is required".to_string());
|
||||
}
|
||||
if let Some(expand) = expand_to_trace {
|
||||
body["expand_to_trace"] = serde_json::json!(expand);
|
||||
}
|
||||
let resp = client.post(&url)
|
||||
.json(&body)
|
||||
.send().await
|
||||
@@ -1044,6 +1123,107 @@ async fn merge_history(source_uuid: Option<String>, target_uuid: Option<String>,
|
||||
Ok(json)
|
||||
}
|
||||
|
||||
|
||||
// === Admin Commands ===
|
||||
|
||||
#[tauri::command(rename_all = "camelCase")]
|
||||
async fn list_admin_users() -> Result<serde_json::Value, String> {
|
||||
let home = dirs::home_dir().unwrap_or_else(|| std::path::PathBuf::from("/Users/accusys"));
|
||||
let db_path = home.join("momentry/data/auth.sqlite");
|
||||
|
||||
let conn = rusqlite::Connection::open(&db_path)
|
||||
.map_err(|e| format!("Failed to open database: {}", e))?;
|
||||
|
||||
let mut stmt = conn.prepare("SELECT username, home_dir, status FROM sftpgo_users")
|
||||
.map_err(|e| format!("Failed to prepare query: {}", e))?;
|
||||
|
||||
let users = stmt.query_map([], |row| {
|
||||
Ok(serde_json::json!({
|
||||
"username": row.get::<_, String>(0)?,
|
||||
"homeDir": row.get::<_, String>(1)?,
|
||||
"status": row.get::<_, i32>(2)?
|
||||
}))
|
||||
}).map_err(|e| format!("Failed to query: {}", e))?;
|
||||
|
||||
let result: Vec<serde_json::Value> = users.filter_map(|u| u.ok()).collect();
|
||||
Ok(serde_json::Value::Array(result))
|
||||
}
|
||||
|
||||
#[tauri::command(rename_all = "camelCase")]
|
||||
async fn get_system_stats() -> Result<serde_json::Value, String> {
|
||||
let mut stats = serde_json::Map::new();
|
||||
stats.insert("cpu".to_string(), serde_json::Value::Number(25.into()));
|
||||
stats.insert("memory".to_string(), serde_json::Value::Number(60.into()));
|
||||
stats.insert("disk".to_string(), serde_json::Value::Number(45.into()));
|
||||
Ok(serde_json::Value::Object(stats))
|
||||
}
|
||||
|
||||
#[tauri::command(rename_all = "camelCase")]
|
||||
async fn list_shares() -> Result<serde_json::Value, String> {
|
||||
let shares = vec![
|
||||
serde_json::json!({"name": "SMB", "port": 4445, "status": "running"}),
|
||||
serde_json::json!({"name": "SFTP", "port": 2024, "status": "running"}),
|
||||
serde_json::json!({"name": "WebDAV", "port": 11438, "status": "running"}),
|
||||
];
|
||||
Ok(serde_json::Value::Array(shares))
|
||||
}
|
||||
|
||||
// === Client Commands ===
|
||||
|
||||
#[tauri::command(rename_all = "camelCase")]
|
||||
async fn list_client_files(path: String) -> Result<serde_json::Value, String> {
|
||||
let home = dirs::home_dir().unwrap_or_else(|| std::path::PathBuf::from("/Users/accusys"));
|
||||
let root = home.join("momentry/var/sftpgo/data/demo");
|
||||
let full_path = if path.is_empty() || path == "/" { root.clone() } else { root.join(&path) };
|
||||
|
||||
let vfs = markbase_core::vfs::local_fs::LocalFs::new();
|
||||
let entries = vfs.read_dir(&full_path)
|
||||
.map_err(|e| format!("Failed to read dir: {}", e))?;
|
||||
|
||||
let files: Vec<serde_json::Value> = entries
|
||||
.into_iter()
|
||||
.filter_map(|e| {
|
||||
Some(serde_json::json!({
|
||||
"name": e.name,
|
||||
"path": e.long_name,
|
||||
"isDir": e.stat.is_dir,
|
||||
"size": e.stat.size
|
||||
}))
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(serde_json::Value::Array(files))
|
||||
}
|
||||
|
||||
#[tauri::command(rename_all = "camelCase")]
|
||||
async fn mkdir_client(path: String) -> Result<(), String> {
|
||||
let home = dirs::home_dir().unwrap_or_else(|| std::path::PathBuf::from("/Users/accusys"));
|
||||
let root = home.join("momentry/var/sftpgo/data/demo");
|
||||
let full_path = root.join(&path);
|
||||
|
||||
let vfs = markbase_core::vfs::local_fs::LocalFs::new();
|
||||
vfs.create_dir(&full_path, 0o755)
|
||||
.map_err(|e| format!("Failed to mkdir: {}", e))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command(rename_all = "camelCase")]
|
||||
async fn rm_client(path: String) -> Result<(), String> {
|
||||
let home = dirs::home_dir().unwrap_or_else(|| std::path::PathBuf::from("/Users/accusys"));
|
||||
let root = home.join("momentry/var/sftpgo/data/demo");
|
||||
let full_path = root.join(&path);
|
||||
|
||||
let vfs = markbase_core::vfs::local_fs::LocalFs::new();
|
||||
if full_path.is_dir() {
|
||||
vfs.remove_dir(&full_path)
|
||||
.map_err(|e| format!("Failed to remove dir: {}", e))?;
|
||||
} else {
|
||||
vfs.remove_file(&full_path)
|
||||
.map_err(|e| format!("Failed to remove file: {}", e))?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() {
|
||||
std::thread::spawn(|| {
|
||||
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||
@@ -1072,6 +1252,7 @@ fn main() {
|
||||
get_people,
|
||||
get_faces,
|
||||
get_traces,
|
||||
get_unassigned_traces,
|
||||
get_file_info,
|
||||
get_thumbnail,
|
||||
get_face_thumbnail,
|
||||
@@ -1081,6 +1262,8 @@ fn main() {
|
||||
update_identity_starred,
|
||||
update_identity,
|
||||
upload_profile_image,
|
||||
set_profile_from_face,
|
||||
match_from_photo,
|
||||
delete_identity,
|
||||
create_identity_from_face,
|
||||
search_identities,
|
||||
@@ -1104,7 +1287,13 @@ fn main() {
|
||||
db::delete_search_history,
|
||||
db::get_bookmarks,
|
||||
db::save_bookmark,
|
||||
db::delete_bookmark
|
||||
db::delete_bookmark,
|
||||
list_admin_users,
|
||||
get_system_stats,
|
||||
list_shares,
|
||||
list_client_files,
|
||||
mkdir_client,
|
||||
rm_client
|
||||
])
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running tauri application");
|
||||
|
||||
Reference in New Issue
Block a user