diff --git a/README.md b/README.md index 13dfd2b..96317b6 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ The project is under active development. Core blogging workflows are broadly ava - Post and translation authoring with change-aware draft/published/archive lifecycle, file-backed change discard, canonical draft reopening after manual translation edits, non-disruptive automatic translation, desktop archive/unarchive actions, in-place published-frontmatter updates, metadata, tags, categories, live link/backlink graphs, media, and batch gallery-image import. - Media import, thumbnails, metadata translations, filters, validation, post assignment, and sequential drag-and-drop insertion into post editors. - WordPress WXR migration with saved analyses, HTML-to-Markdown and shortcode conversion, conflict/taxonomy review, recoverable 500-item execution batches, media-parent linking, progress reporting, and optional AI-assisted taxonomy mapping. -- Post, Liquid template, and Lua script editing with dedicated syntax highlighting and explicit syntax-check feedback, including publish-time enforcement of the bDS2 Liquid tag/filter/operator subset, using a custom Ropey/Syntect/Cosmic Text editor and the documented, bDS2-signature-compatible project-scoped [`bds` host API](docs/scripting/API_REFERENCE.md) across utilities, rendered macros, and Blogmark transforms, including airplane-gated Git sync. +- Post, Liquid template, and Lua script editing with dedicated syntax highlighting, explicit syntax-check feedback, reference-safe template slug changes, and publish-time enforcement of the bDS2 Liquid tag/filter/operator subset, using a custom Ropey/Syntect/Cosmic Text editor and the documented, bDS2-signature-compatible project-scoped [`bds` host API](docs/scripting/API_REFERENCE.md) across utilities, rendered macros, and Blogmark transforms, including airplane-gated Git sync. - SQLite and filesystem persistence with frontmatter, relationship-safe media sidecars, rebuild, metadata diff/repair, stale post-path cleanup on republish, bDS2-compatible checksums and NFD slug generation, and FTS5 search. - Optional on-device multilingual semantic search and similar-post tag suggestions backed by a persistent USearch index, plus always-available partial-name tag autocomplete and duplicate-post review in the desktop workspace. - Read-only in-app browsers in the Help menu for the bundled global `DOCUMENTATION.md`, the generated Lua API reference with public types and runnable examples, the [CLI/server/TUI documentation](CLI.md), and the [MCP server documentation](MCP.md), with safe GFM rendering and confirmed external links. diff --git a/crates/bds-core/src/db/connection.rs b/crates/bds-core/src/db/connection.rs index 90a583a..ff1c1c8 100644 --- a/crates/bds-core/src/db/connection.rs +++ b/crates/bds-core/src/db/connection.rs @@ -53,6 +53,15 @@ impl DbConnection { .batch_execute("ROLLBACK TO bds_operation; RELEASE bds_operation") } + #[cfg(test)] + pub(crate) fn reject_tag_template_updates_for_test(&self) -> diesel::QueryResult<()> { + self.0.borrow_mut().batch_execute( + "CREATE TRIGGER reject_template_tag_cascade \ + BEFORE UPDATE OF post_template_slug ON tags \ + BEGIN SELECT RAISE(ABORT, 'reject cascade'); END", + ) + } + /// Filesystem database path for sibling surfaces that must open their own /// short-lived connection (gallery workers, preview servers, Lua hosts). pub fn database_path(&self) -> diesel::QueryResult { diff --git a/crates/bds-core/src/engine/template.rs b/crates/bds-core/src/engine/template.rs index 436034f..09c6fb2 100644 --- a/crates/bds-core/src/engine/template.rs +++ b/crates/bds-core/src/engine/template.rs @@ -8,7 +8,9 @@ use uuid::Uuid; use crate::db::queries::template as qt; use crate::engine::{EngineError, EngineResult, domain_events}; -use crate::model::{DomainEntity, NotificationAction, Template, TemplateKind, TemplateStatus}; +use crate::model::{ + DomainEntity, NotificationAction, Post, Tag, Template, TemplateKind, TemplateStatus, +}; use crate::util::frontmatter::{TemplateFrontmatter, write_template_file}; use crate::util::{atomic_write_str, ensure_unique, now_unix_ms, slugify}; @@ -73,6 +75,7 @@ pub fn create_template( )] pub fn update_template( conn: &Connection, + data_dir: &Path, template_id: &str, project_id: &str, title: Option<&str>, @@ -82,6 +85,10 @@ pub fn update_template( content: Option<&str>, ) -> EngineResult