mixvideo-v2/apps/desktop/src-tauri/src/business/services/project_service.rs

143 lines
4.2 KiB
Rust

use crate::data::models::project::{Project, CreateProjectRequest, UpdateProjectRequest};
use crate::data::repositories::project_repository::ProjectRepository;
use crate::infrastructure::file_system::FileSystemService;
use anyhow::{Result, anyhow};
/// 项目业务服务
/// 遵循 Tauri 开发规范的业务逻辑层设计
pub struct ProjectService;
impl ProjectService {
/// 创建新项目
/// 遵循安全第一原则,验证输入数据和文件系统权限
pub fn create_project(
repository: &ProjectRepository,
request: CreateProjectRequest,
) -> Result<Project> {
// 验证请求数据
request.validate().map_err(|e| anyhow!(e))?;
// 验证路径
if !FileSystemService::is_valid_project_directory(&request.path)? {
return Err(anyhow!("无效的项目路径或没有访问权限"));
}
// 获取绝对路径
let absolute_path = FileSystemService::get_absolute_path(&request.path)?;
// 检查路径是否已被使用
if repository.path_exists(&absolute_path, None)? {
return Err(anyhow!("该路径已被其他项目使用"));
}
// 创建项目实例
let project = Project::new(
request.name,
absolute_path.clone(),
request.description,
);
// 验证项目数据
project.validate().map_err(|e| anyhow!(e))?;
// 创建项目目录结构
FileSystemService::create_project_structure(&absolute_path)?;
// 保存到数据库
repository.create(&project)?;
Ok(project)
}
/// 获取所有活跃项目
pub fn get_all_projects(repository: &ProjectRepository) -> Result<Vec<Project>> {
let projects = repository.find_all_active()?;
// 验证项目路径是否仍然有效
let mut valid_projects = Vec::new();
for project in projects {
if FileSystemService::validate_path(&project.path).unwrap_or(false) {
valid_projects.push(project);
}
}
Ok(valid_projects)
}
/// 根据ID获取项目
pub fn get_project_by_id(
repository: &ProjectRepository,
id: &str,
) -> Result<Option<Project>> {
if id.trim().is_empty() {
return Err(anyhow!("项目ID不能为空"));
}
let project = repository.find_by_id(id)?;
// 验证项目路径是否仍然有效
if let Some(ref proj) = project {
if !FileSystemService::validate_path(&proj.path).unwrap_or(false) {
return Err(anyhow!("项目路径不存在或无法访问"));
}
}
Ok(project)
}
/// 更新项目
pub fn update_project(
repository: &ProjectRepository,
id: &str,
request: UpdateProjectRequest,
) -> Result<Project> {
// 验证请求数据
request.validate().map_err(|e| anyhow!(e))?;
// 获取现有项目
let mut project = repository.find_by_id(id)?
.ok_or_else(|| anyhow!("项目不存在"))?;
// 更新项目信息
project.update(request.name, request.description);
// 验证更新后的项目数据
project.validate().map_err(|e| anyhow!(e))?;
// 保存更新
repository.update(&project)?;
Ok(project)
}
/// 删除项目
pub fn delete_project(repository: &ProjectRepository, id: &str) -> Result<()> {
if id.trim().is_empty() {
return Err(anyhow!("项目ID不能为空"));
}
// 检查项目是否存在
let project = repository.find_by_id(id)?
.ok_or_else(|| anyhow!("项目不存在"))?;
// 执行软删除
repository.delete(&project.id)?;
Ok(())
}
/// 验证项目路径
pub fn validate_project_path(path: &str) -> Result<bool> {
if path.trim().is_empty() {
return Ok(false);
}
FileSystemService::is_valid_project_directory(path)
}
/// 获取目录名称作为默认项目名
pub fn get_default_project_name(path: &str) -> Result<String> {
FileSystemService::get_directory_name(path)
}
}