fix: revert disallowed built-in block updates

1. built-in pages (non-classes) shouldn't be used as tags
2. some protected properties for built-in nodes shouldn't be updated,
e.g. db/ident, block/title, block/name, logseq.property/type
This commit is contained in:
Tienson Qin
2025-11-04 21:49:26 +08:00
parent 79f670f799
commit e4e8388588
8 changed files with 97 additions and 32 deletions

View File

@@ -327,11 +327,6 @@
(:block/title m*)
(not= (:block/title m*) (:block/title block-entity)))
(outliner-validate/validate-block-title db (:block/title m*) block-entity))
_ (when (and db-based? (seq (:block/tags m*)))
;; Add built-in? b/c it's not available here
(doseq [tag (map #(assoc % :logseq.property/built-in?
(contains? sqlite-create-graph/built-in-pages-names (:block/title %))) (:block/tags m*))]
(outliner-validate/validate-built-in-pages tag {:message "Built-in page can't be a tag"})))
m (cond-> m*
db-based?
(dissoc :block/format :block/pre-block? :block/priority :block/marker :block/properties-order))]

View File

@@ -39,15 +39,6 @@
(def ^:api uneditable-page? ldb/built-in?)
(defn ^:api validate-built-in-pages
"Validates built-in pages shouldn't be modified"
[entity & {:keys [message]}]
(when (uneditable-page? entity)
(throw (ex-info "Rename built-in pages"
{:type :notification
:payload {:message (or message "Built-in pages can't be edited")
:type :warning}}))))
(defn- find-other-ids-with-title-and-tags
"Query that finds other ids given the id to ignore, title to look up and tags to consider"
[entity]
@@ -138,7 +129,6 @@
(defn validate-block-title
"Validates a block title when it has changed for a entity-util/page? or tagged node"
[db new-title existing-block-entity]
(validate-built-in-pages existing-block-entity)
(validate-unique-by-name-and-tags db new-title existing-block-entity)
(validate-disallow-page-with-journal-name new-title existing-block-entity))

View File

@@ -161,11 +161,13 @@
result (if db-tag?
(let [classes (editor-handler/get-matched-classes q)]
(if (and (ldb/internal-page? block)
(= (:block/title block) q))
(cons {:block/title (util/format "Convert \"%s\" to tag" q)
(= (:block/title block) q)
(not (ldb/built-in? block)))
(cons {:block/title q
:db/id (:db/id block)
:block/uuid (:block/uuid block)
:convert-page-to-tag? true} classes)
:convert-page-to-tag? true
:friendly-title (util/format "Convert \"%s\" to tag" q)} classes)
classes))
(editor-handler/<get-matched-blocks q {:nlp-pages? true
:page-only? (not db-based?)}))]
@@ -203,7 +205,7 @@
(let [block' (if-let [id (:block/uuid block)]
(if-let [e (db/entity [:block/uuid id])]
(assoc e
:block/title (or (:block/title e) (:block/title block))
:block/title (or (:friendly-title block) (:block/title e) (:block/title block))
:alias (:alias block))
block)
block)]

View File

@@ -50,7 +50,7 @@
(:block/parent page-entity)
(notification/show! "Namespaced pages can't be tags" :error false)
(outliner-validate/uneditable-page? page-entity)
(notification/show! "Built-in pages can't be edited" :error)
(notification/show! "Built-in pages can't be used as tags" :error)
:else
(let [txs [(db-class/build-new-class (db/get-db)
{:db/id (:db/id page-entity)
@@ -65,7 +65,7 @@
(cond (db/page-exists? (:block/title entity) #{:logseq.class/Page})
(notification/show! (str "A page with the name \"" (:block/title entity) "\" already exists.") :warning false)
(outliner-validate/uneditable-page? entity)
(notification/show! "Built-in tags can't be edited" :error)
(notification/show! "Built-in tags can't be converted to pages" :error)
:else
(if (seq (:logseq.property.class/_extends entity))
(notification/show! "This tag cannot be converted because it has tag children. All tag children must be removed or converted before converting this tag." :error false)

View File

@@ -3630,13 +3630,10 @@
(save-current-block!) ;; Save the input contents before collapsing
(ui-outliner-tx/transact! ;; Save the new collapsed state as an undo transaction (if it changed)
{:outliner-op :collapse-expand-blocks}
(doseq [block-id block-ids]
(when-let [block (db/entity [:block/uuid block-id])]
(let [current-value (boolean (:block/collapsed? block))]
(when-not (= current-value value)
(let [block {:block/uuid block-id
:block/collapsed? value}]
(outliner-save-block! block {:outliner-op :collapse-expand-blocks})))))))
(let [tx-data (map (fn [block-id]
{:block/uuid block-id
:block/collapsed? value}) block-ids)]
(outliner-op/transact! tx-data {})))
(doseq [block-id block-ids]
(state/set-collapsed-block! block-id value)))))

View File

@@ -510,8 +510,6 @@
r (d/transact! conn data' {:fix-db? true
:db-migrate? true})]
(when (seq (:tx-data r))
(prn :debug :ensure-built-in-data-exists? :tx-data (:tx-data r)))
(assoc r :migrate-updates
;; fake it as a normal :fix type migration
{:fix (constantly :ensure-built-in-data-exists!)})))

View File

@@ -15,6 +15,7 @@
[logseq.db.common.order :as db-order]
[logseq.db.common.sqlite :as common-sqlite]
[logseq.db.frontend.class :as db-class]
[logseq.db.sqlite.create-graph :as sqlite-create-graph]
[logseq.db.sqlite.export :as sqlite-export]
[logseq.graph-parser.exporter :as gp-exporter]
[logseq.outliner.core :as outliner-core]
@@ -86,6 +87,7 @@
(:block/uuid e)))))))]
blocks))))]
(when (seq template-blocks)
;; FIXME: outliner core apis shouldn't use `repo`
(let [result (outliner-core/insert-blocks
repo db template-blocks object
{:sibling? false
@@ -323,10 +325,49 @@
(cond->> add-created-by-tx-data
(nil? created-by-ent) (cons created-by-block))))))
(defn- revert-disallowed-changes
[{:keys [tx-meta tx-data db-before db-after]}]
(when-not (rtc-tx-or-download-graph? tx-meta)
(let [built-in-page? (fn [id]
(let [block (d/entity db-after id)]
(and (contains? sqlite-create-graph/built-in-pages-names
(:block/title block))
(ldb/built-in? block))))
tx-data' (mapcat
(fn [[e a v _t added]]
(when added
(cond
;; using built-in pages as tags
(and (= a :block/tags) (built-in-page? v))
[[:db/retract v :db/ident]
[:db/retract v :logseq.property.class/extends]
[:db/retract v :block/tags :logseq.class/Tag]
[:db/add v :block/tags :logseq.class/Page]
[:db/retract e a v]]
;; built-in block protected properties updated
(and (contains? #{:db/ident :block/title :block/name :logseq.property/type
:logseq.property/built-in? :logseq.property.class/extends} a)
(some? (d/entity db-before e))
(let [block (d/entity db-after e)]
(and (ldb/built-in? block)
(not= (get block a) (get (d/entity db-before e) a)))))
(if-some [prev-v (get (d/entity db-before e) a)]
[[:db/add e a prev-v]]
[[:db/retract e a v]])
:else
nil)))
tx-data)]
(when (seq tx-data')
(prn :debug ::revert-built-in-block-updates :tx-data (distinct tx-data')))
(distinct tx-data'))))
(defn- compute-extra-tx-data
[repo tx-report]
(let [{:keys [db-before db-after tx-data tx-meta]} tx-report
db db-after
revert-tx-data (revert-disallowed-changes tx-report)
fix-page-tags-tx-data (fix-page-tags tx-report)
fix-inline-page-tx-data (fix-inline-built-in-page-classes tx-report)
toggle-page-and-block-tx-data (when (empty? fix-inline-page-tx-data)
@@ -337,7 +378,8 @@
insert-templates-tx (when-not (rtc-tx-or-download-graph? tx-meta)
(insert-tag-templates repo tx-report))
created-by-tx (add-created-by-ref-hook db-before db-after tx-data tx-meta)]
(concat toggle-page-and-block-tx-data
(concat revert-tx-data
toggle-page-and-block-tx-data
display-blocks-tx-data
commands-tx
insert-templates-tx

View File

@@ -1,6 +1,10 @@
(ns frontend.worker.pipeline-test
(:require [cljs.test :refer [deftest is testing]]
[frontend.worker.pipeline :as worker-pipeline]))
[datascript.core :as d]
[frontend.test.helper :as test-helper]
[frontend.worker.pipeline :as worker-pipeline]
[logseq.db :as ldb]
[logseq.db.test.helper :as db-test]))
(deftest remove-conflict-datoms-test
(testing "remove-conflict-datoms (1)"
@@ -36,3 +40,40 @@
[177 :block/refs 136 536871082 true]
[177 :block/refs 21 536871082 true]])
(set (#'worker-pipeline/remove-conflict-datoms datoms)))))))
(deftest test-built-in-page-updates-that-should-be-reverted
(let [graph test-helper/test-db-name-db-version
conn (db-test/create-conn-with-blocks
[{:page {:block/title "page1"}
:blocks [{:block/title "b1"}]}])
library (ldb/get-built-in-page @conn "Library")]
(ldb/register-transact-pipeline-fn!
(fn [tx-report]
(worker-pipeline/transact-pipeline graph tx-report)))
(testing "Using built-in pages as tags"
(let [page-1 (ldb/get-page @conn "page1")
b1 (first (:block/_page page-1))]
(ldb/transact! conn [{:db/id (:db/id b1)
:block/title "b1 #Library"
:block/tags [library]}])
(is (not (ldb/class? library)))
(is (empty? (:block/tags (d/entity @conn (:db/id b1)))))))
(testing "Updating protected properties for built-in nodes"
(ldb/transact! conn [{:db/id (:db/id library)
:block/title "newlibrary"
:db/ident :test/ident}])
(let [library (ldb/get-built-in-page @conn "Library")]
(is (nil? (:db/ident library)))
(is (= "Library" (:block/title library))))
(let [task (d/entity @conn :logseq.class/Task)]
(ldb/transact! conn [{:db/id (:db/id task)
:db/ident :logseq.class/task-new-ident
:block/title "task"}])
(let [task (d/entity @conn (:db/id task))]
(is (= :logseq.class/Task (:db/ident task)))
(is (= "Task" (:block/title task))))))))