use entity::notecontent::{Entity as NoteContent};
use migration::prelude::Utc;
use crate::lockmanager::LockManager;
+use crate::note::{create_nodename, randomize_nodename};
use crate::storage::{get_collection_storage_path, get_note_storage_path, write_file};
pub struct Backend {
callback(SaveNoteResult::ValidationError("title not set"));
return;
};
+ let Set(kind) = ¬e.kind else {
+ callback(SaveNoteResult::ValidationError("note type not set"));
+ return;
+ };
let mut nodename = if let Set(nn) = ¬e.nodename {
nn.clone()
} else {
// generate nodename from title
- title.clone()
+ let nodename = create_nodename(title, kind);
+ note.nodename = Set(nodename.clone());
+ nodename
};
let bhandle = self.clone();
// collection+name unique constraint.
// Generate a random suffix and try it again
- let suffix: String = rand::rng()
- .sample_iter(Alphanumeric)
- .take(6)
- .map(char::from)
- .collect();
- let new_nodename = nodename + "-" + suffix.as_str();
+ let new_nodename = randomize_nodename(nodename.as_str());
note.nodename = Set(new_nodename.clone());
nodename = new_nodename;
let result = note.clone().insert(&bhandle.backend.db).await;
pub mod backend;
pub mod lockmanager;
-pub mod storage;
\ No newline at end of file
+pub mod storage;
+mod note;
\ No newline at end of file
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
+
use std::collections::{HashSet};
use std::sync::Arc;
--- /dev/null
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2026 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+use std::path::Path;
+use rand::distr::Alphanumeric;
+use rand::RngExt;
+use entity::note::NoteType;
+
+pub fn notetype2ext(t: &NoteType) -> &'static str {
+ match t {
+ NoteType::PlainTextNote => { ".txt" }
+ NoteType::MDTextNote => { ".md" }
+ }
+}
+
+pub fn create_nodename(title: &str, kind: &NoteType) -> String {
+ format!("{}{}", title, notetype2ext(kind))
+}
+
+pub fn randomize_nodename(nodename: &str) -> String {
+ let suffix: String = rand::rng()
+ .sample_iter(Alphanumeric)
+ .take(6)
+ .map(char::from)
+ .collect();
+
+ let path = Path::new(nodename);
+ let stem = path
+ .file_stem()
+ .and_then(|s| s.to_str())
+ .unwrap_or(nodename);
+
+ match path.extension().and_then(|e| e.to_str()) {
+ Some(ext) => format!("{stem}-{suffix}.{ext}"),
+ None => format!("{stem}_{suffix}"),
+ }
+}
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2026 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
use std::io::ErrorKind;
use std::path::Path;
use sea_orm::{DatabaseConnection, DbErr, EntityTrait, QuerySelect, RelationTrait};