]> uap-core.de Git - note.git/commitdiff
add backend function for adding new note attachments
authorOlaf Wintermann <olaf.wintermann@gmail.com>
Sat, 22 Aug 2026 20:53:52 +0000 (22:53 +0200)
committerOlaf Wintermann <olaf.wintermann@gmail.com>
Sat, 22 Aug 2026 20:53:52 +0000 (22:53 +0200)
application/backend/src/backend.rs

index 9685d1b394b2434479b7d2026cb2ffbe12cd1e5b..e6add72320b352366a52e636bc2202194a1c631a 100644 (file)
@@ -31,18 +31,19 @@ use std::future::Future;
 use std::io::{Error, ErrorKind};
 use std::path::{Path, PathBuf};
 use std::pin::Pin;
-use sea_orm::{ActiveModelTrait, Database, DatabaseConnection, EntityTrait, QueryFilter, ColumnTrait, Set, QueryOrder, DbErr, ExprTrait, QuerySelect};
+use sea_orm::{ActiveModelTrait, Database, DatabaseConnection, EntityTrait, QueryFilter, ColumnTrait, Set, QueryOrder, DbErr, ExprTrait, QuerySelect, NotSet};
 use tokio::runtime::Runtime;
 use std::sync::{Arc};
 use std::thread::JoinHandle;
 use std::time::SystemTime;
 use notify::Event;
+use sea_orm::prelude::DateTimeWithTimeZone;
 use tokio::fs;
 use tokio::sync::{broadcast, mpsc};
 use tokio::sync::broadcast::error::SendError;
 use migration::{Expr, Migrator, MigratorTrait};
 
-use entity::{attachment, collection, filecontent, note, notecontent, profile, repository};
+use entity::{attachment, attachmentcontent, collection, filecontent, note, notecontent, profile, repository};
 use entity::profile::Entity as Profile;
 use entity::collection::{create_notebook_hierarchy, CollectionType, Entity as Collection, Node};
 use entity::note::{Column, Entity as Note, NoteType};
@@ -899,6 +900,52 @@ impl BackendHandle {
         let _ = self.tx.send(cmd);
     }
 
+    pub fn add_note_attachment<F>(&self, note_id: i32, path: &Path, callback: F)
+    where F: FnOnce(Result<(attachment::Model, attachmentcontent::Model), DbErr>) + Send + 'static {
+        let backend = self.backend.clone();
+        let pathbuf = path.to_path_buf();
+        let name = pathbuf.file_name();
+        let Some(name) = pathbuf.file_name() else {
+            callback(Err(DbErr::Custom("invalid path".to_string())));
+            return;
+        };
+        let file_name = name.to_string_lossy().to_string();
+        let cmd = Box::pin(async move {
+            let result = async {
+                let collection_id = note::Entity::find_by_id(note_id)
+                    .select_only()
+                    .column(note::Column::CollectionId)
+                    .into_tuple::<i32>()
+                    .one(&backend.db).await?.ok_or(DbErr::Custom("note not found".to_string()))?;
+
+                let now: DateTimeWithTimeZone = Utc::now().into();
+                let new_attachment = attachment::ActiveModel {
+                    attachment_id: Default::default(),
+                    note_id: Set(note_id),
+                    collection_id: Set(collection_id),
+                    nodename: Set(file_name.clone()),
+                    title: Set(file_name.clone()),
+                    content_type: Set(nodename_to_contenttype(file_name.as_str()).to_string()),
+                    lastmodified: Set(now.clone()),
+                    created: Set(now),
+                };
+                let attachment = new_attachment.insert(&backend.db).await?;
+
+                let content = fs::read(pathbuf).await.map_err(|e| DbErr::Custom(e.to_string()))?;
+                let new_attachment_content = attachmentcontent::ActiveModel {
+                    id: Default::default(),
+                    attachment_id: Set(attachment.attachment_id),
+                    content: Set(content)
+                };
+                let attachment_content = new_attachment_content.insert(&backend.db).await?;
+
+                Ok((attachment, attachment_content))
+            }.await;
+            callback(result);
+        });
+        let _ = self.tx.send(cmd);
+    }
+
     pub fn open_extern<F>(&self, note_id: i32, callback: F)
     where F: FnOnce(OpenExternResult) + Send + 'static {
         let backend = self.backend.clone();