oxios_kernel/kernel_handle/
project_api.rs1use std::path::PathBuf;
9use std::sync::Arc;
10
11use anyhow::{Context, Result};
12use chrono::Utc;
13use serde::{Deserialize, Serialize};
14use uuid::Uuid;
15
16use crate::project::{Project, ProjectManager, ProjectSource};
17
18#[derive(Debug, Clone, Serialize, Deserialize)]
20#[allow(missing_docs)]
21pub struct ProjectInfo {
22 pub id: String,
23 pub name: String,
24 pub description: String,
25 pub source: String,
26 pub paths: Vec<String>,
27 pub tags: Vec<String>,
28 pub emoji: String,
29 pub memory_visible: bool,
30 pub created_at: String,
31 pub updated_at: String,
32 pub last_active_at: String,
33}
34
35impl From<&Project> for ProjectInfo {
36 fn from(project: &Project) -> Self {
37 Self {
38 id: project.id.to_string(),
39 name: project.name.clone(),
40 description: project.description.clone(),
41 source: project.source.to_string(),
42 paths: project
43 .paths
44 .iter()
45 .map(|p| p.to_string_lossy().to_string())
46 .collect(),
47 tags: project.tags.clone(),
48 emoji: project.emoji.clone(),
49 memory_visible: project.memory_visible,
50 created_at: project.created_at.to_rfc3339(),
51 updated_at: project.updated_at.to_rfc3339(),
52 last_active_at: project.last_active_at.to_rfc3339(),
53 }
54 }
55}
56
57#[allow(dead_code)]
62pub struct ProjectApi {
63 pub(crate) project_manager: Arc<ProjectManager>,
65}
66
67impl ProjectApi {
68 pub fn new(project_manager: Arc<ProjectManager>) -> Self {
70 Self { project_manager }
71 }
72
73 pub fn list_projects(&self) -> Vec<ProjectInfo> {
75 self.project_manager
76 .list_projects()
77 .iter()
78 .map(ProjectInfo::from)
79 .collect()
80 }
81
82 pub fn get_project(&self, id: &str) -> Option<ProjectInfo> {
84 let project_id = Uuid::parse_str(id).ok()?;
85 self.project_manager
86 .get_project(project_id)
87 .as_ref()
88 .map(ProjectInfo::from)
89 }
90
91 pub fn create_project(
93 &self,
94 name: String,
95 paths: Vec<String>,
96 tags: Vec<String>,
97 emoji: Option<String>,
98 description: Option<String>,
99 ) -> Result<ProjectInfo> {
100 let paths: Vec<PathBuf> = paths.into_iter().map(PathBuf::from).collect();
101 let project = self.project_manager.create_project(
102 name,
103 paths,
104 tags,
105 emoji,
106 description,
107 ProjectSource::Manual,
108 )?;
109 Ok(ProjectInfo::from(&project))
110 }
111
112 #[allow(clippy::too_many_arguments)]
114 pub fn update_project(
115 &self,
116 id: &str,
117 name: Option<String>,
118 paths: Option<Vec<String>>,
119 tags: Option<Vec<String>>,
120 emoji: Option<String>,
121 description: Option<String>,
122 memory_visible: Option<bool>,
123 ) -> Result<ProjectInfo> {
124 let project_id = Uuid::parse_str(id).context("Invalid project ID")?;
125 let paths = paths.map(|v| v.into_iter().map(PathBuf::from).collect());
126
127 let mut project = self.project_manager.update_project(
128 project_id,
129 name,
130 paths,
131 tags,
132 emoji,
133 description,
134 )?;
135
136 if let Some(visible) = memory_visible {
138 project.memory_visible = visible;
139 project.updated_at = Utc::now();
140 self.project_manager.save_project(&project)?;
141 }
142
143 Ok(ProjectInfo::from(&project))
144 }
145
146 pub fn remove_project(&self, id: &str) -> Result<()> {
148 let project_id = Uuid::parse_str(id).context("Invalid project ID")?;
149 self.project_manager.remove_project(project_id)
150 }
151
152 pub fn link_memory(&self, project_id: &str, memory_id: &str) -> Result<()> {
154 let pid = Uuid::parse_str(project_id).context("Invalid project ID")?;
155 self.project_manager.link_memory(pid, memory_id)
156 }
157
158 pub fn unlink_memory(&self, project_id: &str, memory_id: &str) -> Result<()> {
160 let pid = Uuid::parse_str(project_id).context("Invalid project ID")?;
161 self.project_manager.unlink_memory(pid, memory_id)
162 }
163
164 pub fn get_project_memory_ids(&self, project_id: &str) -> Result<Vec<String>> {
166 let pid = Uuid::parse_str(project_id).context("Invalid project ID")?;
167 self.project_manager.get_project_memory_ids(pid)
168 }
169}