Merge pull request #6345 from penpot/niwinz-staging-add-interaction-cleaning

🐛 Add migration for decoding and cleaning shape interactions
This commit is contained in:
Alejandro Alonso 2025-04-23 08:08:31 +02:00 committed by GitHub
commit f155042958
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 129 additions and 46 deletions

View 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)))

View file

@ -8,6 +8,7 @@
"A ZIP based binary file exportation"
(:refer-clojure :exclude [read])
(:require
[app.binfile.cleaner :as bfl]
[app.binfile.common :as bfc]
[app.binfile.migrations :as bfm]
[app.common.data :as d]
@ -594,16 +595,25 @@
(defn- read-file-components
[{: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)
(reduce (fn [result {:keys [id entry]}]
(let [object (->> (read-entry input entry)
(decode-component)
(clean-component-post-decode)
(validate-component))]
(if (= id (:id object))
(assoc result id object)
result)))
{})
(not-empty)))
(not-empty))))
(defn- read-file-typographies
[{:keys [::bfc/input ::file-id ::entries]}]
@ -631,7 +641,9 @@
(reduce (fn [result {:keys [id entry]}]
(let [object (->> (read-entry input entry)
(decode-shape)
(bfl/clean-shape-post-decode)
(validate-shape))]
(if (= id (:id object))
(assoc result id object)
result)))

View file

@ -238,6 +238,7 @@
(db/update! conn :file
{:data (blob/encode (:data file))
:version (:version file)
:modified-at (dt/now)
:features (db/create-array conn "text" (:features file))}
{:id id})

View file

@ -180,8 +180,7 @@
(def ^:private
schema:get-file-data-for-thumbnail
[:map {:title "get-file-data-for-thumbnail"}
[:file-id ::sm/uuid]
[:features {:optional true} ::cfeat/features]])
[:file-id ::sm/uuid]])
(def ^:private
schema:partial-file
@ -211,7 +210,6 @@
(fmg/migrate-file)))]
(-> (cfeat/get-team-enabled-features cf/flags team)
(cfeat/check-client-features! (:features params))
(cfeat/check-file-features! (:features file)))
{:file-id file-id

View file

@ -28,6 +28,7 @@
[app.common.types.container :as ctn]
[app.common.types.file :as ctf]
[app.common.types.shape :as cts]
[app.common.types.shape.interactions :as ctsi]
[app.common.types.shape.shadow :as ctss]
[app.common.uuid :as uuid]
[clojure.set :as set]
@ -847,9 +848,6 @@
(update :pages-index update-vals update-container)
(update :components update-vals update-container))))
(def ^:private valid-shadow?
(sm/lazy-validator ::ctss/shadow))
(defmethod migrate-data "legacy-44"
[data _]
(letfn [(fix-shadow [shadow]
@ -861,7 +859,7 @@
(update-object [object]
(let [xform (comp (map fix-shadow)
(filter valid-shadow?))]
(filter ctss/valid-shadow?))]
(d/update-when object :shadow #(into [] xform %))))
(update-container [container]
@ -1036,7 +1034,7 @@
(update-shape [shape]
(let [xform (comp (map fix-shadow)
(filter valid-shadow?))]
(filter ctss/valid-shadow?))]
(d/update-when shape :shadow #(into [] xform %))))
(update-container [container]
@ -1207,11 +1205,11 @@
object))
(update-container [container]
(d/update-when container :objects update-vals update-object))]
(d/update-when container :objects d/update-vals update-object))]
(-> data
(update :pages-index update-vals update-container)
(update :components update-vals update-container))))
(update :pages-index d/update-vals update-container)
(update :components d/update-vals update-container))))
(defmethod migrate-data "legacy-67"
[data _]
@ -1222,8 +1220,8 @@
(d/update-when container :objects update-vals update-object))]
(-> data
(update :pages-index update-vals update-container)
(update :components update-vals update-container))))
(update :pages-index d/update-vals update-container)
(update :components d/update-vals update-container))))
(defmethod migrate-data "0001-remove-tokens-from-groups"
[data _]
@ -1237,8 +1235,33 @@
(dissoc :applied-tokens)))
(update-page [page]
(d/update-when page :objects update-vals update-object))]
(update data :pages-index update-vals update-page)))
(d/update-when page :objects d/update-vals update-object))]
(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
(into (d/ordered-set)
@ -1294,4 +1317,5 @@
"legacy-65"
"legacy-66"
"legacy-67"
"0001-remove-tokens-from-groups"]))
"0001-remove-tokens-from-groups"
"0002-clean-shape-interactions"]))

View file

@ -864,7 +864,7 @@
choices))]
{:pred pred
:type-properties
{:title "contains"
{:title "contains any"
:description "contains predicate"}}))})
(register!

View file

@ -211,7 +211,7 @@
[:interactions {:optional true}
[:vector {:gen/max 2} ::ctsi/interaction]]
[:shadow {:optional true}
[:vector {:gen/max 1} ::ctss/shadow]]
[:vector {:gen/max 1} ctss/schema:shadow]]
[:blur {:optional true} ::ctsb/blur]
[:grow-type {:optional true}
[::sm/one-of grow-types]]

View file

@ -26,7 +26,9 @@
[:hidden :boolean]
[:color ::ctc/color]])
(sm/register! ::shadow schema:shadow)
(def check-shadow
(sm/check-fn schema:shadow))
(def valid-shadow?
(sm/validator schema:shadow))

View file

@ -89,6 +89,7 @@
(mf/with-effect [file-id revn visible? thumbnail-id]
(when (and visible? (not thumbnail-id))
(let [subscription
(->> (ask-for-thumbnail file-id revn)
(rx/subs! (fn [thumbnail-id]
(st/emit! (dd/set-file-thumbnail file-id thumbnail-id)))
@ -96,7 +97,8 @@
(log/error :hint "unable to render thumbnail"
:file-if file-id
:revn revn
:message (ex-message cause)))))))
:message (ex-message cause)))))]
(partial rx/dispose! subscription))))
[:div {:class (stl/css :grid-item-th)
:style {:background-color bg-color}

View file

@ -432,7 +432,7 @@
(let [id (obj/get self "$id")
value (mapv #(shadow-defaults (parser/parse-shadow %)) value)]
(cond
(not (sm/validate [:vector ::ctss/shadow] value))
(not (sm/validate [:vector ctss/schema:shadow] value))
(u/display-not-valid :shadows value)
(not (r/check-permission plugin-id "content:write"))

View file

@ -50,7 +50,8 @@
[headers]
(into {} (map vec) (seq (.entries ^js headers))))
(def default-headers
(defn default-headers
[]
{"x-frontend-version" (:full cfg/version)})
(defn fetch
@ -74,7 +75,7 @@
headers (cond-> headers
(not omit-default-headers)
(d/merge default-headers))
(merge (default-headers)))
headers (-update-headers body headers)

View file

@ -42,12 +42,11 @@
:http-body body})))
(defn- request-data-for-thumbnail
[file-id revn features]
[file-id revn]
(let [path "api/rpc/command/get-file-data-for-thumbnail"
params {:file-id file-id
:revn revn
:strip-frames-with-thumbnails true
:features features}
:strip-frames-with-thumbnails true}
request {:method :get
:uri (u/join cf/public-uri path)
:credentials "include"
@ -86,6 +85,6 @@
nil)))
(defmethod impl/handler :thumbnails/generate-for-file
[{:keys [file-id revn features] :as message} _]
(->> (request-data-for-thumbnail file-id revn features)
[{:keys [file-id revn] :as message} _]
(->> (request-data-for-thumbnail file-id revn)
(rx/map render-thumbnail)))