From 3bbd2023a423eb9ad199cbe95daa8013054a7ffa Mon Sep 17 00:00:00 2001
From: Andrey Antukh <niwi@niwi.nz>
Date: Fri, 19 Jan 2024 15:51:52 +0100
Subject: [PATCH] :bug: Fix incorrect validation of shape geom attrs

Requied validation in a subset of supported shapes
---
 common/src/app/common/files/validate.cljc |  3 +
 common/src/app/common/types/shape.cljc    | 82 +++++++++++++----------
 2 files changed, 51 insertions(+), 34 deletions(-)

diff --git a/common/src/app/common/files/validate.cljc b/common/src/app/common/files/validate.cljc
index 1e62d14ec..ca4d471cb 100644
--- a/common/src/app/common/files/validate.cljc
+++ b/common/src/app/common/files/validate.cljc
@@ -483,6 +483,9 @@
   (sm/lazy-explainer ::ctf/data))
 
 (defn validate-file-schema!
+  "Validates the file itself, without external dependencies, it
+  performs the schema checking and some semantical validation of the
+  content."
   [{:keys [id data] :as file}]
   (when-not (valid-fdata? data)
     (ex/raise :type :validation
diff --git a/common/src/app/common/types/shape.cljc b/common/src/app/common/types/shape.cljc
index 4f347e9ff..6187a7aa7 100644
--- a/common/src/app/common/types/shape.cljc
+++ b/common/src/app/common/types/shape.cljc
@@ -127,21 +127,24 @@
    [:stroke-color-gradient {:optional true} ::ctc/gradient]
    [:stroke-image {:optional true} ::ctc/image-color]])
 
-(sm/define! ::minimal-shape-attrs
+(sm/define! ::shape-base-attrs
   [:map {:title "ShapeMinimalRecord"}
-   [:id {:optional false} ::sm/uuid]
-   [:name {:optional false} :string]
-   [:type {:optional false} [::sm/one-of shape-types]]
-   [:x {:optional false} [:maybe ::sm/safe-number]]
-   [:y {:optional false} [:maybe ::sm/safe-number]]
-   [:width {:optional false} [:maybe ::sm/safe-number]]
-   [:height {:optional false} [:maybe ::sm/safe-number]]
-   [:selrect {:optional false} ::selrect]
-   [:points {:optional false} ::points]
-   [:transform {:optional false} ::gmt/matrix]
-   [:transform-inverse {:optional false} ::gmt/matrix]
-   [:parent-id {:optional false} ::sm/uuid]
-   [:frame-id {:optional false} ::sm/uuid]])
+   [:id ::sm/uuid]
+   [:name :string]
+   [:type [::sm/one-of shape-types]]
+   [:selrect ::selrect]
+   [:points ::points]
+   [:transform ::gmt/matrix]
+   [:transform-inverse ::gmt/matrix]
+   [:parent-id ::sm/uuid]
+   [:frame-id ::sm/uuid]])
+
+(sm/define! ::shape-geom-attrs
+  [:map {:title "ShapeGeometryAttrs"}
+   [:x ::sm/safe-number]
+   [:y ::sm/safe-number]
+   [:width ::sm/safe-number]
+   [:height ::sm/safe-number]])
 
 (sm/define! ::shape-attrs
   [:map {:title "ShapeAttrs"}
@@ -273,84 +276,95 @@
   [:multi {:dispatch :type :title "Shape"}
    [:group
     [:and {:title "GroupShape"}
+     ::shape-base-attrs
+     ::shape-geom-attrs
      ::shape-attrs
-     ::minimal-shape-attrs
      ::group-attrs
      ::ctsl/layout-child-attrs]]
 
    [:frame
     [:and {:title "FrameShape"}
-     ::minimal-shape-attrs
+     ::shape-base-attrs
+     ::shape-geom-attrs
      ::frame-attrs
      ::ctsl/layout-attrs
      ::ctsl/layout-child-attrs]]
 
    [:bool
     [:and {:title "BoolShape"}
+     ::shape-base-attrs
      ::shape-attrs
-     ::minimal-shape-attrs
      ::bool-attrs
      ::ctsl/layout-child-attrs]]
 
    [:rect
     [:and {:title "RectShape"}
+     ::shape-base-attrs
+     ::shape-geom-attrs
      ::shape-attrs
-     ::minimal-shape-attrs
      ::rect-attrs
      ::ctsl/layout-child-attrs]]
 
    [:circle
     [:and {:title "CircleShape"}
+     ::shape-base-attrs
+     ::shape-geom-attrs
      ::shape-attrs
-     ::minimal-shape-attrs
      ::circle-attrs
      ::ctsl/layout-child-attrs]]
 
    [:image
     [:and {:title "ImageShape"}
+     ::shape-base-attrs
+     ::shape-geom-attrs
      ::shape-attrs
-     ::minimal-shape-attrs
      ::image-attrs
      ::ctsl/layout-child-attrs]]
 
    [:svg-raw
     [:and {:title "SvgRawShape"}
+     ::shape-base-attrs
+     ::shape-geom-attrs
      ::shape-attrs
-     ::minimal-shape-attrs
      ::svg-raw-attrs
      ::ctsl/layout-child-attrs]]
 
    [:path
     [:and {:title "PathShape"}
+     ::shape-base-attrs
      ::shape-attrs
-     ::minimal-shape-attrs
      ::path-attrs
      ::ctsl/layout-child-attrs]]
 
    [:text
     [:and {:title "TextShape"}
+     ::shape-base-attrs
+     ::shape-geom-attrs
      ::shape-attrs
-     ::minimal-shape-attrs
      ::text-attrs
      ::ctsl/layout-child-attrs]]])
 
 (sm/define! ::shape
   [:and
    {:title "Shape"
-    :gen/gen (->> (sg/generator ::minimal-shape-attrs)
+    :gen/gen (->> (sg/generator ::shape-base-attrs)
                   (sg/mcat (fn [{:keys [type] :as shape}]
                              (sg/let [attrs1 (sg/generator ::shape-attrs)
-                                      attrs2 (case type
-                                               :text (sg/generator ::text-attrs)
-                                               :path (sg/generator ::path-attrs)
+                                      attrs2 (sg/generator ::shape-geom-attrs)
+                                      attrs3 (case type
+                                               :text    (sg/generator ::text-attrs)
+                                               :path    (sg/generator ::path-attrs)
                                                :svg-raw (sg/generator ::svg-raw-attrs)
-                                               :image (sg/generator ::image-attrs)
-                                               :circle (sg/generator ::circle-attrs)
-                                               :rect (sg/generator ::rect-attrs)
-                                               :bool (sg/generator ::bool-attrs)
-                                               :group (sg/generator ::group-attrs)
-                                               :frame (sg/generator ::frame-attrs))]
-                               (merge attrs1 shape attrs2))))
+                                               :image   (sg/generator ::image-attrs)
+                                               :circle  (sg/generator ::circle-attrs)
+                                               :rect    (sg/generator ::rect-attrs)
+                                               :bool    (sg/generator ::bool-attrs)
+                                               :group   (sg/generator ::group-attrs)
+                                               :frame   (sg/generator ::frame-attrs))]
+                               (if (or (= type :path)
+                                       (= type :bool))
+                                 (merge attrs1 shape attrs3)
+                                 (merge attrs1 shape attrs2 attrs3)))))
                   (sg/fmap map->Shape))}
    ::shape-map
    [:fn shape?]])