diff --git a/common/src/app/common/files/migrations.cljc b/common/src/app/common/files/migrations.cljc index dbe0b0abd7..adc25e6cf6 100644 --- a/common/src/app/common/files/migrations.cljc +++ b/common/src/app/common/files/migrations.cljc @@ -223,8 +223,10 @@ [data _] (letfn [(fix-line-paths [shape] (if (= (:type shape) :path) - (let [{:keys [width height]} (grc/points->rect (:points shape))] - (if (or (mth/almost-zero? width) (mth/almost-zero? height)) + ;; A path with missing or empty points has no rect; rebuild + ;; its geometry from the content as for line-like paths. + (let [{:keys [width height] :as rect} (grc/points->rect (:points shape))] + (if (or (nil? rect) (mth/almost-zero? width) (mth/almost-zero? height)) (let [selrect (path.segment/content->selrect (:content shape)) points (grc/rect->points selrect) transform (gmt/matrix) diff --git a/common/test/common_tests/files_migrations_test.cljc b/common/test/common_tests/files_migrations_test.cljc index 0ac8084708..b76f4f369c 100644 --- a/common/test/common_tests/files_migrations_test.cljc +++ b/common/test/common_tests/files_migrations_test.cljc @@ -605,3 +605,45 @@ data' (cfm/migrate-data data migration-id)] (t/is (= [child-id] (get-in data' [:components component-id :objects main-id :shapes]))))) + +(defn- make-path-shape + [shape-id] + (cts/setup-shape {:id shape-id + :type :path + :content [{:command :move-to :params {:x 10 :y 20}} + {:command :line-to :params {:x 110 :y 70}}]})) + +(t/deftest migration-legacy-6-repairs-paths-without-points + (let [migration-id "legacy-6" + page-id (uuid/next) + shape-id (uuid/next) + shape (make-path-shape shape-id)] + + (doseq [points [nil []]] + (let [data {:pages-index {page-id {:objects {shape-id (assoc shape :points points)}}}} + data' (cfm/migrate-data data migration-id) + shape' (get-in data' [:pages-index page-id :objects shape-id])] + + (t/is (= (:points shape) (:points shape')) + (str "points rebuilt from content when they were " (pr-str points))) + (t/is (= (:selrect shape) (:selrect shape')) + "selrect rebuilt from content"))))) + +(t/deftest migration-legacy-6-runs-through-file-migration + ;; A file saved before version 6 runs every migration from legacy-6 on, + ;; and the whole chain must succeed for the file to load. + (let [migration-id "legacy-6" + shape-id (uuid/next) + file (ctf/make-file {:name "Legacy path without points"}) + page-id (first (get-in file [:data :pages])) + shape (-> (make-path-shape shape-id) + (assoc :points [])) + file (-> file + (dissoc :migrations) + (assoc :version 5) + (assoc-in [:data :pages-index page-id :objects shape-id] shape)) + file' (cfm/migrate-file file (delay {}))] + + (t/is (contains? (:migrations file') migration-id) "migration id persisted") + (t/is (= 4 (count (get-in file' [:data :pages-index page-id :objects shape-id :points]))) + "path points repaired before schema validation")))