mirror of
https://github.com/penpot/penpot.git
synced 2025-07-26 03:27:20 +02:00
Merge pull request #6345 from penpot/niwinz-staging-add-interaction-cleaning
🐛 Add migration for decoding and cleaning shape interactions
This commit is contained in:
commit
f155042958
12 changed files with 129 additions and 46 deletions
44
backend/src/app/binfile/cleaner.clj
Normal file
44
backend/src/app/binfile/cleaner.clj
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
;;
|
||||||
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
|
(ns app.binfile.cleaner
|
||||||
|
"A collection of helpers for perform cleaning of artifacts; mainly
|
||||||
|
for recently imported shapes."
|
||||||
|
(:require
|
||||||
|
[app.common.data :as d]
|
||||||
|
[app.common.uuid :as uuid]))
|
||||||
|
|
||||||
|
(defn- fix-shape-shadow-color
|
||||||
|
"Some shapes can come with invalid `id` property on shadow colors
|
||||||
|
caused by incorrect uuid parsing bug that should be already fixed;
|
||||||
|
this function removes the invalid id from the data structure."
|
||||||
|
[shape]
|
||||||
|
(let [fix-color
|
||||||
|
(fn [{:keys [id] :as color}]
|
||||||
|
(if (uuid? id)
|
||||||
|
color
|
||||||
|
(if (and (string? id)
|
||||||
|
(re-matches uuid/regex id))
|
||||||
|
(assoc color :id (uuid/uuid id))
|
||||||
|
(dissoc color :id))))
|
||||||
|
|
||||||
|
fix-shadow
|
||||||
|
(fn [shadow]
|
||||||
|
(d/update-when shadow :color fix-color))
|
||||||
|
|
||||||
|
xform
|
||||||
|
(map fix-shadow)]
|
||||||
|
|
||||||
|
(d/update-when shape :shadow
|
||||||
|
(fn [shadows]
|
||||||
|
(into [] xform shadows)))))
|
||||||
|
|
||||||
|
(defn clean-shape-post-decode
|
||||||
|
"A shape procesor that expected to be executed after schema decoding
|
||||||
|
process but before validation."
|
||||||
|
[shape]
|
||||||
|
(-> shape
|
||||||
|
(fix-shape-shadow-color)))
|
|
@ -8,6 +8,7 @@
|
||||||
"A ZIP based binary file exportation"
|
"A ZIP based binary file exportation"
|
||||||
(:refer-clojure :exclude [read])
|
(:refer-clojure :exclude [read])
|
||||||
(:require
|
(:require
|
||||||
|
[app.binfile.cleaner :as bfl]
|
||||||
[app.binfile.common :as bfc]
|
[app.binfile.common :as bfc]
|
||||||
[app.binfile.migrations :as bfm]
|
[app.binfile.migrations :as bfm]
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
|
@ -594,16 +595,25 @@
|
||||||
|
|
||||||
(defn- read-file-components
|
(defn- read-file-components
|
||||||
[{:keys [::bfc/input ::file-id ::entries]}]
|
[{:keys [::bfc/input ::file-id ::entries]}]
|
||||||
|
(let [clean-component-post-decode
|
||||||
|
(fn [component]
|
||||||
|
(d/update-when component :objects
|
||||||
|
(fn [objects]
|
||||||
|
(reduce-kv (fn [objects id shape]
|
||||||
|
(assoc objects id (bfl/clean-shape-post-decode shape)))
|
||||||
|
objects
|
||||||
|
objects))))]
|
||||||
(->> (keep (match-component-entry-fn file-id) entries)
|
(->> (keep (match-component-entry-fn file-id) entries)
|
||||||
(reduce (fn [result {:keys [id entry]}]
|
(reduce (fn [result {:keys [id entry]}]
|
||||||
(let [object (->> (read-entry input entry)
|
(let [object (->> (read-entry input entry)
|
||||||
(decode-component)
|
(decode-component)
|
||||||
|
(clean-component-post-decode)
|
||||||
(validate-component))]
|
(validate-component))]
|
||||||
(if (= id (:id object))
|
(if (= id (:id object))
|
||||||
(assoc result id object)
|
(assoc result id object)
|
||||||
result)))
|
result)))
|
||||||
{})
|
{})
|
||||||
(not-empty)))
|
(not-empty))))
|
||||||
|
|
||||||
(defn- read-file-typographies
|
(defn- read-file-typographies
|
||||||
[{:keys [::bfc/input ::file-id ::entries]}]
|
[{:keys [::bfc/input ::file-id ::entries]}]
|
||||||
|
@ -631,7 +641,9 @@
|
||||||
(reduce (fn [result {:keys [id entry]}]
|
(reduce (fn [result {:keys [id entry]}]
|
||||||
(let [object (->> (read-entry input entry)
|
(let [object (->> (read-entry input entry)
|
||||||
(decode-shape)
|
(decode-shape)
|
||||||
|
(bfl/clean-shape-post-decode)
|
||||||
(validate-shape))]
|
(validate-shape))]
|
||||||
|
|
||||||
(if (= id (:id object))
|
(if (= id (:id object))
|
||||||
(assoc result id object)
|
(assoc result id object)
|
||||||
result)))
|
result)))
|
||||||
|
|
|
@ -238,6 +238,7 @@
|
||||||
(db/update! conn :file
|
(db/update! conn :file
|
||||||
{:data (blob/encode (:data file))
|
{:data (blob/encode (:data file))
|
||||||
:version (:version file)
|
:version (:version file)
|
||||||
|
:modified-at (dt/now)
|
||||||
:features (db/create-array conn "text" (:features file))}
|
:features (db/create-array conn "text" (:features file))}
|
||||||
{:id id})
|
{:id id})
|
||||||
|
|
||||||
|
|
|
@ -180,8 +180,7 @@
|
||||||
(def ^:private
|
(def ^:private
|
||||||
schema:get-file-data-for-thumbnail
|
schema:get-file-data-for-thumbnail
|
||||||
[:map {:title "get-file-data-for-thumbnail"}
|
[:map {:title "get-file-data-for-thumbnail"}
|
||||||
[:file-id ::sm/uuid]
|
[:file-id ::sm/uuid]])
|
||||||
[:features {:optional true} ::cfeat/features]])
|
|
||||||
|
|
||||||
(def ^:private
|
(def ^:private
|
||||||
schema:partial-file
|
schema:partial-file
|
||||||
|
@ -211,7 +210,6 @@
|
||||||
(fmg/migrate-file)))]
|
(fmg/migrate-file)))]
|
||||||
|
|
||||||
(-> (cfeat/get-team-enabled-features cf/flags team)
|
(-> (cfeat/get-team-enabled-features cf/flags team)
|
||||||
(cfeat/check-client-features! (:features params))
|
|
||||||
(cfeat/check-file-features! (:features file)))
|
(cfeat/check-file-features! (:features file)))
|
||||||
|
|
||||||
{:file-id file-id
|
{:file-id file-id
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
[app.common.types.container :as ctn]
|
[app.common.types.container :as ctn]
|
||||||
[app.common.types.file :as ctf]
|
[app.common.types.file :as ctf]
|
||||||
[app.common.types.shape :as cts]
|
[app.common.types.shape :as cts]
|
||||||
|
[app.common.types.shape.interactions :as ctsi]
|
||||||
[app.common.types.shape.shadow :as ctss]
|
[app.common.types.shape.shadow :as ctss]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[clojure.set :as set]
|
[clojure.set :as set]
|
||||||
|
@ -847,9 +848,6 @@
|
||||||
(update :pages-index update-vals update-container)
|
(update :pages-index update-vals update-container)
|
||||||
(update :components update-vals update-container))))
|
(update :components update-vals update-container))))
|
||||||
|
|
||||||
(def ^:private valid-shadow?
|
|
||||||
(sm/lazy-validator ::ctss/shadow))
|
|
||||||
|
|
||||||
(defmethod migrate-data "legacy-44"
|
(defmethod migrate-data "legacy-44"
|
||||||
[data _]
|
[data _]
|
||||||
(letfn [(fix-shadow [shadow]
|
(letfn [(fix-shadow [shadow]
|
||||||
|
@ -861,7 +859,7 @@
|
||||||
|
|
||||||
(update-object [object]
|
(update-object [object]
|
||||||
(let [xform (comp (map fix-shadow)
|
(let [xform (comp (map fix-shadow)
|
||||||
(filter valid-shadow?))]
|
(filter ctss/valid-shadow?))]
|
||||||
(d/update-when object :shadow #(into [] xform %))))
|
(d/update-when object :shadow #(into [] xform %))))
|
||||||
|
|
||||||
(update-container [container]
|
(update-container [container]
|
||||||
|
@ -1036,7 +1034,7 @@
|
||||||
|
|
||||||
(update-shape [shape]
|
(update-shape [shape]
|
||||||
(let [xform (comp (map fix-shadow)
|
(let [xform (comp (map fix-shadow)
|
||||||
(filter valid-shadow?))]
|
(filter ctss/valid-shadow?))]
|
||||||
(d/update-when shape :shadow #(into [] xform %))))
|
(d/update-when shape :shadow #(into [] xform %))))
|
||||||
|
|
||||||
(update-container [container]
|
(update-container [container]
|
||||||
|
@ -1207,11 +1205,11 @@
|
||||||
object))
|
object))
|
||||||
|
|
||||||
(update-container [container]
|
(update-container [container]
|
||||||
(d/update-when container :objects update-vals update-object))]
|
(d/update-when container :objects d/update-vals update-object))]
|
||||||
|
|
||||||
(-> data
|
(-> data
|
||||||
(update :pages-index update-vals update-container)
|
(update :pages-index d/update-vals update-container)
|
||||||
(update :components update-vals update-container))))
|
(update :components d/update-vals update-container))))
|
||||||
|
|
||||||
(defmethod migrate-data "legacy-67"
|
(defmethod migrate-data "legacy-67"
|
||||||
[data _]
|
[data _]
|
||||||
|
@ -1222,8 +1220,8 @@
|
||||||
(d/update-when container :objects update-vals update-object))]
|
(d/update-when container :objects update-vals update-object))]
|
||||||
|
|
||||||
(-> data
|
(-> data
|
||||||
(update :pages-index update-vals update-container)
|
(update :pages-index d/update-vals update-container)
|
||||||
(update :components update-vals update-container))))
|
(update :components d/update-vals update-container))))
|
||||||
|
|
||||||
(defmethod migrate-data "0001-remove-tokens-from-groups"
|
(defmethod migrate-data "0001-remove-tokens-from-groups"
|
||||||
[data _]
|
[data _]
|
||||||
|
@ -1237,8 +1235,33 @@
|
||||||
(dissoc :applied-tokens)))
|
(dissoc :applied-tokens)))
|
||||||
|
|
||||||
(update-page [page]
|
(update-page [page]
|
||||||
(d/update-when page :objects update-vals update-object))]
|
(d/update-when page :objects d/update-vals update-object))]
|
||||||
(update data :pages-index update-vals update-page)))
|
|
||||||
|
(update data :pages-index d/update-vals update-page)))
|
||||||
|
|
||||||
|
(defmethod migrate-data "0002-clean-shape-interactions"
|
||||||
|
[data _]
|
||||||
|
(let [decode-fn (sm/decoder ctsi/schema:interaction sm/json-transformer)
|
||||||
|
validate-fn (sm/validator ctsi/schema:interaction)
|
||||||
|
|
||||||
|
xform
|
||||||
|
(comp
|
||||||
|
(map decode-fn)
|
||||||
|
(filter validate-fn))
|
||||||
|
|
||||||
|
update-object
|
||||||
|
(fn [object]
|
||||||
|
(d/update-when object :interactions
|
||||||
|
(fn [interactions]
|
||||||
|
(into [] xform interactions))))
|
||||||
|
|
||||||
|
update-container
|
||||||
|
(fn [container]
|
||||||
|
(d/update-when container :objects d/update-vals update-object))]
|
||||||
|
|
||||||
|
(-> data
|
||||||
|
(update :pages-index d/update-vals update-container)
|
||||||
|
(update :components d/update-vals update-container))))
|
||||||
|
|
||||||
(def available-migrations
|
(def available-migrations
|
||||||
(into (d/ordered-set)
|
(into (d/ordered-set)
|
||||||
|
@ -1294,4 +1317,5 @@
|
||||||
"legacy-65"
|
"legacy-65"
|
||||||
"legacy-66"
|
"legacy-66"
|
||||||
"legacy-67"
|
"legacy-67"
|
||||||
"0001-remove-tokens-from-groups"]))
|
"0001-remove-tokens-from-groups"
|
||||||
|
"0002-clean-shape-interactions"]))
|
||||||
|
|
|
@ -864,7 +864,7 @@
|
||||||
choices))]
|
choices))]
|
||||||
{:pred pred
|
{:pred pred
|
||||||
:type-properties
|
:type-properties
|
||||||
{:title "contains"
|
{:title "contains any"
|
||||||
:description "contains predicate"}}))})
|
:description "contains predicate"}}))})
|
||||||
|
|
||||||
(register!
|
(register!
|
||||||
|
|
|
@ -211,7 +211,7 @@
|
||||||
[:interactions {:optional true}
|
[:interactions {:optional true}
|
||||||
[:vector {:gen/max 2} ::ctsi/interaction]]
|
[:vector {:gen/max 2} ::ctsi/interaction]]
|
||||||
[:shadow {:optional true}
|
[:shadow {:optional true}
|
||||||
[:vector {:gen/max 1} ::ctss/shadow]]
|
[:vector {:gen/max 1} ctss/schema:shadow]]
|
||||||
[:blur {:optional true} ::ctsb/blur]
|
[:blur {:optional true} ::ctsb/blur]
|
||||||
[:grow-type {:optional true}
|
[:grow-type {:optional true}
|
||||||
[::sm/one-of grow-types]]
|
[::sm/one-of grow-types]]
|
||||||
|
|
|
@ -26,7 +26,9 @@
|
||||||
[:hidden :boolean]
|
[:hidden :boolean]
|
||||||
[:color ::ctc/color]])
|
[:color ::ctc/color]])
|
||||||
|
|
||||||
(sm/register! ::shadow schema:shadow)
|
|
||||||
|
|
||||||
(def check-shadow
|
(def check-shadow
|
||||||
(sm/check-fn schema:shadow))
|
(sm/check-fn schema:shadow))
|
||||||
|
|
||||||
|
(def valid-shadow?
|
||||||
|
(sm/validator schema:shadow))
|
||||||
|
|
||||||
|
|
|
@ -89,6 +89,7 @@
|
||||||
|
|
||||||
(mf/with-effect [file-id revn visible? thumbnail-id]
|
(mf/with-effect [file-id revn visible? thumbnail-id]
|
||||||
(when (and visible? (not thumbnail-id))
|
(when (and visible? (not thumbnail-id))
|
||||||
|
(let [subscription
|
||||||
(->> (ask-for-thumbnail file-id revn)
|
(->> (ask-for-thumbnail file-id revn)
|
||||||
(rx/subs! (fn [thumbnail-id]
|
(rx/subs! (fn [thumbnail-id]
|
||||||
(st/emit! (dd/set-file-thumbnail file-id thumbnail-id)))
|
(st/emit! (dd/set-file-thumbnail file-id thumbnail-id)))
|
||||||
|
@ -96,7 +97,8 @@
|
||||||
(log/error :hint "unable to render thumbnail"
|
(log/error :hint "unable to render thumbnail"
|
||||||
:file-if file-id
|
:file-if file-id
|
||||||
:revn revn
|
:revn revn
|
||||||
:message (ex-message cause)))))))
|
:message (ex-message cause)))))]
|
||||||
|
(partial rx/dispose! subscription))))
|
||||||
|
|
||||||
[:div {:class (stl/css :grid-item-th)
|
[:div {:class (stl/css :grid-item-th)
|
||||||
:style {:background-color bg-color}
|
:style {:background-color bg-color}
|
||||||
|
|
|
@ -432,7 +432,7 @@
|
||||||
(let [id (obj/get self "$id")
|
(let [id (obj/get self "$id")
|
||||||
value (mapv #(shadow-defaults (parser/parse-shadow %)) value)]
|
value (mapv #(shadow-defaults (parser/parse-shadow %)) value)]
|
||||||
(cond
|
(cond
|
||||||
(not (sm/validate [:vector ::ctss/shadow] value))
|
(not (sm/validate [:vector ctss/schema:shadow] value))
|
||||||
(u/display-not-valid :shadows value)
|
(u/display-not-valid :shadows value)
|
||||||
|
|
||||||
(not (r/check-permission plugin-id "content:write"))
|
(not (r/check-permission plugin-id "content:write"))
|
||||||
|
|
|
@ -50,7 +50,8 @@
|
||||||
[headers]
|
[headers]
|
||||||
(into {} (map vec) (seq (.entries ^js headers))))
|
(into {} (map vec) (seq (.entries ^js headers))))
|
||||||
|
|
||||||
(def default-headers
|
(defn default-headers
|
||||||
|
[]
|
||||||
{"x-frontend-version" (:full cfg/version)})
|
{"x-frontend-version" (:full cfg/version)})
|
||||||
|
|
||||||
(defn fetch
|
(defn fetch
|
||||||
|
@ -74,7 +75,7 @@
|
||||||
|
|
||||||
headers (cond-> headers
|
headers (cond-> headers
|
||||||
(not omit-default-headers)
|
(not omit-default-headers)
|
||||||
(d/merge default-headers))
|
(merge (default-headers)))
|
||||||
|
|
||||||
headers (-update-headers body headers)
|
headers (-update-headers body headers)
|
||||||
|
|
||||||
|
|
|
@ -42,12 +42,11 @@
|
||||||
:http-body body})))
|
:http-body body})))
|
||||||
|
|
||||||
(defn- request-data-for-thumbnail
|
(defn- request-data-for-thumbnail
|
||||||
[file-id revn features]
|
[file-id revn]
|
||||||
(let [path "api/rpc/command/get-file-data-for-thumbnail"
|
(let [path "api/rpc/command/get-file-data-for-thumbnail"
|
||||||
params {:file-id file-id
|
params {:file-id file-id
|
||||||
:revn revn
|
:revn revn
|
||||||
:strip-frames-with-thumbnails true
|
:strip-frames-with-thumbnails true}
|
||||||
:features features}
|
|
||||||
request {:method :get
|
request {:method :get
|
||||||
:uri (u/join cf/public-uri path)
|
:uri (u/join cf/public-uri path)
|
||||||
:credentials "include"
|
:credentials "include"
|
||||||
|
@ -86,6 +85,6 @@
|
||||||
nil)))
|
nil)))
|
||||||
|
|
||||||
(defmethod impl/handler :thumbnails/generate-for-file
|
(defmethod impl/handler :thumbnails/generate-for-file
|
||||||
[{:keys [file-id revn features] :as message} _]
|
[{:keys [file-id revn] :as message} _]
|
||||||
(->> (request-data-for-thumbnail file-id revn features)
|
(->> (request-data-for-thumbnail file-id revn)
|
||||||
(rx/map render-thumbnail)))
|
(rx/map render-thumbnail)))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue