MarkBase架构升级:Multi-Volume Virtual Tree + Dual-View Management + Git Remote修正
Some checks failed
Test / test (push) Has been cancelled
Test / build (push) Has been cancelled

核心功能:
-  Categories/Series双视图管理(category_view.rs + import_markdown.rs)
-  FUSE Multi-Volume支持(tree_type参数)
-  SSH/SFTP/SCP/rsync协议完整实现(4042行)
-  NFS/SMB Module Phase 1-3完成
-  Archive Module Phase 1-4完成(2916行)
-  Download Center API完整实现
-  S3兼容API实现(560行)

Git配置修正:
-  删除错误origin(gitea.momentry.ddns.net)
-  删除m5max128(指向机器名)
-  设置origin = m5max128gitea.momentry.ddns.net/admin/markbase
-  设置m4minigitea = m4minigitea.momentry.ddns.net/warren/markbase

数据清理:
-  删除38个临时SQLite(保留accusys.sqlite、demo.sqlite)
-  删除.bak、test_*.bin、调试脚本等临时文件
-  删除临时目录(build/、download files/、raid_test/等)
-  更新.gitignore排除临时文件

架构优化:
- 52个文件修改,2434行新增,4739行删除
- Workspace成员整合(16个crate)
- 数据库状态:accusys.sqlite保留(主demo测试)

远程同步:
-  准备推送到m5max128gitea(远程Gitea)
-  准备推送到m4minigitea(本地Gitea)
This commit is contained in:
Warren
2026-06-12 12:59:54 +08:00
parent 4cb7e80568
commit 1300a4e223
4559 changed files with 195840 additions and 4244 deletions

View File

@@ -1,6 +1,6 @@
use anyhow::Result;
use chrono::Utc;
use rusqlite::{Connection, params};
use rusqlite::{params, Connection};
use serde::{Deserialize, Serialize};
use std::path::Path;
@@ -90,14 +90,14 @@ impl SyncResult {
..Default::default()
}
}
pub fn cached() -> Self {
Self {
status: "cached".to_string(),
..Default::default()
}
}
pub fn failed(error: String) -> Self {
Self {
status: "failed".to_string(),
@@ -105,7 +105,7 @@ impl SyncResult {
..Default::default()
}
}
pub fn merge(&mut self, other: SyncResult) {
self.users_synced += other.users_synced;
self.users_failed += other.users_failed;
@@ -114,7 +114,7 @@ impl SyncResult {
self.mappings_synced += other.mappings_synced;
self.mappings_failed += other.mappings_failed;
self.errors.extend(other.errors);
if self.users_failed > 0 || self.groups_failed > 0 || self.mappings_failed > 0 {
if self.users_synced > 0 || self.groups_synced > 0 || self.mappings_synced > 0 {
self.status = "partial_success".to_string();
@@ -135,23 +135,25 @@ impl AuthDb {
if !Path::new(path).exists() {
Self::init_db(path)?;
}
Ok(Self { path: path.to_string() })
Ok(Self {
path: path.to_string(),
})
}
pub fn init_db(path: &str) -> Result<()> {
let conn = Connection::open(path)?;
conn.execute_batch(include_str!("../data/init_auth_db.sql"))?;
conn.execute_batch(include_str!("../../data/init_auth_db.sql"))?;
Ok(())
}
pub fn open(&self) -> Result<Connection> {
Ok(Connection::open(&self.path)?)
}
pub fn save_user(&self, user: &PgUser) -> Result<()> {
let conn = self.open()?;
let now = Utc::now().timestamp();
conn.execute(
"INSERT OR REPLACE INTO sftpgo_users
(username, password_hash, email, status, home_dir, permissions,
@@ -171,16 +173,16 @@ impl AuthDb {
user.updated_at,
now,
1, // sync_status = synced
]
],
)?;
Ok(())
}
pub fn save_group(&self, group: &PgGroup) -> Result<()> {
let conn = self.open()?;
let now = Utc::now().timestamp();
conn.execute(
"INSERT OR REPLACE INTO sftpgo_groups
(name, description, created_at, updated_at, last_sync_at)
@@ -191,33 +193,29 @@ impl AuthDb {
group.created_at,
group.updated_at,
now,
]
],
)?;
Ok(())
}
pub fn save_mapping(&self, mapping: &PgUserGroupMapping) -> Result<()> {
let conn = self.open()?;
let now = Utc::now().timestamp();
conn.execute(
"INSERT OR REPLACE INTO users_groups_mapping
(username, group_name, created_at)
VALUES (?1, ?2, ?3)",
params![
mapping.username,
mapping.group_name,
now,
]
params![mapping.username, mapping.group_name, now,],
)?;
Ok(())
}
pub fn save_sync_log(&self, result: &SyncResult) -> Result<()> {
let conn = self.open()?;
conn.execute(
"INSERT INTO sync_log
(sync_type, sync_time, users_synced, users_failed,
@@ -238,9 +236,9 @@ impl AuthDb {
result.admins_failed,
result.status,
result.errors.join(";"),
]
],
)?;
log::info!(
"Sync log saved: users={}, groups={}, mappings={}, admins={}, status={}",
result.users_synced,
@@ -249,13 +247,13 @@ impl AuthDb {
result.admins_synced,
result.status
);
Ok(())
}
pub fn save_admin(&self, admin: &PgAdmin) -> Result<()> {
let conn = self.open()?;
conn.execute(
"INSERT OR REPLACE INTO sftpgo_admins
(username, password_hash, email, description, status,
@@ -277,94 +275,96 @@ impl AuthDb {
Utc::now().timestamp(),
],
)?;
Ok(())
}
pub fn get_admin(&self, username: &str) -> Result<Option<PgAdmin>> {
let conn = self.open()?;
let result = conn.query_row(
"SELECT username, password_hash, email, description, status,
permissions, filters, role_id, last_login,
created_at, updated_at
FROM sftpgo_admins WHERE username = ?1 AND status = 1",
params![username],
|row| Ok(PgAdmin {
username: row.get(0)?,
password_hash: row.get(1)?,
email: row.get(2)?,
description: row.get(3)?,
status: row.get(4)?,
permissions: row.get(5)?,
filters: row.get(6)?,
role_id: row.get(7)?,
last_login: row.get(8)?,
created_at: row.get(9)?,
updated_at: row.get(10)?,
}),
|row| {
Ok(PgAdmin {
username: row.get(0)?,
password_hash: row.get(1)?,
email: row.get(2)?,
description: row.get(3)?,
status: row.get(4)?,
permissions: row.get(5)?,
filters: row.get(6)?,
role_id: row.get(7)?,
last_login: row.get(8)?,
created_at: row.get(9)?,
updated_at: row.get(10)?,
})
},
);
match result {
Ok(admin) => Ok(Some(admin)),
Err(rusqlite::Error::QueryReturnedNoRows) => Ok(None),
Err(e) => Err(e.into()),
}
}
pub fn sync_admins(&self, admins: Vec<PgAdmin>) -> Result<usize> {
let mut synced = 0;
for admin in admins {
match self.save_admin(&admin) {
Ok(_) => synced += 1,
Err(e) => log::warn!("Failed to sync admin {}: {}", admin.username, e),
}
}
Ok(synced)
}
pub fn get_user(&self, username: &str) -> Result<Option<PgUser>> {
let conn = self.open()?;
let result = conn.query_row(
"SELECT username, password_hash, email, status, home_dir, permissions,
uid, gid, last_login, created_at, updated_at
FROM sftpgo_users WHERE username = ?1 AND status = 1",
params![username],
|row| Ok(PgUser {
username: row.get(0)?,
password_hash: row.get(1)?,
email: row.get(2)?,
status: row.get(3)?,
home_dir: row.get(4)?,
permissions: row.get(5)?,
uid: row.get(6)?,
gid: row.get(7)?,
last_login: row.get(8)?,
created_at: row.get(9)?,
updated_at: row.get(10)?,
})
|row| {
Ok(PgUser {
username: row.get(0)?,
password_hash: row.get(1)?,
email: row.get(2)?,
status: row.get(3)?,
home_dir: row.get(4)?,
permissions: row.get(5)?,
uid: row.get(6)?,
gid: row.get(7)?,
last_login: row.get(8)?,
created_at: row.get(9)?,
updated_at: row.get(10)?,
})
},
);
match result {
Ok(user) => Ok(Some(user)),
Err(rusqlite::Error::QueryReturnedNoRows) => Ok(None),
Err(e) => Err(e.into()),
}
}
pub fn get_user_groups(&self, username: &str) -> Result<Vec<String>> {
let conn = self.open()?;
let groups: Vec<String> = conn
.prepare(
"SELECT group_name FROM users_groups_mapping WHERE username = ?1"
)?
.prepare("SELECT group_name FROM users_groups_mapping WHERE username = ?1")?
.query_map(params![username], |row| row.get(0))?
.collect::<Result<Vec<_>, _>>()?;
Ok(groups)
}
}
}