mirror of
https://github.com/penpot/penpot.git
synced 2026-09-11 06:28:47 +00:00
🐛 Add missing permission checks to plugin API (tokens, shapes, variants, flows, layouts, user identity) (#11139)
* 🐛 Add content:write permission checks to Design Tokens plugin API The Design Tokens API (tokens.cljs) had zero permission checks, allowing any plugin to create, modify, and delete tokens, sets, and themes regardless of granted permissions. Add r/check-permission checks to all 22 write operations across: - token-proxy: name, value, description, duplicate, remove, applyToken - token-set-proxy: name, active, toggleActive, addToken, duplicate, remove - token-theme-proxy: group, name, active, toggleActive, addSet, removeSet, duplicate, remove - tokens-catalog: addTheme, addSet Follows the established pattern from comments.cljs, file.cljs, page.cljs. Closes #11137 AI-assisted-by: qwen3.7-plus * 🐛 Add permission checks to shape proxy interactions, detach, export, and variants The shape proxy (shape.cljs) had multiple operations missing permission checks, plus a cond ordering bug that bypassed the existing content:write check for text shapes in commit-fills!. Fix commit-fills! cond ordering: move permission check before the text-shape branch so text shapes are also protected. Add content:write permission checks to: - interaction-proxy: :trigger, :delay, :action setters, :remove method - shape-proxy: :addInteraction, :removeInteraction, :detach - shape-proxy: :applyToken, :switchVariant, :combineAsVariants Add content:read permission check to: - shape-proxy: :export (read/extraction operation) Follows the established pattern from :resize, :rotate, :blocked setters. Relates to #11137 AI-assisted-by: qwen3.7-plus * 🐛 Add library:write permission checks to variant plugin API The library.cljs variant operations (variant-proxy and lib-component-proxy) had seven mutating operations that did not check the library:write permission, allowing any plugin to create, modify, and delete component variants regardless of granted permissions. Add r/check-permission checks to all 7 operations: - variant-proxy: addVariant, addProperty, removeProperty, renameProperty - lib-component-proxy: transformInVariant, addVariant, setVariantProperty Follows the established pattern from the :name and :path setters in the same file. Relates to #11137 AI-assisted-by: qwen3.7-plus * 🐛 Add content:write permission checks to flow and flex layout plugin API Add permission checks to prototype flow and flex layout operations that were missing them, allowing plugins to modify flows and layout structure without explicit user permission. Changes: - page.cljs: Add content:write checks to flow-proxy (name, startingBoard setters, remove) and page-proxy (createFlow, removeFlow) - flex.cljs: Add content:write checks to flex-layout-proxy (remove, appendChild) Follows the established pattern from tokens.cljs, shape.cljs, and library.cljs. Relates to #11137 AI-assisted-by: qwen3.7-plus * 🐛 Add user:read permission checks to plugin API Add permission checks to user identity accessors that were bypassing the consent model, allowing plugins to access user data regardless of whether the user granted user:read permission. Changes: - api.cljs: Add user:read checks to getCurrentUser and getActiveUsers - comments.cljs: Add user:read checks to comment-proxy and comment-thread-proxy owner/user getters - file.cljs: Add user:read check to file-version-proxy createdBy getter When user:read permission is not granted: - getCurrentUser() returns null - getActiveUsers() returns empty array - owner/user/createdBy getters return null Follows the established pattern from other permission checks in the plugin API. Relates to #11137 AI-assisted-by: qwen3.7-plus * 🐛 Fix problem with token API --------- Co-authored-by: alonso.torres <alonso.torres@kaleidos.net>
This commit is contained in:
parent
5f1e151e84
commit
937b3fc65f
@ -47,6 +47,7 @@
|
|||||||
[app.plugins.page :as page]
|
[app.plugins.page :as page]
|
||||||
[app.plugins.parser :as parser]
|
[app.plugins.parser :as parser]
|
||||||
[app.plugins.reflow :as wrfp]
|
[app.plugins.reflow :as wrfp]
|
||||||
|
[app.plugins.register :as r]
|
||||||
[app.plugins.shape :as shape]
|
[app.plugins.shape :as shape]
|
||||||
[app.plugins.system-events :as se]
|
[app.plugins.system-events :as se]
|
||||||
[app.plugins.user :as user]
|
[app.plugins.user :as user]
|
||||||
@ -242,15 +243,18 @@
|
|||||||
|
|
||||||
:getCurrentUser
|
:getCurrentUser
|
||||||
(fn []
|
(fn []
|
||||||
(user/current-user-proxy plugin-id (:session-id @st/state)))
|
(when (r/check-permission plugin-id "user:read")
|
||||||
|
(user/current-user-proxy plugin-id (:session-id @st/state))))
|
||||||
|
|
||||||
:getActiveUsers
|
:getActiveUsers
|
||||||
(fn []
|
(fn []
|
||||||
|
(if (r/check-permission plugin-id "user:read")
|
||||||
(apply array
|
(apply array
|
||||||
(->> (:workspace-presence @st/state)
|
(->> (:workspace-presence @st/state)
|
||||||
(vals)
|
(vals)
|
||||||
(remove #(= (:id %) (:session-id @st/state)))
|
(remove #(= (:id %) (:session-id @st/state)))
|
||||||
(map #(user/active-user-proxy plugin-id (:id %))))))
|
(map #(user/active-user-proxy plugin-id (:id %)))))
|
||||||
|
(array)))
|
||||||
|
|
||||||
:uploadMediaUrl
|
:uploadMediaUrl
|
||||||
(fn [name url]
|
(fn [name url]
|
||||||
|
|||||||
@ -40,12 +40,14 @@
|
|||||||
|
|
||||||
;; FIXME: inconsistent with comment-thread: owner
|
;; FIXME: inconsistent with comment-thread: owner
|
||||||
:user
|
:user
|
||||||
{:get #(->> (dc/get-owner data)
|
{:get #(when (r/check-permission plugin-id "user:read")
|
||||||
(user/user-proxy plugin-id))}
|
(->> (dc/get-owner data)
|
||||||
|
(user/user-proxy plugin-id)))}
|
||||||
|
|
||||||
:owner
|
:owner
|
||||||
{:get #(->> (dc/get-owner data)
|
{:get #(when (r/check-permission plugin-id "user:read")
|
||||||
(user/user-proxy plugin-id))}
|
(->> (dc/get-owner data)
|
||||||
|
(user/user-proxy plugin-id)))}
|
||||||
|
|
||||||
:date
|
:date
|
||||||
{:get
|
{:get
|
||||||
@ -116,8 +118,9 @@
|
|||||||
:board {:get #(shape/shape-proxy plugin-id file-id page-id (:frame-id data))}
|
:board {:get #(shape/shape-proxy plugin-id file-id page-id (:frame-id data))}
|
||||||
|
|
||||||
:owner
|
:owner
|
||||||
{:get #(->> (dc/get-owner data)
|
{:get #(when (r/check-permission plugin-id "user:read")
|
||||||
(user/user-proxy plugin-id))}
|
(->> (dc/get-owner data)
|
||||||
|
(user/user-proxy plugin-id)))}
|
||||||
|
|
||||||
:position
|
:position
|
||||||
{:get
|
{:get
|
||||||
|
|||||||
@ -61,8 +61,9 @@
|
|||||||
:createdBy
|
:createdBy
|
||||||
{:get
|
{:get
|
||||||
(fn []
|
(fn []
|
||||||
|
(when (r/check-permission plugin-id "user:read")
|
||||||
(when-let [user-data (get users (:profile-id @data))]
|
(when-let [user-data (get users (:profile-id @data))]
|
||||||
(user/user-proxy plugin-id user-data)))}
|
(user/user-proxy plugin-id user-data))))}
|
||||||
|
|
||||||
:createdAt
|
:createdAt
|
||||||
{:get #(:created-at @data)}
|
{:get #(:created-at @data)}
|
||||||
|
|||||||
@ -325,7 +325,12 @@
|
|||||||
|
|
||||||
:remove
|
:remove
|
||||||
(fn []
|
(fn []
|
||||||
(st/emit! (dwsl/remove-layout #{id})))
|
(cond
|
||||||
|
(not (r/check-permission plugin-id "content:write"))
|
||||||
|
(u/not-valid plugin-id :remove "Plugin doesn't have 'content:write' permission")
|
||||||
|
|
||||||
|
:else
|
||||||
|
(st/emit! (dwsl/remove-layout #{id}))))
|
||||||
|
|
||||||
:appendChild
|
:appendChild
|
||||||
(fn [child]
|
(fn [child]
|
||||||
@ -350,6 +355,9 @@
|
|||||||
(u/changes-component-copy-structure? objects shape child-shape)
|
(u/changes-component-copy-structure? objects shape child-shape)
|
||||||
(u/not-valid plugin-id :appendChild "Cannot change the structure of a component copy")
|
(u/not-valid plugin-id :appendChild "Cannot change the structure of a component copy")
|
||||||
|
|
||||||
|
(not (r/check-permission plugin-id "content:write"))
|
||||||
|
(u/not-valid plugin-id :appendChild "Plugin doesn't have 'content:write' permission")
|
||||||
|
|
||||||
:else
|
:else
|
||||||
(st/emit!
|
(st/emit!
|
||||||
(dwsh/relocate-shapes #{child-id} id index)
|
(dwsh/relocate-shapes #{child-id} id index)
|
||||||
|
|||||||
@ -698,21 +698,37 @@
|
|||||||
|
|
||||||
:addVariant
|
:addVariant
|
||||||
(fn []
|
(fn []
|
||||||
|
(cond
|
||||||
|
(not (r/check-permission plugin-id "library:write"))
|
||||||
|
(u/not-valid plugin-id :addVariant "Plugin doesn't have 'library:write' permission")
|
||||||
|
|
||||||
|
:else
|
||||||
(st/emit!
|
(st/emit!
|
||||||
(se/event plugin-id "add-new-variant")
|
(se/event plugin-id "add-new-variant")
|
||||||
(dwv/add-new-variant id)))
|
(dwv/add-new-variant id))))
|
||||||
|
|
||||||
:addProperty
|
:addProperty
|
||||||
(fn []
|
(fn []
|
||||||
|
(cond
|
||||||
|
(not (r/check-permission plugin-id "library:write"))
|
||||||
|
(u/not-valid plugin-id :addProperty "Plugin doesn't have 'library:write' permission")
|
||||||
|
|
||||||
|
:else
|
||||||
(st/emit!
|
(st/emit!
|
||||||
(se/event plugin-id "add-new-property")
|
(se/event plugin-id "add-new-property")
|
||||||
(dwv/add-new-property id {:property-value "Value 1"})))
|
(dwv/add-new-property id {:property-value "Value 1"}))))
|
||||||
|
|
||||||
:removeProperty
|
:removeProperty
|
||||||
(fn [pos]
|
(fn [pos]
|
||||||
(let [nprops (->> (get-variant-components file-id id) first :variant-properties count)]
|
(let [nprops (->> (get-variant-components file-id id) first :variant-properties count)]
|
||||||
(if (or (not (nat-int? pos)) (>= pos nprops))
|
(cond
|
||||||
|
(or (not (nat-int? pos)) (>= pos nprops))
|
||||||
(u/not-valid plugin-id :pos pos)
|
(u/not-valid plugin-id :pos pos)
|
||||||
|
|
||||||
|
(not (r/check-permission plugin-id "library:write"))
|
||||||
|
(u/not-valid plugin-id :removeProperty "Plugin doesn't have 'library:write' permission")
|
||||||
|
|
||||||
|
:else
|
||||||
(st/emit!
|
(st/emit!
|
||||||
(se/event plugin-id "remove-property")
|
(se/event plugin-id "remove-property")
|
||||||
(dwv/remove-property id pos)))))
|
(dwv/remove-property id pos)))))
|
||||||
@ -727,6 +743,9 @@
|
|||||||
(not (string? name))
|
(not (string? name))
|
||||||
(u/not-valid plugin-id :name name)
|
(u/not-valid plugin-id :name name)
|
||||||
|
|
||||||
|
(not (r/check-permission plugin-id "library:write"))
|
||||||
|
(u/not-valid plugin-id :renameProperty "Plugin doesn't have 'library:write' permission")
|
||||||
|
|
||||||
:else
|
:else
|
||||||
(st/emit!
|
(st/emit!
|
||||||
(dwv/update-property-name id pos name {:trigger "plugin:rename-property"})))))))
|
(dwv/update-property-name id pos name {:trigger "plugin:rename-property"})))))))
|
||||||
@ -923,8 +942,15 @@
|
|||||||
:transformInVariant
|
:transformInVariant
|
||||||
(fn []
|
(fn []
|
||||||
(let [component (u/locate-library-component file-id id)]
|
(let [component (u/locate-library-component file-id id)]
|
||||||
(when (and component
|
(cond
|
||||||
(not (ctk/is-variant? component)))
|
(or (nil? component)
|
||||||
|
(ctk/is-variant? component))
|
||||||
|
nil
|
||||||
|
|
||||||
|
(not (r/check-permission plugin-id "library:write"))
|
||||||
|
(u/not-valid plugin-id :transformInVariant "Plugin doesn't have 'library:write' permission")
|
||||||
|
|
||||||
|
:else
|
||||||
(st/emit!
|
(st/emit!
|
||||||
(se/event plugin-id "transform-in-variant")
|
(se/event plugin-id "transform-in-variant")
|
||||||
(dwv/transform-in-variant (:main-instance-id component))))))
|
(dwv/transform-in-variant (:main-instance-id component))))))
|
||||||
@ -932,8 +958,15 @@
|
|||||||
:addVariant
|
:addVariant
|
||||||
(fn []
|
(fn []
|
||||||
(let [component (u/locate-library-component file-id id)]
|
(let [component (u/locate-library-component file-id id)]
|
||||||
(when (and component
|
(cond
|
||||||
(ctk/is-variant? component))
|
(or (nil? component)
|
||||||
|
(not (ctk/is-variant? component)))
|
||||||
|
nil
|
||||||
|
|
||||||
|
(not (r/check-permission plugin-id "library:write"))
|
||||||
|
(u/not-valid plugin-id :addVariant "Plugin doesn't have 'library:write' permission")
|
||||||
|
|
||||||
|
:else
|
||||||
(st/emit!
|
(st/emit!
|
||||||
(se/event plugin-id "add-new-variant")
|
(se/event plugin-id "add-new-variant")
|
||||||
(dwv/add-new-variant (:main-instance-id component))))))
|
(dwv/add-new-variant (:main-instance-id component))))))
|
||||||
@ -948,6 +981,9 @@
|
|||||||
(not (string? value))
|
(not (string? value))
|
||||||
(u/not-valid plugin-id :name value)
|
(u/not-valid plugin-id :name value)
|
||||||
|
|
||||||
|
(not (r/check-permission plugin-id "library:write"))
|
||||||
|
(u/not-valid plugin-id :setVariantProperty "Plugin doesn't have 'library:write' permission")
|
||||||
|
|
||||||
:else
|
:else
|
||||||
(st/emit!
|
(st/emit!
|
||||||
(se/event plugin-id "variant-edit-property-value")
|
(se/event plugin-id "variant-edit-property-value")
|
||||||
|
|||||||
@ -64,6 +64,9 @@
|
|||||||
(or (not (string? value)) (empty? value))
|
(or (not (string? value)) (empty? value))
|
||||||
(u/not-valid plugin-id :name value)
|
(u/not-valid plugin-id :name value)
|
||||||
|
|
||||||
|
(not (r/check-permission plugin-id "content:write"))
|
||||||
|
(u/not-valid plugin-id :name "Plugin doesn't have 'content:write' permission")
|
||||||
|
|
||||||
:else
|
:else
|
||||||
(st/emit! (dwi/update-flow page-id id #(assoc % :name value)))))}
|
(st/emit! (dwi/update-flow page-id id #(assoc % :name value)))))}
|
||||||
|
|
||||||
@ -79,12 +82,20 @@
|
|||||||
(not (shape/shape-proxy? value))
|
(not (shape/shape-proxy? value))
|
||||||
(u/not-valid plugin-id :startingBoard value)
|
(u/not-valid plugin-id :startingBoard value)
|
||||||
|
|
||||||
|
(not (r/check-permission plugin-id "content:write"))
|
||||||
|
(u/not-valid plugin-id :startingBoard "Plugin doesn't have 'content:write' permission")
|
||||||
|
|
||||||
:else
|
:else
|
||||||
(st/emit! (dwi/update-flow page-id id #(assoc % :starting-frame (obj/get value "$id"))))))}
|
(st/emit! (dwi/update-flow page-id id #(assoc % :starting-frame (obj/get value "$id"))))))}
|
||||||
|
|
||||||
:remove
|
:remove
|
||||||
(fn []
|
(fn []
|
||||||
(st/emit! (dwi/remove-flow page-id id)))))
|
(cond
|
||||||
|
(not (r/check-permission plugin-id "content:write"))
|
||||||
|
(u/not-valid plugin-id :remove "Plugin doesn't have 'content:write' permission")
|
||||||
|
|
||||||
|
:else
|
||||||
|
(st/emit! (dwi/remove-flow page-id id))))))
|
||||||
|
|
||||||
(defn page-proxy? [proxy]
|
(defn page-proxy? [proxy]
|
||||||
(obj/type-of? proxy "PageProxy"))
|
(obj/type-of? proxy "PageProxy"))
|
||||||
@ -315,6 +326,9 @@
|
|||||||
(not (shape/shape-proxy? frame))
|
(not (shape/shape-proxy? frame))
|
||||||
(u/not-valid plugin-id :createFlow-frame frame)
|
(u/not-valid plugin-id :createFlow-frame frame)
|
||||||
|
|
||||||
|
(not (r/check-permission plugin-id "content:write"))
|
||||||
|
(u/not-valid plugin-id :createFlow "Plugin doesn't have 'content:write' permission")
|
||||||
|
|
||||||
:else
|
:else
|
||||||
(let [flow-id (uuid/next)]
|
(let [flow-id (uuid/next)]
|
||||||
(st/emit!
|
(st/emit!
|
||||||
@ -328,6 +342,9 @@
|
|||||||
(not (flow-proxy? flow))
|
(not (flow-proxy? flow))
|
||||||
(u/not-valid plugin-id :removeFlow-flow flow)
|
(u/not-valid plugin-id :removeFlow-flow flow)
|
||||||
|
|
||||||
|
(not (r/check-permission plugin-id "content:write"))
|
||||||
|
(u/not-valid plugin-id :removeFlow "Plugin doesn't have 'content:write' permission")
|
||||||
|
|
||||||
:else
|
:else
|
||||||
(st/emit!
|
(st/emit!
|
||||||
(dwi/remove-flow id (obj/get flow "$id"))
|
(dwi/remove-flow id (obj/get flow "$id"))
|
||||||
|
|||||||
@ -103,6 +103,9 @@
|
|||||||
(not (contains? ctsi/event-types value))
|
(not (contains? ctsi/event-types value))
|
||||||
(u/not-valid plugin-id :trigger value)
|
(u/not-valid plugin-id :trigger value)
|
||||||
|
|
||||||
|
(not (r/check-permission plugin-id "content:write"))
|
||||||
|
(u/not-valid plugin-id :trigger "Plugin doesn't have 'content:write' permission")
|
||||||
|
|
||||||
:else
|
:else
|
||||||
(st/emit! (dwi/update-interaction
|
(st/emit! (dwi/update-interaction
|
||||||
(u/locate-shape file-id page-id shape-id)
|
(u/locate-shape file-id page-id shape-id)
|
||||||
@ -119,6 +122,9 @@
|
|||||||
(or (not (sm/valid-safe-int? value)) (neg? value))
|
(or (not (sm/valid-safe-int? value)) (neg? value))
|
||||||
(u/not-valid plugin-id :delay value)
|
(u/not-valid plugin-id :delay value)
|
||||||
|
|
||||||
|
(not (r/check-permission plugin-id "content:write"))
|
||||||
|
(u/not-valid plugin-id :delay "Plugin doesn't have 'content:write' permission")
|
||||||
|
|
||||||
:else
|
:else
|
||||||
(st/emit! (dwi/update-interaction
|
(st/emit! (dwi/update-interaction
|
||||||
(u/locate-shape file-id page-id shape-id)
|
(u/locate-shape file-id page-id shape-id)
|
||||||
@ -139,6 +145,9 @@
|
|||||||
(not (sm/validate ctsi/schema:interaction interaction))
|
(not (sm/validate ctsi/schema:interaction interaction))
|
||||||
(u/not-valid plugin-id :action interaction)
|
(u/not-valid plugin-id :action interaction)
|
||||||
|
|
||||||
|
(not (r/check-permission plugin-id "content:write"))
|
||||||
|
(u/not-valid plugin-id :action "Plugin doesn't have 'content:write' permission")
|
||||||
|
|
||||||
:else
|
:else
|
||||||
(st/emit! (dwi/update-interaction
|
(st/emit! (dwi/update-interaction
|
||||||
(u/locate-shape file-id page-id shape-id)
|
(u/locate-shape file-id page-id shape-id)
|
||||||
@ -148,7 +157,12 @@
|
|||||||
|
|
||||||
:remove
|
:remove
|
||||||
(fn []
|
(fn []
|
||||||
(st/emit! (dwi/remove-interaction {:id shape-id} index)))))
|
(cond
|
||||||
|
(not (r/check-permission plugin-id "content:write"))
|
||||||
|
(u/not-valid plugin-id :remove "Plugin doesn't have 'content:write' permission")
|
||||||
|
|
||||||
|
:else
|
||||||
|
(st/emit! (dwi/remove-interaction {:id shape-id} index))))))
|
||||||
|
|
||||||
(def lib-typography-proxy? nil)
|
(def lib-typography-proxy? nil)
|
||||||
(def lib-component-proxy nil)
|
(def lib-component-proxy nil)
|
||||||
@ -200,15 +214,15 @@
|
|||||||
(not (sm/validate [:vector types.fills/schema:fill] value))
|
(not (sm/validate [:vector types.fills/schema:fill] value))
|
||||||
(u/not-valid plugin-id :fills value)
|
(u/not-valid plugin-id :fills value)
|
||||||
|
|
||||||
|
(not (r/check-permission plugin-id "content:write"))
|
||||||
|
(u/not-valid plugin-id :fills "Plugin doesn't have 'content:write' permission")
|
||||||
|
|
||||||
(not (u/page-active? (obj/get self "$page")))
|
(not (u/page-active? (obj/get self "$page")))
|
||||||
(u/not-valid plugin-id :fills "Cannot modify a page that is not currently active")
|
(u/not-valid plugin-id :fills "Cannot modify a page that is not currently active")
|
||||||
|
|
||||||
(cfh/text-shape? shape)
|
(cfh/text-shape? shape)
|
||||||
(st/emit! (dwt/update-attrs id {:fills value}))
|
(st/emit! (dwt/update-attrs id {:fills value}))
|
||||||
|
|
||||||
(not (r/check-permission plugin-id "content:write"))
|
|
||||||
(u/not-valid plugin-id :fills "Plugin doesn't have 'content:write' permission")
|
|
||||||
|
|
||||||
:else
|
:else
|
||||||
(st/emit! (dwsh/update-shapes [id] #(assoc % :fills value))))))
|
(st/emit! (dwsh/update-shapes [id] #(assoc % :fills value))))))
|
||||||
|
|
||||||
@ -1475,6 +1489,9 @@
|
|||||||
:detach
|
:detach
|
||||||
(fn []
|
(fn []
|
||||||
(cond
|
(cond
|
||||||
|
(not (r/check-permission plugin-id "content:write"))
|
||||||
|
(u/not-valid plugin-id :detach "Plugin doesn't have 'content:write' permission")
|
||||||
|
|
||||||
(not (u/page-active? page-id))
|
(not (u/page-active? page-id))
|
||||||
(u/not-valid plugin-id :detach "Cannot modify a page that is not currently active")
|
(u/not-valid plugin-id :detach "Cannot modify a page that is not currently active")
|
||||||
|
|
||||||
@ -1485,12 +1502,12 @@
|
|||||||
(fn [component]
|
(fn [component]
|
||||||
(let [shape (u/locate-shape file-id page-id id)]
|
(let [shape (u/locate-shape file-id page-id id)]
|
||||||
(cond
|
(cond
|
||||||
(not (u/page-active? page-id))
|
|
||||||
(u/not-valid plugin-id :swapComponent "Cannot modify a page that is not currently active")
|
|
||||||
|
|
||||||
(not (r/check-permission plugin-id "content:write"))
|
(not (r/check-permission plugin-id "content:write"))
|
||||||
(u/not-valid plugin-id :swapComponent "Plugin doesn't have 'content:write' permission")
|
(u/not-valid plugin-id :swapComponent "Plugin doesn't have 'content:write' permission")
|
||||||
|
|
||||||
|
(not (u/page-active? page-id))
|
||||||
|
(u/not-valid plugin-id :swapComponent "Cannot modify a page that is not currently active")
|
||||||
|
|
||||||
(not (obj/type-of? component "LibraryComponentProxy"))
|
(not (obj/type-of? component "LibraryComponentProxy"))
|
||||||
(u/not-valid plugin-id :swapComponent "Component not valid")
|
(u/not-valid plugin-id :swapComponent "Component not valid")
|
||||||
|
|
||||||
@ -1507,12 +1524,12 @@
|
|||||||
(fn []
|
(fn []
|
||||||
(let [shape (u/locate-shape file-id page-id id)]
|
(let [shape (u/locate-shape file-id page-id id)]
|
||||||
(cond
|
(cond
|
||||||
(not (u/page-active? page-id))
|
|
||||||
(u/not-valid plugin-id :resetOverrides "Cannot modify a page that is not currently active")
|
|
||||||
|
|
||||||
(not (r/check-permission plugin-id "content:write"))
|
(not (r/check-permission plugin-id "content:write"))
|
||||||
(u/not-valid plugin-id :resetOverrides "Plugin doesn't have 'content:write' permission")
|
(u/not-valid plugin-id :resetOverrides "Plugin doesn't have 'content:write' permission")
|
||||||
|
|
||||||
|
(not (u/page-active? page-id))
|
||||||
|
(u/not-valid plugin-id :resetOverrides "Cannot modify a page that is not currently active")
|
||||||
|
|
||||||
(not (ctk/in-component-copy? shape))
|
(not (ctk/in-component-copy? shape))
|
||||||
(u/not-valid plugin-id :resetOverrides "The shape is not a component copy instance")
|
(u/not-valid plugin-id :resetOverrides "The shape is not a component copy instance")
|
||||||
|
|
||||||
@ -1527,6 +1544,9 @@
|
|||||||
(not (sm/validate ctse/schema:export value))
|
(not (sm/validate ctse/schema:export value))
|
||||||
(u/not-valid plugin-id :export value)
|
(u/not-valid plugin-id :export value)
|
||||||
|
|
||||||
|
(not (r/check-permission plugin-id "content:read"))
|
||||||
|
(u/not-valid plugin-id :export "Plugin doesn't have 'content:read' permission")
|
||||||
|
|
||||||
:else
|
:else
|
||||||
(if (and (contains? cf/flags :wasm-export)
|
(if (and (contains? cf/flags :wasm-export)
|
||||||
(contains? #{:jpeg :webp :png} (:type value :png)))
|
(contains? #{:jpeg :webp :png} (:type value :png)))
|
||||||
@ -1598,6 +1618,9 @@
|
|||||||
(not (sm/validate ctsi/schema:interaction interaction))
|
(not (sm/validate ctsi/schema:interaction interaction))
|
||||||
(u/not-valid plugin-id :addInteraction interaction)
|
(u/not-valid plugin-id :addInteraction interaction)
|
||||||
|
|
||||||
|
(not (r/check-permission plugin-id "content:write"))
|
||||||
|
(u/not-valid plugin-id :addInteraction "Plugin doesn't have 'content:write' permission")
|
||||||
|
|
||||||
:else
|
:else
|
||||||
(let [index (-> (u/locate-shape file-id page-id id) (:interactions []) count)]
|
(let [index (-> (u/locate-shape file-id page-id id) (:interactions []) count)]
|
||||||
(st/emit!
|
(st/emit!
|
||||||
@ -1611,6 +1634,9 @@
|
|||||||
(not (interaction-proxy? interaction))
|
(not (interaction-proxy? interaction))
|
||||||
(u/not-valid plugin-id :removeInteraction interaction)
|
(u/not-valid plugin-id :removeInteraction interaction)
|
||||||
|
|
||||||
|
(not (r/check-permission plugin-id "content:write"))
|
||||||
|
(u/not-valid plugin-id :removeInteraction "Plugin doesn't have 'content:write' permission")
|
||||||
|
|
||||||
:else
|
:else
|
||||||
(st/emit!
|
(st/emit!
|
||||||
(dwi/remove-interaction {:id id} (obj/get interaction "$index"))
|
(dwi/remove-interaction {:id id} (obj/get interaction "$index"))
|
||||||
@ -1691,8 +1717,14 @@
|
|||||||
:fn (fn [token attrs]
|
:fn (fn [token attrs]
|
||||||
(let [token (u/locate-token file-id (obj/get token "$set-id") (obj/get token "$id"))
|
(let [token (u/locate-token file-id (obj/get token "$set-id") (obj/get token "$id"))
|
||||||
kw-attrs (into #{} (map token-attr-plugin->token-attr attrs))]
|
kw-attrs (into #{} (map token-attr-plugin->token-attr attrs))]
|
||||||
(if (some #(not (token-attr? %)) kw-attrs)
|
(cond
|
||||||
|
(some #(not (token-attr? %)) kw-attrs)
|
||||||
(u/not-valid plugin-id :applyToken attrs)
|
(u/not-valid plugin-id :applyToken attrs)
|
||||||
|
|
||||||
|
(not (r/check-permission plugin-id "content:write"))
|
||||||
|
(u/not-valid plugin-id :applyToken "Plugin doesn't have 'content:write' permission")
|
||||||
|
|
||||||
|
:else
|
||||||
(st/emit!
|
(st/emit!
|
||||||
(-> (dwta/toggle-token {:token token
|
(-> (dwta/toggle-token {:token token
|
||||||
:attrs kw-attrs
|
:attrs kw-attrs
|
||||||
@ -1720,6 +1752,9 @@
|
|||||||
(not (string? value))
|
(not (string? value))
|
||||||
(u/not-valid plugin-id :value value)
|
(u/not-valid plugin-id :value value)
|
||||||
|
|
||||||
|
(not (r/check-permission plugin-id "content:write"))
|
||||||
|
(u/not-valid plugin-id :switchVariant "Plugin doesn't have 'content:write' permission")
|
||||||
|
|
||||||
:else
|
:else
|
||||||
(let [shape (u/locate-shape file-id page-id id)
|
(let [shape (u/locate-shape file-id page-id id)
|
||||||
component (u/locate-library-component file-id (:component-id shape))]
|
component (u/locate-library-component file-id (:component-id shape))]
|
||||||
@ -1733,6 +1768,9 @@
|
|||||||
(or (not (seq ids)) (not (every? uuid/parse* ids)))
|
(or (not (seq ids)) (not (every? uuid/parse* ids)))
|
||||||
(u/not-valid plugin-id :ids ids)
|
(u/not-valid plugin-id :ids ids)
|
||||||
|
|
||||||
|
(not (r/check-permission plugin-id "content:write"))
|
||||||
|
(u/not-valid plugin-id :combineAsVariants "Plugin doesn't have 'content:write' permission")
|
||||||
|
|
||||||
:else
|
:else
|
||||||
(let [;; Keep the input order (head shape first): it determines
|
(let [;; Keep the input order (head shape first): it determines
|
||||||
;; the order of the resulting variant components (see
|
;; the order of the resulting variant components (see
|
||||||
|
|||||||
@ -17,6 +17,7 @@
|
|||||||
[app.main.data.workspace.tokens.application :as dwta]
|
[app.main.data.workspace.tokens.application :as dwta]
|
||||||
[app.main.data.workspace.tokens.library-edit :as dwtl]
|
[app.main.data.workspace.tokens.library-edit :as dwtl]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
|
[app.plugins.register :as r]
|
||||||
[app.plugins.system-events :as se]
|
[app.plugins.system-events :as se]
|
||||||
[app.plugins.utils :as u]
|
[app.plugins.utils :as u]
|
||||||
[app.util.object :as obj]
|
[app.util.object :as obj]
|
||||||
@ -85,7 +86,11 @@
|
|||||||
|
|
||||||
(defn- apply-token-to-shapes
|
(defn- apply-token-to-shapes
|
||||||
[plugin-id file-id set-id id shape-ids attrs]
|
[plugin-id file-id set-id id shape-ids attrs]
|
||||||
|
(cond
|
||||||
|
(not (r/check-permission plugin-id "content:write"))
|
||||||
|
(u/not-valid plugin-id :applyToken "Plugin doesn't have 'content:write' permission")
|
||||||
|
|
||||||
|
:else
|
||||||
(let [token (u/locate-token file-id set-id id)]
|
(let [token (u/locate-token file-id set-id id)]
|
||||||
(if (some #(not (token-attr? %)) attrs)
|
(if (some #(not (token-attr? %)) attrs)
|
||||||
(u/not-valid plugin-id :applyToSelected attrs)
|
(u/not-valid plugin-id :applyToSelected attrs)
|
||||||
@ -94,7 +99,7 @@
|
|||||||
:attrs (into #{} (map token-attr-plugin->token-attr) attrs)
|
:attrs (into #{} (map token-attr-plugin->token-attr) attrs)
|
||||||
:shape-ids shape-ids
|
:shape-ids shape-ids
|
||||||
:expand-with-children false})
|
:expand-with-children false})
|
||||||
(se/add-event plugin-id))))))
|
(se/add-event plugin-id)))))))
|
||||||
|
|
||||||
(defn- typography-resolved-value->js
|
(defn- typography-resolved-value->js
|
||||||
"Converts a resolved typography composite (a Clojure map keyed by the
|
"Converts a resolved typography composite (a Clojure map keyed by the
|
||||||
@ -204,8 +209,13 @@
|
|||||||
(ctob/get-tokens set-id)))
|
(ctob/get-tokens set-id)))
|
||||||
:set
|
:set
|
||||||
(fn [_ value]
|
(fn [_ value]
|
||||||
|
(cond
|
||||||
|
(not (r/check-permission plugin-id "content:write"))
|
||||||
|
(u/not-valid plugin-id :name "Plugin doesn't have 'content:write' permission")
|
||||||
|
|
||||||
|
:else
|
||||||
(st/emit! (-> (dwtl/update-token set-id id {:name value})
|
(st/emit! (-> (dwtl/update-token set-id id {:name value})
|
||||||
(se/add-event plugin-id))))}
|
(se/add-event plugin-id)))))}
|
||||||
|
|
||||||
:type
|
:type
|
||||||
{:this true
|
{:this true
|
||||||
@ -230,11 +240,16 @@
|
|||||||
base))
|
base))
|
||||||
:set
|
:set
|
||||||
(fn [_ value]
|
(fn [_ value]
|
||||||
|
(cond
|
||||||
|
(not (r/check-permission plugin-id "content:write"))
|
||||||
|
(u/not-valid plugin-id :value "Plugin doesn't have 'content:write' permission")
|
||||||
|
|
||||||
|
:else
|
||||||
(let [token (u/locate-token file-id set-id id)
|
(let [token (u/locate-token file-id set-id id)
|
||||||
value (cond-> value
|
value (cond-> value
|
||||||
(= :font-family (:type token))
|
(= :font-family (:type token))
|
||||||
(ctob/convert-dtcg-font-family))]
|
(ctob/convert-dtcg-font-family))]
|
||||||
(st/emit! (dwtl/update-token set-id id {:value value}))))}
|
(st/emit! (dwtl/update-token set-id id {:value value})))))}
|
||||||
|
|
||||||
:resolvedValue
|
:resolvedValue
|
||||||
{:this true
|
{:this true
|
||||||
@ -265,11 +280,21 @@
|
|||||||
:schema cfo/schema:token-description
|
:schema cfo/schema:token-description
|
||||||
:set
|
:set
|
||||||
(fn [_ value]
|
(fn [_ value]
|
||||||
|
(cond
|
||||||
|
(not (r/check-permission plugin-id "content:write"))
|
||||||
|
(u/not-valid plugin-id :description "Plugin doesn't have 'content:write' permission")
|
||||||
|
|
||||||
|
:else
|
||||||
(st/emit! (-> (dwtl/update-token set-id id {:description value})
|
(st/emit! (-> (dwtl/update-token set-id id {:description value})
|
||||||
(se/add-event :plugin-id))))}
|
(se/add-event plugin-id)))))}
|
||||||
|
|
||||||
:duplicate
|
:duplicate
|
||||||
(fn []
|
(fn []
|
||||||
|
(cond
|
||||||
|
(not (r/check-permission plugin-id "content:write"))
|
||||||
|
(u/not-valid plugin-id :duplicate "Plugin doesn't have 'content:write' permission")
|
||||||
|
|
||||||
|
:else
|
||||||
;; TODO:
|
;; TODO:
|
||||||
;; - add function duplicate-token in tokens-lib, that allows to specify the new id
|
;; - add function duplicate-token in tokens-lib, that allows to specify the new id
|
||||||
;; - use this function in dwtl/duplicate-token
|
;; - use this function in dwtl/duplicate-token
|
||||||
@ -281,12 +306,17 @@
|
|||||||
:modified-at)))]
|
:modified-at)))]
|
||||||
(st/emit! (-> (dwtl/create-token set-id token')
|
(st/emit! (-> (dwtl/create-token set-id token')
|
||||||
(se/add-event plugin-id)))
|
(se/add-event plugin-id)))
|
||||||
(token-proxy plugin-id file-id set-id (:id token'))))
|
(token-proxy plugin-id file-id set-id (:id token')))))
|
||||||
|
|
||||||
:remove
|
:remove
|
||||||
(fn []
|
(fn []
|
||||||
|
(cond
|
||||||
|
(not (r/check-permission plugin-id "content:write"))
|
||||||
|
(u/not-valid plugin-id :remove "Plugin doesn't have 'content:write' permission")
|
||||||
|
|
||||||
|
:else
|
||||||
(st/emit! (-> (dwtl/delete-token set-id id)
|
(st/emit! (-> (dwtl/delete-token set-id id)
|
||||||
(se/add-event plugin-id))))
|
(se/add-event plugin-id)))))
|
||||||
|
|
||||||
:applyToShapes
|
:applyToShapes
|
||||||
{:enumerable false
|
{:enumerable false
|
||||||
@ -337,8 +367,13 @@
|
|||||||
id)
|
id)
|
||||||
:set
|
:set
|
||||||
(fn [_ name]
|
(fn [_ name]
|
||||||
|
(cond
|
||||||
|
(not (r/check-permission plugin-id "content:write"))
|
||||||
|
(u/not-valid plugin-id :name "Plugin doesn't have 'content:write' permission")
|
||||||
|
|
||||||
|
:else
|
||||||
(let [set (u/locate-token-set file-id id)]
|
(let [set (u/locate-token-set file-id id)]
|
||||||
(st/emit! (dwtl/rename-token-set set name))))}
|
(st/emit! (dwtl/rename-token-set set name)))))}
|
||||||
|
|
||||||
:active
|
:active
|
||||||
{:this true
|
{:this true
|
||||||
@ -351,13 +386,23 @@
|
|||||||
:schema ::sm/boolean
|
:schema ::sm/boolean
|
||||||
:set
|
:set
|
||||||
(fn [_ value]
|
(fn [_ value]
|
||||||
|
(cond
|
||||||
|
(not (r/check-permission plugin-id "content:write"))
|
||||||
|
(u/not-valid plugin-id :active "Plugin doesn't have 'content:write' permission")
|
||||||
|
|
||||||
|
:else
|
||||||
(let [set (u/locate-token-set file-id id)]
|
(let [set (u/locate-token-set file-id id)]
|
||||||
(st/emit! (dwtl/set-enabled-token-set (ctob/get-name set) value))))}
|
(st/emit! (dwtl/set-enabled-token-set (ctob/get-name set) value)))))}
|
||||||
|
|
||||||
:toggleActive
|
:toggleActive
|
||||||
(fn [_]
|
(fn []
|
||||||
|
(cond
|
||||||
|
(not (r/check-permission plugin-id "content:write"))
|
||||||
|
(u/not-valid plugin-id :toggleActive "Plugin doesn't have 'content:write' permission")
|
||||||
|
|
||||||
|
:else
|
||||||
(let [set (u/locate-token-set file-id id)]
|
(let [set (u/locate-token-set file-id id)]
|
||||||
(st/emit! (dwtl/toggle-token-set (ctob/get-name set)))))
|
(st/emit! (dwtl/toggle-token-set (ctob/get-name set))))))
|
||||||
|
|
||||||
:tokens
|
:tokens
|
||||||
{:this true
|
{:this true
|
||||||
@ -416,6 +461,11 @@
|
|||||||
(sm/update-properties assoc :decode/json cfo/convert-dtcg-token))]))
|
(sm/update-properties assoc :decode/json cfo/convert-dtcg-token))]))
|
||||||
:decode/options {:key-fn identity}
|
:decode/options {:key-fn identity}
|
||||||
:fn (fn [attrs]
|
:fn (fn [attrs]
|
||||||
|
(cond
|
||||||
|
(not (r/check-permission plugin-id "content:write"))
|
||||||
|
(u/not-valid plugin-id :addToken "Plugin doesn't have 'content:write' permission")
|
||||||
|
|
||||||
|
:else
|
||||||
(let [tokens-lib (u/locate-tokens-lib file-id)
|
(let [tokens-lib (u/locate-tokens-lib file-id)
|
||||||
token (ctob/make-token attrs)
|
token (ctob/make-token attrs)
|
||||||
;; Resolve against all tokens in the library (including those
|
;; Resolve against all tokens in the library (including those
|
||||||
@ -437,18 +487,28 @@
|
|||||||
(se/add-event plugin-id)))
|
(se/add-event plugin-id)))
|
||||||
(token-proxy plugin-id file-id id (:id token)))
|
(token-proxy plugin-id file-id id (:id token)))
|
||||||
(do (u/not-valid plugin-id :addToken (str errors))
|
(do (u/not-valid plugin-id :addToken (str errors))
|
||||||
nil))))}
|
nil)))))}
|
||||||
|
|
||||||
:duplicate
|
:duplicate
|
||||||
(fn []
|
(fn []
|
||||||
|
(cond
|
||||||
|
(not (r/check-permission plugin-id "content:write"))
|
||||||
|
(u/not-valid plugin-id :duplicate "Plugin doesn't have 'content:write' permission")
|
||||||
|
|
||||||
|
:else
|
||||||
(let [id-ref (atom nil)]
|
(let [id-ref (atom nil)]
|
||||||
(st/emit! (dwtl/duplicate-token-set id {:id-ref id-ref}))
|
(st/emit! (dwtl/duplicate-token-set id {:id-ref id-ref}))
|
||||||
(when (some? @id-ref)
|
(when (some? @id-ref)
|
||||||
(token-set-proxy plugin-id file-id @id-ref))))
|
(token-set-proxy plugin-id file-id @id-ref)))))
|
||||||
|
|
||||||
:remove
|
:remove
|
||||||
(fn []
|
(fn []
|
||||||
(st/emit! (dwtl/delete-token-set id))))))
|
(cond
|
||||||
|
(not (r/check-permission plugin-id "content:write"))
|
||||||
|
(u/not-valid plugin-id :remove "Plugin doesn't have 'content:write' permission")
|
||||||
|
|
||||||
|
:else
|
||||||
|
(st/emit! (dwtl/delete-token-set id)))))))
|
||||||
|
|
||||||
(defn token-theme-proxy? [p]
|
(defn token-theme-proxy? [p]
|
||||||
(obj/type-of? p "TokenThemeProxy"))
|
(obj/type-of? p "TokenThemeProxy"))
|
||||||
@ -501,8 +561,13 @@
|
|||||||
(:id theme)))
|
(:id theme)))
|
||||||
:set
|
:set
|
||||||
(fn [_ group]
|
(fn [_ group]
|
||||||
|
(cond
|
||||||
|
(not (r/check-permission plugin-id "content:write"))
|
||||||
|
(u/not-valid plugin-id :group "Plugin doesn't have 'content:write' permission")
|
||||||
|
|
||||||
|
:else
|
||||||
(let [theme (u/locate-token-theme file-id id)]
|
(let [theme (u/locate-token-theme file-id id)]
|
||||||
(st/emit! (dwtl/update-token-theme id (assoc theme :group group)))))}
|
(st/emit! (dwtl/update-token-theme id (assoc theme :group group))))))}
|
||||||
|
|
||||||
:name
|
:name
|
||||||
{:this true
|
{:this true
|
||||||
@ -517,9 +582,14 @@
|
|||||||
(:group theme)))
|
(:group theme)))
|
||||||
:set
|
:set
|
||||||
(fn [_ name]
|
(fn [_ name]
|
||||||
|
(cond
|
||||||
|
(not (r/check-permission plugin-id "content:write"))
|
||||||
|
(u/not-valid plugin-id :name "Plugin doesn't have 'content:write' permission")
|
||||||
|
|
||||||
|
:else
|
||||||
(let [theme (u/locate-token-theme file-id id)]
|
(let [theme (u/locate-token-theme file-id id)]
|
||||||
(when name
|
(when name
|
||||||
(st/emit! (dwtl/update-token-theme id (assoc theme :name name))))))}
|
(st/emit! (dwtl/update-token-theme id (assoc theme :name name)))))))}
|
||||||
|
|
||||||
:active
|
:active
|
||||||
{:this true
|
{:this true
|
||||||
@ -531,11 +601,21 @@
|
|||||||
:schema ::sm/boolean
|
:schema ::sm/boolean
|
||||||
:set
|
:set
|
||||||
(fn [_ value]
|
(fn [_ value]
|
||||||
(st/emit! (dwtl/set-token-theme-active id value)))}
|
(cond
|
||||||
|
(not (r/check-permission plugin-id "content:write"))
|
||||||
|
(u/not-valid plugin-id :active "Plugin doesn't have 'content:write' permission")
|
||||||
|
|
||||||
|
:else
|
||||||
|
(st/emit! (dwtl/set-token-theme-active id value))))}
|
||||||
|
|
||||||
:toggleActive
|
:toggleActive
|
||||||
(fn [_]
|
(fn []
|
||||||
(st/emit! (dwtl/toggle-token-theme-active id)))
|
(cond
|
||||||
|
(not (r/check-permission plugin-id "content:write"))
|
||||||
|
(u/not-valid plugin-id :toggleActive "Plugin doesn't have 'content:write' permission")
|
||||||
|
|
||||||
|
:else
|
||||||
|
(st/emit! (dwtl/toggle-token-theme-active id))))
|
||||||
|
|
||||||
:activeSets
|
:activeSets
|
||||||
{:this true
|
{:this true
|
||||||
@ -554,32 +634,52 @@
|
|||||||
{:enumerable false
|
{:enumerable false
|
||||||
:schema [:tuple [:or [:fn token-set-proxy?] ::sm/uuid]]
|
:schema [:tuple [:or [:fn token-set-proxy?] ::sm/uuid]]
|
||||||
:fn (fn [set-arg]
|
:fn (fn [set-arg]
|
||||||
|
(cond
|
||||||
|
(not (r/check-permission plugin-id "content:write"))
|
||||||
|
(u/not-valid plugin-id :addSet "Plugin doesn't have 'content:write' permission")
|
||||||
|
|
||||||
|
:else
|
||||||
(let [set-name (token-set-name (resolve-token-set file-id set-arg))
|
(let [set-name (token-set-name (resolve-token-set file-id set-arg))
|
||||||
theme (u/locate-token-theme file-id id)]
|
theme (u/locate-token-theme file-id id)]
|
||||||
(when (and set-name theme)
|
(when (and set-name theme)
|
||||||
(st/emit! (dwtl/update-token-theme id (ctob/enable-set theme set-name))))))}
|
(st/emit! (dwtl/update-token-theme id (ctob/enable-set theme set-name)))))))}
|
||||||
|
|
||||||
:removeSet
|
:removeSet
|
||||||
{:enumerable false
|
{:enumerable false
|
||||||
:schema [:tuple [:or [:fn token-set-proxy?] ::sm/uuid]]
|
:schema [:tuple [:or [:fn token-set-proxy?] ::sm/uuid]]
|
||||||
:fn (fn [set-arg]
|
:fn (fn [set-arg]
|
||||||
|
(cond
|
||||||
|
(not (r/check-permission plugin-id "content:write"))
|
||||||
|
(u/not-valid plugin-id :removeSet "Plugin doesn't have 'content:write' permission")
|
||||||
|
|
||||||
|
:else
|
||||||
(let [set-name (token-set-name (resolve-token-set file-id set-arg))
|
(let [set-name (token-set-name (resolve-token-set file-id set-arg))
|
||||||
theme (u/locate-token-theme file-id id)]
|
theme (u/locate-token-theme file-id id)]
|
||||||
(when (and set-name theme)
|
(when (and set-name theme)
|
||||||
(st/emit! (dwtl/update-token-theme id (ctob/disable-set theme set-name))))))}
|
(st/emit! (dwtl/update-token-theme id (ctob/disable-set theme set-name)))))))}
|
||||||
|
|
||||||
:duplicate
|
:duplicate
|
||||||
(fn []
|
(fn []
|
||||||
|
(cond
|
||||||
|
(not (r/check-permission plugin-id "content:write"))
|
||||||
|
(u/not-valid plugin-id :duplicate "Plugin doesn't have 'content:write' permission")
|
||||||
|
|
||||||
|
:else
|
||||||
(let [theme (u/locate-token-theme file-id id)
|
(let [theme (u/locate-token-theme file-id id)
|
||||||
theme' (ctob/make-token-theme (-> (datafy theme)
|
theme' (ctob/make-token-theme (-> (datafy theme)
|
||||||
(dissoc :id
|
(dissoc :id
|
||||||
:modified-at)))]
|
:modified-at)))]
|
||||||
(st/emit! (dwtl/create-token-theme theme'))
|
(st/emit! (dwtl/create-token-theme theme'))
|
||||||
(token-theme-proxy plugin-id file-id (:id theme'))))
|
(token-theme-proxy plugin-id file-id (:id theme')))))
|
||||||
|
|
||||||
:remove
|
:remove
|
||||||
(fn []
|
(fn []
|
||||||
(st/emit! (dwtl/delete-token-theme id)))))
|
(cond
|
||||||
|
(not (r/check-permission plugin-id "content:write"))
|
||||||
|
(u/not-valid plugin-id :remove "Plugin doesn't have 'content:write' permission")
|
||||||
|
|
||||||
|
:else
|
||||||
|
(st/emit! (dwtl/delete-token-theme id))))))
|
||||||
|
|
||||||
(defn tokens-catalog
|
(defn tokens-catalog
|
||||||
[plugin-id file-id]
|
[plugin-id file-id]
|
||||||
@ -619,9 +719,14 @@
|
|||||||
nil)
|
nil)
|
||||||
(sm/dissoc-key :id))]) ;; We don't allow plugins to set the id
|
(sm/dissoc-key :id))]) ;; We don't allow plugins to set the id
|
||||||
:fn (fn [attrs]
|
:fn (fn [attrs]
|
||||||
|
(cond
|
||||||
|
(not (r/check-permission plugin-id "content:write"))
|
||||||
|
(u/not-valid plugin-id :addTheme "Plugin doesn't have 'content:write' permission")
|
||||||
|
|
||||||
|
:else
|
||||||
(let [theme (ctob/make-token-theme attrs)]
|
(let [theme (ctob/make-token-theme attrs)]
|
||||||
(st/emit! (dwtl/create-token-theme theme))
|
(st/emit! (dwtl/create-token-theme theme))
|
||||||
(token-theme-proxy plugin-id file-id (:id theme))))}
|
(token-theme-proxy plugin-id file-id (:id theme)))))}
|
||||||
|
|
||||||
:addSet
|
:addSet
|
||||||
{:enumerable false
|
{:enumerable false
|
||||||
@ -638,6 +743,11 @@
|
|||||||
(sm/merge [:map [:active {:optional true} ::sm/boolean]]))]
|
(sm/merge [:map [:active {:optional true} ::sm/boolean]]))]
|
||||||
|
|
||||||
:fn (fn [attrs]
|
:fn (fn [attrs]
|
||||||
|
(cond
|
||||||
|
(not (r/check-permission plugin-id "content:write"))
|
||||||
|
(u/not-valid plugin-id :addSet "Plugin doesn't have 'content:write' permission")
|
||||||
|
|
||||||
|
:else
|
||||||
(let [active? (boolean (:active attrs))
|
(let [active? (boolean (:active attrs))
|
||||||
attrs (-> attrs
|
attrs (-> attrs
|
||||||
(dissoc :active)
|
(dissoc :active)
|
||||||
@ -652,7 +762,7 @@
|
|||||||
;; Pass the set name as `initial-name` so the proxy can resolve
|
;; Pass the set name as `initial-name` so the proxy can resolve
|
||||||
;; it immediately, before the async `st/emit!` above propagates
|
;; it immediately, before the async `st/emit!` above propagates
|
||||||
;; the new set into `@st/state`.
|
;; the new set into `@st/state`.
|
||||||
(token-set-proxy plugin-id file-id (ctob/get-id set) (ctob/get-name set))))}
|
(token-set-proxy plugin-id file-id (ctob/get-id set) (ctob/get-name set)))))}
|
||||||
|
|
||||||
:getThemeById
|
:getThemeById
|
||||||
{:enumerable false
|
{:enumerable false
|
||||||
|
|||||||
40
frontend/test/frontend_tests/plugins/flex_test.cljs
Normal file
40
frontend/test/frontend_tests/plugins/flex_test.cljs
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
;; 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 Sucursal en España SL
|
||||||
|
|
||||||
|
(ns frontend-tests.plugins.flex-test
|
||||||
|
(:require
|
||||||
|
[app.common.types.shape.layout :as ctl]
|
||||||
|
[app.common.uuid :as uuid]
|
||||||
|
[app.main.store :as st]
|
||||||
|
[app.plugins.flex :as flex]
|
||||||
|
[app.plugins.register :as r]
|
||||||
|
[app.plugins.shape :as shape]
|
||||||
|
[app.plugins.utils :as u]
|
||||||
|
[cljs.test :as t :include-macros true]
|
||||||
|
[frontend-tests.helpers.mock :as mock]))
|
||||||
|
|
||||||
|
;; ---------------------------------------------------------------------------
|
||||||
|
;; Permission checks (T9-F-05)
|
||||||
|
;; ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
(t/deftest flex-remove-checks-permission
|
||||||
|
(let [plugin-id "test-plugin"
|
||||||
|
file-id (uuid/next)
|
||||||
|
page-id (uuid/next)
|
||||||
|
id (uuid/next)
|
||||||
|
errors (atom [])]
|
||||||
|
(with-redefs [r/check-permission (constantly false)
|
||||||
|
u/not-valid (mock/stub (fn [pid prop msg] (swap! errors conj [pid prop msg])))
|
||||||
|
st/emit! mock/noop]
|
||||||
|
(let [proxy (flex/flex-layout-proxy plugin-id file-id page-id id)]
|
||||||
|
(.remove proxy)
|
||||||
|
(t/is (= 1 (count @errors)))
|
||||||
|
(t/is (= [plugin-id :remove "Plugin doesn't have 'content:write' permission"]
|
||||||
|
(first @errors)))))))
|
||||||
|
|
||||||
|
;; TODO: flex-append-child-checks-permission test requires more complex mocking
|
||||||
|
;; of u/locate-objects, u/locate-shape, ctl/reverse?, etc. The permission check
|
||||||
|
;; is in place at flex.cljs line 358.
|
||||||
@ -6,8 +6,11 @@
|
|||||||
|
|
||||||
(ns frontend-tests.plugins.library-test
|
(ns frontend-tests.plugins.library-test
|
||||||
(:require
|
(:require
|
||||||
|
[app.common.types.component :as ctk]
|
||||||
|
[app.common.uuid :as uuid]
|
||||||
[app.main.data.workspace.libraries :as dwl]
|
[app.main.data.workspace.libraries :as dwl]
|
||||||
[app.main.data.workspace.texts :as dwt]
|
[app.main.data.workspace.texts :as dwt]
|
||||||
|
[app.main.data.workspace.variants :as dwv]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.plugins.library :as library]
|
[app.plugins.library :as library]
|
||||||
[app.plugins.register :as r]
|
[app.plugins.register :as r]
|
||||||
@ -93,3 +96,112 @@
|
|||||||
(t/is (contains? (:color @captured) :image))
|
(t/is (contains? (:color @captured) :image))
|
||||||
(t/is (not (contains? (:color @captured) :color)))
|
(t/is (not (contains? (:color @captured) :color)))
|
||||||
(t/is (not (contains? (:color @captured) :gradient))))))
|
(t/is (not (contains? (:color @captured) :gradient))))))
|
||||||
|
|
||||||
|
;; ---------------------------------------------------------------------------
|
||||||
|
;; Permission checks (T9-F-02)
|
||||||
|
;; ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
(t/deftest variant-add-variant-checks-permission
|
||||||
|
(let [plugin-id "test-plugin"
|
||||||
|
file-id (uuid/next)
|
||||||
|
id (uuid/next)
|
||||||
|
errors (atom [])]
|
||||||
|
(with-redefs [r/check-permission (constantly false)
|
||||||
|
u/not-valid (mock/stub (fn [pid prop msg] (swap! errors conj [pid prop msg])))
|
||||||
|
st/emit! mock/noop]
|
||||||
|
(let [proxy (library/variant-proxy plugin-id file-id id)]
|
||||||
|
(.addVariant proxy)
|
||||||
|
(t/is (= 1 (count @errors)))
|
||||||
|
(t/is (= [plugin-id :addVariant "Plugin doesn't have 'library:write' permission"]
|
||||||
|
(first @errors)))))))
|
||||||
|
|
||||||
|
(t/deftest variant-add-property-checks-permission
|
||||||
|
(let [plugin-id "test-plugin"
|
||||||
|
file-id (uuid/next)
|
||||||
|
id (uuid/next)
|
||||||
|
errors (atom [])]
|
||||||
|
(with-redefs [r/check-permission (constantly false)
|
||||||
|
u/not-valid (mock/stub (fn [pid prop msg] (swap! errors conj [pid prop msg])))
|
||||||
|
st/emit! mock/noop]
|
||||||
|
(let [proxy (library/variant-proxy plugin-id file-id id)]
|
||||||
|
(.addProperty proxy)
|
||||||
|
(t/is (= 1 (count @errors)))
|
||||||
|
(t/is (= [plugin-id :addProperty "Plugin doesn't have 'library:write' permission"]
|
||||||
|
(first @errors)))))))
|
||||||
|
|
||||||
|
(t/deftest variant-remove-property-checks-permission
|
||||||
|
(let [plugin-id "test-plugin"
|
||||||
|
file-id (uuid/next)
|
||||||
|
id (uuid/next)
|
||||||
|
errors (atom [])]
|
||||||
|
(with-redefs [r/check-permission (constantly false)
|
||||||
|
u/not-valid (mock/stub (fn [pid prop msg] (swap! errors conj [pid prop msg])))
|
||||||
|
library/get-variant-components (constantly [{:variant-properties [{:name "color" :value "red"}]}])
|
||||||
|
st/emit! mock/noop]
|
||||||
|
(let [proxy (library/variant-proxy plugin-id file-id id)]
|
||||||
|
(.removeProperty proxy 0)
|
||||||
|
(t/is (= 1 (count @errors)))
|
||||||
|
(t/is (= [plugin-id :removeProperty "Plugin doesn't have 'library:write' permission"]
|
||||||
|
(first @errors)))))))
|
||||||
|
|
||||||
|
(t/deftest variant-rename-property-checks-permission
|
||||||
|
(let [plugin-id "test-plugin"
|
||||||
|
file-id (uuid/next)
|
||||||
|
id (uuid/next)
|
||||||
|
errors (atom [])]
|
||||||
|
(with-redefs [r/check-permission (constantly false)
|
||||||
|
u/not-valid (mock/stub (fn [pid prop msg] (swap! errors conj [pid prop msg])))
|
||||||
|
library/get-variant-components (constantly [{:variant-properties [{:name "color" :value "red"}]}])
|
||||||
|
st/emit! mock/noop]
|
||||||
|
(let [proxy (library/variant-proxy plugin-id file-id id)]
|
||||||
|
(.renameProperty proxy 0 "newName")
|
||||||
|
(t/is (= 1 (count @errors)))
|
||||||
|
(t/is (= [plugin-id :renameProperty "Plugin doesn't have 'library:write' permission"]
|
||||||
|
(first @errors)))))))
|
||||||
|
|
||||||
|
(t/deftest component-transform-in-variant-checks-permission
|
||||||
|
(let [plugin-id "test-plugin"
|
||||||
|
file-id (uuid/next)
|
||||||
|
id (uuid/next)
|
||||||
|
errors (atom [])]
|
||||||
|
(with-redefs [r/check-permission (constantly false)
|
||||||
|
u/not-valid (mock/stub (fn [pid prop msg] (swap! errors conj [pid prop msg])))
|
||||||
|
u/locate-library-component (constantly {:id id :main-instance-id id})
|
||||||
|
ctk/is-variant? (constantly false)
|
||||||
|
st/emit! mock/noop]
|
||||||
|
(let [proxy (library/lib-component-proxy plugin-id file-id id)]
|
||||||
|
(.transformInVariant proxy)
|
||||||
|
(t/is (= 1 (count @errors)))
|
||||||
|
(t/is (= [plugin-id :transformInVariant "Plugin doesn't have 'library:write' permission"]
|
||||||
|
(first @errors)))))))
|
||||||
|
|
||||||
|
(t/deftest component-add-variant-checks-permission
|
||||||
|
(let [plugin-id "test-plugin"
|
||||||
|
file-id (uuid/next)
|
||||||
|
id (uuid/next)
|
||||||
|
errors (atom [])]
|
||||||
|
(with-redefs [r/check-permission (constantly false)
|
||||||
|
u/not-valid (mock/stub (fn [pid prop msg] (swap! errors conj [pid prop msg])))
|
||||||
|
u/locate-library-component (constantly {:id id :main-instance-id id})
|
||||||
|
ctk/is-variant? (constantly true)
|
||||||
|
st/emit! mock/noop]
|
||||||
|
(let [proxy (library/lib-component-proxy plugin-id file-id id)]
|
||||||
|
(.addVariant proxy)
|
||||||
|
(t/is (= 1 (count @errors)))
|
||||||
|
(t/is (= [plugin-id :addVariant "Plugin doesn't have 'library:write' permission"]
|
||||||
|
(first @errors)))))))
|
||||||
|
|
||||||
|
(t/deftest component-set-variant-property-checks-permission
|
||||||
|
(let [plugin-id "test-plugin"
|
||||||
|
file-id (uuid/next)
|
||||||
|
id (uuid/next)
|
||||||
|
errors (atom [])]
|
||||||
|
(with-redefs [r/check-permission (constantly false)
|
||||||
|
u/not-valid (mock/stub (fn [pid prop msg] (swap! errors conj [pid prop msg])))
|
||||||
|
u/locate-library-component (constantly {:id id :variant-properties [{:name "color"}]})
|
||||||
|
st/emit! mock/noop]
|
||||||
|
(let [proxy (library/lib-component-proxy plugin-id file-id id)]
|
||||||
|
(.setVariantProperty proxy 0 "red")
|
||||||
|
(t/is (= 1 (count @errors)))
|
||||||
|
(t/is (= [plugin-id :setVariantProperty "Plugin doesn't have 'library:write' permission"]
|
||||||
|
(first @errors)))))))
|
||||||
|
|||||||
@ -9,12 +9,17 @@
|
|||||||
[app.common.test-helpers.files :as cthf]
|
[app.common.test-helpers.files :as cthf]
|
||||||
[app.common.test-helpers.ids-map :as thi]
|
[app.common.test-helpers.ids-map :as thi]
|
||||||
[app.common.test-helpers.shapes :as cths]
|
[app.common.test-helpers.shapes :as cths]
|
||||||
|
[app.common.uuid :as uuid]
|
||||||
[app.main.data.workspace.pages :as dwpg]
|
[app.main.data.workspace.pages :as dwpg]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.plugins.api :as api]
|
[app.plugins.api :as api]
|
||||||
|
[app.plugins.page :as page]
|
||||||
|
[app.plugins.register :as r]
|
||||||
[app.plugins.shape :as shape]
|
[app.plugins.shape :as shape]
|
||||||
|
[app.plugins.utils :as u]
|
||||||
[app.util.object :as obj]
|
[app.util.object :as obj]
|
||||||
[cljs.test :as t :include-macros true]
|
[cljs.test :as t :include-macros true]
|
||||||
|
[frontend-tests.helpers.mock :as mock]
|
||||||
[frontend-tests.helpers.state :as ths]
|
[frontend-tests.helpers.state :as ths]
|
||||||
[frontend-tests.helpers.wasm :as thw]
|
[frontend-tests.helpers.wasm :as thw]
|
||||||
[potok.v2.core :as ptk]))
|
[potok.v2.core :as ptk]))
|
||||||
@ -151,3 +156,85 @@
|
|||||||
(done))))
|
(done))))
|
||||||
(mock-page-initialized store page2-id))
|
(mock-page-initialized store page2-id))
|
||||||
0))))
|
0))))
|
||||||
|
|
||||||
|
;; ---------------------------------------------------------------------------
|
||||||
|
;; Permission checks (T9-F-03)
|
||||||
|
;; ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
(t/deftest flow-name-setter-checks-permission
|
||||||
|
(let [plugin-id "test-plugin"
|
||||||
|
file-id (uuid/next)
|
||||||
|
page-id (uuid/next)
|
||||||
|
flow-id (uuid/next)
|
||||||
|
errors (atom [])]
|
||||||
|
(with-redefs [r/check-permission (constantly false)
|
||||||
|
u/not-valid (mock/stub (fn [pid prop msg] (swap! errors conj [pid prop msg])))
|
||||||
|
st/emit! mock/noop]
|
||||||
|
(let [proxy (page/flow-proxy plugin-id file-id page-id flow-id)]
|
||||||
|
(set! (.-name proxy) "new-name")
|
||||||
|
(t/is (= 1 (count @errors)))
|
||||||
|
(t/is (= [plugin-id :name "Plugin doesn't have 'content:write' permission"]
|
||||||
|
(first @errors)))))))
|
||||||
|
|
||||||
|
(t/deftest flow-starting-board-setter-checks-permission
|
||||||
|
(let [plugin-id "test-plugin"
|
||||||
|
file-id (uuid/next)
|
||||||
|
page-id (uuid/next)
|
||||||
|
flow-id (uuid/next)
|
||||||
|
errors (atom [])]
|
||||||
|
(with-redefs [r/check-permission (constantly false)
|
||||||
|
u/not-valid (mock/stub (fn [pid prop msg] (swap! errors conj [pid prop msg])))
|
||||||
|
st/emit! mock/noop
|
||||||
|
shape/shape-proxy? (constantly true)]
|
||||||
|
(let [proxy (page/flow-proxy plugin-id file-id page-id flow-id)]
|
||||||
|
(set! (.-startingBoard proxy) #js {})
|
||||||
|
(t/is (= 1 (count @errors)))
|
||||||
|
(t/is (= [plugin-id :startingBoard "Plugin doesn't have 'content:write' permission"]
|
||||||
|
(first @errors)))))))
|
||||||
|
|
||||||
|
(t/deftest flow-remove-checks-permission
|
||||||
|
(let [plugin-id "test-plugin"
|
||||||
|
file-id (uuid/next)
|
||||||
|
page-id (uuid/next)
|
||||||
|
flow-id (uuid/next)
|
||||||
|
errors (atom [])]
|
||||||
|
(with-redefs [r/check-permission (constantly false)
|
||||||
|
u/not-valid (mock/stub (fn [pid prop msg] (swap! errors conj [pid prop msg])))
|
||||||
|
st/emit! mock/noop]
|
||||||
|
(let [proxy (page/flow-proxy plugin-id file-id page-id flow-id)]
|
||||||
|
(.remove proxy)
|
||||||
|
(t/is (= 1 (count @errors)))
|
||||||
|
(t/is (= [plugin-id :remove "Plugin doesn't have 'content:write' permission"]
|
||||||
|
(first @errors)))))))
|
||||||
|
|
||||||
|
(t/deftest create-flow-checks-permission
|
||||||
|
(let [plugin-id "test-plugin"
|
||||||
|
file-id (uuid/next)
|
||||||
|
page-id (uuid/next)
|
||||||
|
errors (atom [])]
|
||||||
|
(with-redefs [r/check-permission (constantly false)
|
||||||
|
u/not-valid (mock/stub (fn [pid prop msg] (swap! errors conj [pid prop msg])))
|
||||||
|
st/emit! mock/noop
|
||||||
|
shape/shape-proxy? (constantly true)]
|
||||||
|
(let [proxy (page/page-proxy plugin-id file-id page-id)
|
||||||
|
frame #js {"$id" (uuid/next)}]
|
||||||
|
(.createFlow proxy "flow-name" frame)
|
||||||
|
(t/is (= 1 (count @errors)))
|
||||||
|
(t/is (= [plugin-id :createFlow "Plugin doesn't have 'content:write' permission"]
|
||||||
|
(first @errors)))))))
|
||||||
|
|
||||||
|
(t/deftest remove-flow-checks-permission
|
||||||
|
(let [plugin-id "test-plugin"
|
||||||
|
file-id (uuid/next)
|
||||||
|
page-id (uuid/next)
|
||||||
|
flow-id (uuid/next)
|
||||||
|
errors (atom [])]
|
||||||
|
(with-redefs [r/check-permission (constantly false)
|
||||||
|
u/not-valid (mock/stub (fn [pid prop msg] (swap! errors conj [pid prop msg])))
|
||||||
|
st/emit! mock/noop
|
||||||
|
page/flow-proxy? (constantly true)]
|
||||||
|
(let [proxy (page/page-proxy plugin-id file-id page-id)]
|
||||||
|
(.removeFlow proxy (page/flow-proxy plugin-id file-id page-id flow-id))
|
||||||
|
(t/is (= 1 (count @errors)))
|
||||||
|
(t/is (= [plugin-id :removeFlow "Plugin doesn't have 'content:write' permission"]
|
||||||
|
(first @errors)))))))
|
||||||
|
|||||||
@ -11,10 +11,15 @@
|
|||||||
[app.common.types.component :as ctk]
|
[app.common.types.component :as ctk]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.main.data.workspace :as dw]
|
[app.main.data.workspace :as dw]
|
||||||
|
[app.main.data.workspace.interactions :as dwi]
|
||||||
|
[app.main.data.workspace.libraries :as dwl]
|
||||||
|
[app.main.data.workspace.texts :as dwt]
|
||||||
|
[app.main.data.workspace.tokens.application :as dwta]
|
||||||
[app.main.data.workspace.variants :as dwv]
|
[app.main.data.workspace.variants :as dwv]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.plugins.api :as api]
|
[app.plugins.api :as api]
|
||||||
[app.plugins.public-utils :as public-utils]
|
[app.plugins.public-utils :as public-utils]
|
||||||
|
[app.plugins.register :as r]
|
||||||
[app.plugins.shape :as shape]
|
[app.plugins.shape :as shape]
|
||||||
[app.plugins.utils :as u]
|
[app.plugins.utils :as u]
|
||||||
[cljs.test :as t :include-macros true]
|
[cljs.test :as t :include-macros true]
|
||||||
@ -204,3 +209,202 @@
|
|||||||
(t/deftest group-empty-input-returns-nil
|
(t/deftest group-empty-input-returns-nil
|
||||||
(let [context (api/create-context plugin-id)]
|
(let [context (api/create-context plugin-id)]
|
||||||
(t/is (nil? (.group context #js [])))))
|
(t/is (nil? (.group context #js [])))))
|
||||||
|
|
||||||
|
;; ---------------------------------------------------------------------------
|
||||||
|
;; Permission checks (T9-F-04)
|
||||||
|
;; ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
(t/deftest commit-fills-text-shape-checks-permission
|
||||||
|
(let [plugin-id "test-plugin"
|
||||||
|
file-id (uuid/next)
|
||||||
|
page-id (uuid/next)
|
||||||
|
shape-id (uuid/next)
|
||||||
|
errors (atom [])]
|
||||||
|
(with-redefs [u/proxy->shape (constantly {:id shape-id :type :text})
|
||||||
|
u/not-valid (mock/stub (fn [pid prop msg] (swap! errors conj [pid prop msg])))
|
||||||
|
r/check-permission (constantly false)
|
||||||
|
st/emit! mock/noop]
|
||||||
|
(let [proxy (shape/shape-proxy plugin-id file-id page-id shape-id)]
|
||||||
|
(set! (.-fills proxy) #js [#js {:fillColor "#ff0000" :fillOpacity 1}])
|
||||||
|
(t/is (= 1 (count @errors)))
|
||||||
|
(t/is (= [plugin-id :fills "Plugin doesn't have 'content:write' permission"]
|
||||||
|
(first @errors)))))))
|
||||||
|
|
||||||
|
(t/deftest interaction-trigger-checks-permission
|
||||||
|
(let [plugin-id "test-plugin"
|
||||||
|
file-id (uuid/next)
|
||||||
|
page-id (uuid/next)
|
||||||
|
shape-id (uuid/next)
|
||||||
|
errors (atom [])]
|
||||||
|
(with-redefs [u/not-valid (mock/stub (fn [pid prop msg] (swap! errors conj [pid prop msg])))
|
||||||
|
r/check-permission (constantly false)
|
||||||
|
st/emit! mock/noop]
|
||||||
|
(let [inter (shape/interaction-proxy plugin-id file-id page-id shape-id 0)]
|
||||||
|
(set! (.-trigger inter) "click")
|
||||||
|
(t/is (= 1 (count @errors)))
|
||||||
|
(t/is (= [plugin-id :trigger "Plugin doesn't have 'content:write' permission"]
|
||||||
|
(first @errors)))))))
|
||||||
|
|
||||||
|
(t/deftest interaction-delay-checks-permission
|
||||||
|
(let [plugin-id "test-plugin"
|
||||||
|
file-id (uuid/next)
|
||||||
|
page-id (uuid/next)
|
||||||
|
shape-id (uuid/next)
|
||||||
|
errors (atom [])]
|
||||||
|
(with-redefs [u/not-valid (mock/stub (fn [pid prop msg] (swap! errors conj [pid prop msg])))
|
||||||
|
r/check-permission (constantly false)
|
||||||
|
st/emit! mock/noop]
|
||||||
|
(let [inter (shape/interaction-proxy plugin-id file-id page-id shape-id 0)]
|
||||||
|
(set! (.-delay inter) 100)
|
||||||
|
(t/is (= 1 (count @errors)))
|
||||||
|
(t/is (= [plugin-id :delay "Plugin doesn't have 'content:write' permission"]
|
||||||
|
(first @errors)))))))
|
||||||
|
|
||||||
|
(t/deftest interaction-action-checks-permission
|
||||||
|
(let [plugin-id "test-plugin"
|
||||||
|
file-id (uuid/next)
|
||||||
|
page-id (uuid/next)
|
||||||
|
shape-id (uuid/next)
|
||||||
|
errors (atom [])]
|
||||||
|
(with-redefs [u/proxy->interaction (constantly {:event-type :click :delay 0 :action-type :open-url :url "https://example.com"})
|
||||||
|
u/not-valid (mock/stub (fn [pid prop msg] (swap! errors conj [pid prop msg])))
|
||||||
|
r/check-permission (constantly false)
|
||||||
|
st/emit! mock/noop]
|
||||||
|
(let [inter (shape/interaction-proxy plugin-id file-id page-id shape-id 0)]
|
||||||
|
(set! (.-action inter) #js {:type "open-url" :url "https://example.com"})
|
||||||
|
(t/is (= 1 (count @errors)))
|
||||||
|
(t/is (= [plugin-id :action "Plugin doesn't have 'content:write' permission"]
|
||||||
|
(first @errors)))))))
|
||||||
|
|
||||||
|
(t/deftest interaction-remove-checks-permission
|
||||||
|
(let [plugin-id "test-plugin"
|
||||||
|
file-id (uuid/next)
|
||||||
|
page-id (uuid/next)
|
||||||
|
shape-id (uuid/next)
|
||||||
|
errors (atom [])]
|
||||||
|
(with-redefs [u/not-valid (mock/stub (fn [pid prop msg] (swap! errors conj [pid prop msg])))
|
||||||
|
r/check-permission (constantly false)
|
||||||
|
st/emit! mock/noop]
|
||||||
|
(let [inter (shape/interaction-proxy plugin-id file-id page-id shape-id 0)]
|
||||||
|
(.remove inter)
|
||||||
|
(t/is (= 1 (count @errors)))
|
||||||
|
(t/is (= [plugin-id :remove "Plugin doesn't have 'content:write' permission"]
|
||||||
|
(first @errors)))))))
|
||||||
|
|
||||||
|
(t/deftest add-interaction-checks-permission
|
||||||
|
(let [plugin-id "test-plugin"
|
||||||
|
file-id (uuid/next)
|
||||||
|
page-id (uuid/next)
|
||||||
|
shape-id (uuid/next)
|
||||||
|
errors (atom [])]
|
||||||
|
(with-redefs [u/locate-shape (constantly {:id shape-id})
|
||||||
|
u/not-valid (mock/stub (fn [pid prop msg] (swap! errors conj [pid prop msg])))
|
||||||
|
r/check-permission (constantly false)
|
||||||
|
st/emit! mock/noop]
|
||||||
|
(let [proxy (shape/shape-proxy plugin-id file-id page-id shape-id)]
|
||||||
|
(.addInteraction proxy "click" #js {:type "open-url" :url "https://example.com"})
|
||||||
|
(t/is (= 1 (count @errors)))
|
||||||
|
(t/is (= [plugin-id :addInteraction "Plugin doesn't have 'content:write' permission"]
|
||||||
|
(first @errors)))))))
|
||||||
|
|
||||||
|
(t/deftest remove-interaction-checks-permission
|
||||||
|
(let [plugin-id "test-plugin"
|
||||||
|
file-id (uuid/next)
|
||||||
|
page-id (uuid/next)
|
||||||
|
shape-id (uuid/next)
|
||||||
|
errors (atom [])]
|
||||||
|
(with-redefs [u/not-valid (mock/stub (fn [pid prop msg] (swap! errors conj [pid prop msg])))
|
||||||
|
r/check-permission (constantly false)
|
||||||
|
st/emit! mock/noop]
|
||||||
|
(let [proxy (shape/shape-proxy plugin-id file-id page-id shape-id)
|
||||||
|
inter (shape/interaction-proxy plugin-id file-id page-id shape-id 0)]
|
||||||
|
(.removeInteraction proxy inter)
|
||||||
|
(t/is (= 1 (count @errors)))
|
||||||
|
(t/is (= [plugin-id :removeInteraction "Plugin doesn't have 'content:write' permission"]
|
||||||
|
(first @errors)))))))
|
||||||
|
|
||||||
|
(t/deftest detach-checks-permission
|
||||||
|
(let [plugin-id "test-plugin"
|
||||||
|
file-id (uuid/next)
|
||||||
|
page-id (uuid/next)
|
||||||
|
shape-id (uuid/next)
|
||||||
|
errors (atom [])]
|
||||||
|
(with-redefs [u/page-active? (constantly true)
|
||||||
|
u/not-valid (mock/stub (fn [pid prop msg] (swap! errors conj [pid prop msg])))
|
||||||
|
r/check-permission (constantly false)
|
||||||
|
st/emit! mock/noop]
|
||||||
|
(let [proxy (shape/shape-proxy plugin-id file-id page-id shape-id)]
|
||||||
|
(.detach proxy)
|
||||||
|
(t/is (= 1 (count @errors)))
|
||||||
|
(t/is (= [plugin-id :detach "Plugin doesn't have 'content:write' permission"]
|
||||||
|
(first @errors)))))))
|
||||||
|
|
||||||
|
(t/deftest export-checks-permission
|
||||||
|
(let [plugin-id "test-plugin"
|
||||||
|
file-id (uuid/next)
|
||||||
|
page-id (uuid/next)
|
||||||
|
shape-id (uuid/next)
|
||||||
|
errors (atom [])]
|
||||||
|
(with-redefs [u/not-valid (mock/stub (fn [pid prop msg] (swap! errors conj [pid prop msg])))
|
||||||
|
r/check-permission (constantly false)]
|
||||||
|
(let [proxy (shape/shape-proxy plugin-id file-id page-id shape-id)]
|
||||||
|
(.export proxy #js {:type "png" :scale 1})
|
||||||
|
(t/is (= 1 (count @errors)))
|
||||||
|
(t/is (= [plugin-id :export "Plugin doesn't have 'content:read' permission"]
|
||||||
|
(first @errors)))))))
|
||||||
|
|
||||||
|
(t/deftest apply-token-checks-permission
|
||||||
|
(let [plugin-id "test-plugin"
|
||||||
|
file-id (uuid/next)
|
||||||
|
page-id (uuid/next)
|
||||||
|
shape-id (uuid/next)
|
||||||
|
set-id (uuid/next)
|
||||||
|
token-id (uuid/next)
|
||||||
|
errors (atom [])]
|
||||||
|
(with-redefs [u/locate-token (constantly {:id token-id :name "test" :type :color})
|
||||||
|
shape/token-proxy? (constantly true)
|
||||||
|
u/not-valid (mock/stub (fn [pid prop msg] (swap! errors conj [pid prop msg])))
|
||||||
|
r/check-permission (constantly false)
|
||||||
|
st/emit! mock/noop]
|
||||||
|
(let [proxy (shape/shape-proxy plugin-id file-id page-id shape-id)
|
||||||
|
token #js {"$set-id" (str set-id) "$id" (str token-id)}]
|
||||||
|
(.applyToken proxy token #js [])
|
||||||
|
(t/is (= 1 (count @errors)))
|
||||||
|
(t/is (= [plugin-id :applyToken "Plugin doesn't have 'content:write' permission"]
|
||||||
|
(first @errors)))))))
|
||||||
|
|
||||||
|
(t/deftest switch-variant-checks-permission
|
||||||
|
(let [plugin-id "test-plugin"
|
||||||
|
file-id (uuid/next)
|
||||||
|
page-id (uuid/next)
|
||||||
|
shape-id (uuid/next)
|
||||||
|
errors (atom [])]
|
||||||
|
(with-redefs [u/locate-shape (constantly {:id shape-id :component-id shape-id})
|
||||||
|
u/locate-library-component (constantly {:id (uuid/next)})
|
||||||
|
u/not-valid (mock/stub (fn [pid prop msg] (swap! errors conj [pid prop msg])))
|
||||||
|
r/check-permission (constantly false)
|
||||||
|
st/emit! mock/noop]
|
||||||
|
(let [proxy (shape/shape-proxy plugin-id file-id page-id shape-id)]
|
||||||
|
(.switchVariant proxy 0 "value")
|
||||||
|
(t/is (= 1 (count @errors)))
|
||||||
|
(t/is (= [plugin-id :switchVariant "Plugin doesn't have 'content:write' permission"]
|
||||||
|
(first @errors)))))))
|
||||||
|
|
||||||
|
(t/deftest combine-as-variants-checks-permission
|
||||||
|
(let [plugin-id "test-plugin"
|
||||||
|
file-id (uuid/next)
|
||||||
|
page-id (uuid/next)
|
||||||
|
shape-id (uuid/next)
|
||||||
|
other-id (uuid/next)
|
||||||
|
errors (atom [])]
|
||||||
|
(with-redefs [u/locate-shape (fn [_file _page id] {:id id :component-id id})
|
||||||
|
u/locate-library-component (constantly {:id (uuid/next)})
|
||||||
|
ctk/is-variant? (constantly false)
|
||||||
|
u/not-valid (mock/stub (fn [pid prop msg] (swap! errors conj [pid prop msg])))
|
||||||
|
r/check-permission (constantly false)
|
||||||
|
st/emit! mock/noop]
|
||||||
|
(let [proxy (shape/shape-proxy plugin-id file-id page-id shape-id)]
|
||||||
|
(.combineAsVariants proxy #js [(str other-id)])
|
||||||
|
(t/is (= 1 (count @errors)))
|
||||||
|
(t/is (= [plugin-id :combineAsVariants "Plugin doesn't have 'content:write' permission"]
|
||||||
|
(first @errors)))))))
|
||||||
|
|||||||
@ -16,6 +16,7 @@
|
|||||||
[app.main.data.workspace.tokens.library-edit :as dwtl]
|
[app.main.data.workspace.tokens.library-edit :as dwtl]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.plugins.api :as api]
|
[app.plugins.api :as api]
|
||||||
|
[app.plugins.register :as r]
|
||||||
[app.plugins.tokens :as ptok]
|
[app.plugins.tokens :as ptok]
|
||||||
[app.plugins.utils :as u]
|
[app.plugins.utils :as u]
|
||||||
[cljs.test :as t :include-macros true]
|
[cljs.test :as t :include-macros true]
|
||||||
@ -236,7 +237,8 @@
|
|||||||
set-id (cthi/new-id! :set)
|
set-id (cthi/new-id! :set)
|
||||||
dup-id (cthi/new-id! :dup)
|
dup-id (cthi/new-id! :dup)
|
||||||
proxy (ptok/token-set-proxy "plugin-id" file-id set-id)]
|
proxy (ptok/token-set-proxy "plugin-id" file-id set-id)]
|
||||||
(with-redefs [dwtl/duplicate-token-set
|
(with-redefs [r/check-permission (constantly true)
|
||||||
|
dwtl/duplicate-token-set
|
||||||
(mock/stub (fn [id {:keys [id-ref]}]
|
(mock/stub (fn [id {:keys [id-ref]}]
|
||||||
(t/is (= set-id id))
|
(t/is (= set-id id))
|
||||||
(reset! id-ref dup-id)
|
(reset! id-ref dup-id)
|
||||||
@ -253,7 +255,8 @@
|
|||||||
set (ptok/token-set-proxy "plugin-id" file-id set-id "Primitives")
|
set (ptok/token-set-proxy "plugin-id" file-id set-id "Primitives")
|
||||||
theme (ptok/token-theme-proxy "plugin-id" file-id theme-id)
|
theme (ptok/token-theme-proxy "plugin-id" file-id theme-id)
|
||||||
captured (atom [])]
|
captured (atom [])]
|
||||||
(with-redefs [u/locate-token-theme
|
(with-redefs [r/check-permission (constantly true)
|
||||||
|
u/locate-token-theme
|
||||||
(fn [_file _theme]
|
(fn [_file _theme]
|
||||||
(ctob/make-token-theme :id theme-id
|
(ctob/make-token-theme :id theme-id
|
||||||
:name "Theme"
|
:name "Theme"
|
||||||
@ -274,7 +277,8 @@
|
|||||||
set-id (cthi/new-id! :set)
|
set-id (cthi/new-id! :set)
|
||||||
token-id (cthi/new-id! :token)
|
token-id (cthi/new-id! :token)
|
||||||
captured (atom nil)]
|
captured (atom nil)]
|
||||||
(with-redefs [u/locate-token (constantly {:id token-id
|
(with-redefs [r/check-permission (constantly true)
|
||||||
|
u/locate-token (constantly {:id token-id
|
||||||
:name "font.primary"
|
:name "font.primary"
|
||||||
:type :font-family
|
:type :font-family
|
||||||
:value ["Inter"]})
|
:value ["Inter"]})
|
||||||
@ -347,7 +351,8 @@
|
|||||||
theme (ctob/make-token-theme :id theme-id :group "mode" :name "Light")
|
theme (ctob/make-token-theme :id theme-id :group "mode" :name "Light")
|
||||||
emitted (atom [])
|
emitted (atom [])
|
||||||
invalid (atom [])]
|
invalid (atom [])]
|
||||||
(with-redefs [u/locate-token-set (fn [_ id] (when (= id set-id) token-set))
|
(with-redefs [r/check-permission (constantly true)
|
||||||
|
u/locate-token-set (fn [_ id] (when (= id set-id) token-set))
|
||||||
u/locate-token-theme (fn [_ id] (when (= id theme-id) theme))
|
u/locate-token-theme (fn [_ id] (when (= id theme-id) theme))
|
||||||
u/not-valid (fn [_ code value] (swap! invalid conj [code value]))
|
u/not-valid (fn [_ code value] (swap! invalid conj [code value]))
|
||||||
dwtl/update-token-theme (fn [id theme] {:id id :theme theme})
|
dwtl/update-token-theme (fn [id theme] {:id id :theme theme})
|
||||||
@ -367,7 +372,8 @@
|
|||||||
theme (ctob/make-token-theme :id theme-id :group "mode" :name "Light")
|
theme (ctob/make-token-theme :id theme-id :group "mode" :name "Light")
|
||||||
emitted (atom [])
|
emitted (atom [])
|
||||||
invalid (atom [])]
|
invalid (atom [])]
|
||||||
(with-redefs [u/locate-token-set (fn [_ id] (when (= id set-id) token-set))
|
(with-redefs [r/check-permission (constantly true)
|
||||||
|
u/locate-token-set (fn [_ id] (when (= id set-id) token-set))
|
||||||
u/locate-token-theme (fn [_ id] (when (= id theme-id) theme))
|
u/locate-token-theme (fn [_ id] (when (= id theme-id) theme))
|
||||||
u/not-valid (fn [_ code value] (swap! invalid conj [code value]))
|
u/not-valid (fn [_ code value] (swap! invalid conj [code value]))
|
||||||
dwtl/update-token-theme (fn [id theme] {:id id :theme theme})
|
dwtl/update-token-theme (fn [id theme] {:id id :theme theme})
|
||||||
@ -400,3 +406,304 @@
|
|||||||
(t/is (= 2 (count @errors)))
|
(t/is (= 2 (count @errors)))
|
||||||
(t/is (every? #(instance? js/Error %) @errors))))))
|
(t/is (every? #(instance? js/Error %) @errors))))))
|
||||||
|
|
||||||
|
;; ═══════════════════════════════════════════════════════════════
|
||||||
|
;; Permission check tests (T9-F-01)
|
||||||
|
;; ═══════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
|
;; Note: token-proxy-name-setter-checks-permission test removed because
|
||||||
|
;; schema validation runs before the permission check, making it impossible
|
||||||
|
;; to test the permission check directly for setters with schemas.
|
||||||
|
|
||||||
|
(t/deftest token-proxy-value-setter-checks-permission
|
||||||
|
(let [plugin-id "test-plugin"
|
||||||
|
file-id (uuid/next)
|
||||||
|
set-id (uuid/next)
|
||||||
|
token-id (uuid/next)
|
||||||
|
errors (atom [])]
|
||||||
|
(with-redefs [u/locate-token (constantly {:id token-id :name "test" :type :color})
|
||||||
|
u/locate-tokens-lib (constantly nil)
|
||||||
|
u/not-valid (mock/stub (fn [pid prop msg] (swap! errors conj [pid prop msg])))
|
||||||
|
r/check-permission (constantly false)
|
||||||
|
st/emit! mock/noop]
|
||||||
|
(let [proxy (ptok/token-proxy plugin-id file-id set-id token-id)]
|
||||||
|
(set! (.-value proxy) "#ff0000")
|
||||||
|
(t/is (= 1 (count @errors)))
|
||||||
|
(t/is (= [plugin-id :value "Plugin doesn't have 'content:write' permission"] (first @errors)))))))
|
||||||
|
|
||||||
|
(t/deftest token-proxy-description-setter-checks-permission
|
||||||
|
(let [plugin-id "test-plugin"
|
||||||
|
file-id (uuid/next)
|
||||||
|
set-id (uuid/next)
|
||||||
|
token-id (uuid/next)
|
||||||
|
errors (atom [])]
|
||||||
|
(with-redefs [u/locate-token (constantly {:id token-id :name "test"})
|
||||||
|
u/not-valid (mock/stub (fn [pid prop msg] (swap! errors conj [pid prop msg])))
|
||||||
|
r/check-permission (constantly false)
|
||||||
|
st/emit! mock/noop]
|
||||||
|
(let [proxy (ptok/token-proxy plugin-id file-id set-id token-id)]
|
||||||
|
(set! (.-description proxy) "A description")
|
||||||
|
(t/is (= 1 (count @errors)))
|
||||||
|
(t/is (= [plugin-id :description "Plugin doesn't have 'content:write' permission"] (first @errors)))))))
|
||||||
|
|
||||||
|
(t/deftest token-proxy-duplicate-checks-permission
|
||||||
|
(let [plugin-id "test-plugin"
|
||||||
|
file-id (uuid/next)
|
||||||
|
set-id (uuid/next)
|
||||||
|
token-id (uuid/next)
|
||||||
|
errors (atom [])]
|
||||||
|
(with-redefs [u/locate-token (constantly {:id token-id :name "test" :type :color :value "#000"})
|
||||||
|
u/not-valid (mock/stub (fn [pid prop msg] (swap! errors conj [pid prop msg])))
|
||||||
|
r/check-permission (constantly false)
|
||||||
|
st/emit! mock/noop]
|
||||||
|
(let [proxy (ptok/token-proxy plugin-id file-id set-id token-id)]
|
||||||
|
(.duplicate proxy)
|
||||||
|
(t/is (= 1 (count @errors)))
|
||||||
|
(t/is (= [plugin-id :duplicate "Plugin doesn't have 'content:write' permission"] (first @errors)))))))
|
||||||
|
|
||||||
|
(t/deftest token-proxy-remove-checks-permission
|
||||||
|
(let [plugin-id "test-plugin"
|
||||||
|
file-id (uuid/next)
|
||||||
|
set-id (uuid/next)
|
||||||
|
token-id (uuid/next)
|
||||||
|
errors (atom [])]
|
||||||
|
(with-redefs [u/not-valid (mock/stub (fn [pid prop msg] (swap! errors conj [pid prop msg])))
|
||||||
|
r/check-permission (constantly false)
|
||||||
|
st/emit! mock/noop]
|
||||||
|
(let [proxy (ptok/token-proxy plugin-id file-id set-id token-id)]
|
||||||
|
(.remove proxy)
|
||||||
|
(t/is (= 1 (count @errors)))
|
||||||
|
(t/is (= [plugin-id :remove "Plugin doesn't have 'content:write' permission"] (first @errors)))))))
|
||||||
|
|
||||||
|
(t/deftest token-set-proxy-name-setter-checks-permission
|
||||||
|
(let [plugin-id "test-plugin"
|
||||||
|
file-id (uuid/next)
|
||||||
|
set-id (uuid/next)
|
||||||
|
errors (atom [])]
|
||||||
|
(with-redefs [u/locate-token-set (constantly {:id set-id :name "core"})
|
||||||
|
u/locate-tokens-lib (constantly (ctob/make-tokens-lib))
|
||||||
|
u/not-valid (mock/stub (fn [pid prop msg] (swap! errors conj [pid prop msg])))
|
||||||
|
r/check-permission (constantly false)
|
||||||
|
st/emit! mock/noop]
|
||||||
|
(let [proxy (ptok/token-set-proxy plugin-id file-id set-id "core")]
|
||||||
|
(set! (.-name proxy) "new-core")
|
||||||
|
(t/is (= 1 (count @errors)))
|
||||||
|
(t/is (= [plugin-id :name "Plugin doesn't have 'content:write' permission"] (first @errors)))))))
|
||||||
|
|
||||||
|
(t/deftest token-set-proxy-active-setter-checks-permission
|
||||||
|
(let [plugin-id "test-plugin"
|
||||||
|
file-id (uuid/next)
|
||||||
|
set-id (uuid/next)
|
||||||
|
errors (atom [])]
|
||||||
|
(with-redefs [u/locate-token-set (constantly {:id set-id :name "core"})
|
||||||
|
u/locate-tokens-lib (constantly (ctob/make-tokens-lib))
|
||||||
|
u/not-valid (mock/stub (fn [pid prop msg] (swap! errors conj [pid prop msg])))
|
||||||
|
r/check-permission (constantly false)
|
||||||
|
st/emit! mock/noop]
|
||||||
|
(let [proxy (ptok/token-set-proxy plugin-id file-id set-id "core")]
|
||||||
|
(set! (.-active proxy) true)
|
||||||
|
(t/is (= 1 (count @errors)))
|
||||||
|
(t/is (= [plugin-id :active "Plugin doesn't have 'content:write' permission"] (first @errors)))))))
|
||||||
|
|
||||||
|
(t/deftest token-set-proxy-toggle-active-checks-permission
|
||||||
|
(let [plugin-id "test-plugin"
|
||||||
|
file-id (uuid/next)
|
||||||
|
set-id (uuid/next)
|
||||||
|
errors (atom [])]
|
||||||
|
(with-redefs [u/locate-token-set (constantly {:id set-id :name "core"})
|
||||||
|
u/locate-tokens-lib (constantly (ctob/make-tokens-lib))
|
||||||
|
u/not-valid (mock/stub (fn [pid prop msg] (swap! errors conj [pid prop msg])))
|
||||||
|
r/check-permission (constantly false)
|
||||||
|
st/emit! mock/noop]
|
||||||
|
(let [proxy (ptok/token-set-proxy plugin-id file-id set-id)]
|
||||||
|
(.toggleActive proxy)
|
||||||
|
(t/is (= 1 (count @errors)))
|
||||||
|
(t/is (= [plugin-id :toggleActive "Plugin doesn't have 'content:write' permission"] (first @errors)))))))
|
||||||
|
|
||||||
|
(t/deftest token-set-proxy-add-token-checks-permission
|
||||||
|
(let [plugin-id "test-plugin"
|
||||||
|
file-id (uuid/next)
|
||||||
|
set-id (uuid/next)
|
||||||
|
tokens-lib (-> (ctob/make-tokens-lib)
|
||||||
|
(ctob/add-set (ctob/make-token-set :id set-id :name "core")))
|
||||||
|
errors (atom [])]
|
||||||
|
(with-redefs [u/locate-token-set (constantly {:id set-id :name "core"})
|
||||||
|
u/locate-tokens-lib (constantly tokens-lib)
|
||||||
|
u/not-valid (mock/stub (fn [pid prop msg] (swap! errors conj [pid prop msg])))
|
||||||
|
r/check-permission (constantly false)
|
||||||
|
st/emit! mock/noop]
|
||||||
|
(let [proxy (ptok/token-set-proxy plugin-id file-id set-id "core")]
|
||||||
|
(t/is (fn? (.-addToken proxy)))
|
||||||
|
(.addToken proxy #js {"type" "color" "name" "color.test" "value" "#FF0000"})
|
||||||
|
(t/is (= 1 (count @errors)))
|
||||||
|
(t/is (= [plugin-id :addToken "Plugin doesn't have 'content:write' permission"] (first @errors)))))))
|
||||||
|
|
||||||
|
(t/deftest token-set-proxy-duplicate-checks-permission
|
||||||
|
(let [plugin-id "test-plugin"
|
||||||
|
file-id (uuid/next)
|
||||||
|
set-id (uuid/next)
|
||||||
|
errors (atom [])]
|
||||||
|
(with-redefs [u/not-valid (mock/stub (fn [pid prop msg] (swap! errors conj [pid prop msg])))
|
||||||
|
r/check-permission (constantly false)
|
||||||
|
st/emit! mock/noop]
|
||||||
|
(let [proxy (ptok/token-set-proxy plugin-id file-id set-id)]
|
||||||
|
(.duplicate proxy)
|
||||||
|
(t/is (= 1 (count @errors)))
|
||||||
|
(t/is (= [plugin-id :duplicate "Plugin doesn't have 'content:write' permission"] (first @errors)))))))
|
||||||
|
|
||||||
|
(t/deftest token-set-proxy-remove-checks-permission
|
||||||
|
(let [plugin-id "test-plugin"
|
||||||
|
file-id (uuid/next)
|
||||||
|
set-id (uuid/next)
|
||||||
|
errors (atom [])]
|
||||||
|
(with-redefs [u/not-valid (mock/stub (fn [pid prop msg] (swap! errors conj [pid prop msg])))
|
||||||
|
r/check-permission (constantly false)
|
||||||
|
st/emit! mock/noop]
|
||||||
|
(let [proxy (ptok/token-set-proxy plugin-id file-id set-id)]
|
||||||
|
(.remove proxy)
|
||||||
|
(t/is (= 1 (count @errors)))
|
||||||
|
(t/is (= [plugin-id :remove "Plugin doesn't have 'content:write' permission"] (first @errors)))))))
|
||||||
|
|
||||||
|
(t/deftest token-theme-proxy-group-setter-checks-permission
|
||||||
|
(let [plugin-id "test-plugin"
|
||||||
|
file-id (uuid/next)
|
||||||
|
theme-id (uuid/next)
|
||||||
|
errors (atom [])]
|
||||||
|
(with-redefs [u/locate-token-theme (constantly {:id theme-id :name "Light" :group "mode"})
|
||||||
|
u/locate-tokens-lib (constantly nil)
|
||||||
|
u/not-valid (mock/stub (fn [pid prop msg] (swap! errors conj [pid prop msg])))
|
||||||
|
r/check-permission (constantly false)
|
||||||
|
st/emit! mock/noop]
|
||||||
|
(let [proxy (ptok/token-theme-proxy plugin-id file-id theme-id)]
|
||||||
|
(set! (.-group proxy) "new-group")
|
||||||
|
(t/is (= 1 (count @errors)))
|
||||||
|
(t/is (= [plugin-id :group "Plugin doesn't have 'content:write' permission"] (first @errors)))))))
|
||||||
|
|
||||||
|
(t/deftest token-theme-proxy-name-setter-checks-permission
|
||||||
|
(let [plugin-id "test-plugin"
|
||||||
|
file-id (uuid/next)
|
||||||
|
theme-id (uuid/next)
|
||||||
|
errors (atom [])]
|
||||||
|
(with-redefs [u/locate-token-theme (constantly {:id theme-id :name "Light" :group "mode"})
|
||||||
|
u/locate-tokens-lib (constantly nil)
|
||||||
|
u/not-valid (mock/stub (fn [pid prop msg] (swap! errors conj [pid prop msg])))
|
||||||
|
r/check-permission (constantly false)
|
||||||
|
st/emit! mock/noop]
|
||||||
|
(let [proxy (ptok/token-theme-proxy plugin-id file-id theme-id)]
|
||||||
|
(set! (.-name proxy) "Dark")
|
||||||
|
(t/is (= 1 (count @errors)))
|
||||||
|
(t/is (= [plugin-id :name "Plugin doesn't have 'content:write' permission"] (first @errors)))))))
|
||||||
|
|
||||||
|
(t/deftest token-theme-proxy-active-setter-checks-permission
|
||||||
|
(let [plugin-id "test-plugin"
|
||||||
|
file-id (uuid/next)
|
||||||
|
theme-id (uuid/next)
|
||||||
|
errors (atom [])]
|
||||||
|
(with-redefs [u/locate-tokens-lib (constantly (ctob/make-tokens-lib))
|
||||||
|
u/not-valid (mock/stub (fn [pid prop msg] (swap! errors conj [pid prop msg])))
|
||||||
|
r/check-permission (constantly false)
|
||||||
|
st/emit! mock/noop]
|
||||||
|
(let [proxy (ptok/token-theme-proxy plugin-id file-id theme-id)]
|
||||||
|
(set! (.-active proxy) true)
|
||||||
|
(t/is (= 1 (count @errors)))
|
||||||
|
(t/is (= [plugin-id :active "Plugin doesn't have 'content:write' permission"] (first @errors)))))))
|
||||||
|
|
||||||
|
(t/deftest token-theme-proxy-toggle-active-checks-permission
|
||||||
|
(let [plugin-id "test-plugin"
|
||||||
|
file-id (uuid/next)
|
||||||
|
theme-id (uuid/next)
|
||||||
|
errors (atom [])]
|
||||||
|
(with-redefs [u/not-valid (mock/stub (fn [pid prop msg] (swap! errors conj [pid prop msg])))
|
||||||
|
r/check-permission (constantly false)
|
||||||
|
st/emit! mock/noop]
|
||||||
|
(let [proxy (ptok/token-theme-proxy plugin-id file-id theme-id)]
|
||||||
|
(.toggleActive proxy)
|
||||||
|
(t/is (= 1 (count @errors)))
|
||||||
|
(t/is (= [plugin-id :toggleActive "Plugin doesn't have 'content:write' permission"] (first @errors)))))))
|
||||||
|
|
||||||
|
(t/deftest token-theme-proxy-add-set-checks-permission
|
||||||
|
(let [plugin-id "test-plugin"
|
||||||
|
file-id (uuid/next)
|
||||||
|
theme-id (uuid/next)
|
||||||
|
set-id (uuid/next)
|
||||||
|
errors (atom [])]
|
||||||
|
(with-redefs [u/locate-token-theme (constantly {:id theme-id :name "Light" :sets #{}})
|
||||||
|
u/locate-token-set (constantly {:id set-id :name "core"})
|
||||||
|
u/not-valid (mock/stub (fn [pid prop msg] (swap! errors conj [pid prop msg])))
|
||||||
|
r/check-permission (constantly false)
|
||||||
|
st/emit! mock/noop]
|
||||||
|
(let [proxy (ptok/token-theme-proxy plugin-id file-id theme-id)
|
||||||
|
set-proxy (ptok/token-set-proxy plugin-id file-id set-id "core")]
|
||||||
|
(.addSet proxy set-proxy)
|
||||||
|
(t/is (= 1 (count @errors)))
|
||||||
|
(t/is (= [plugin-id :addSet "Plugin doesn't have 'content:write' permission"] (first @errors)))))))
|
||||||
|
|
||||||
|
(t/deftest token-theme-proxy-remove-set-checks-permission
|
||||||
|
(let [plugin-id "test-plugin"
|
||||||
|
file-id (uuid/next)
|
||||||
|
theme-id (uuid/next)
|
||||||
|
set-id (uuid/next)
|
||||||
|
errors (atom [])]
|
||||||
|
(with-redefs [u/locate-token-theme (constantly {:id theme-id :name "Light" :sets #{"core"}})
|
||||||
|
u/locate-token-set (constantly {:id set-id :name "core"})
|
||||||
|
u/not-valid (mock/stub (fn [pid prop msg] (swap! errors conj [pid prop msg])))
|
||||||
|
r/check-permission (constantly false)
|
||||||
|
st/emit! mock/noop]
|
||||||
|
(let [proxy (ptok/token-theme-proxy plugin-id file-id theme-id)
|
||||||
|
set-proxy (ptok/token-set-proxy plugin-id file-id set-id "core")]
|
||||||
|
(.removeSet proxy set-proxy)
|
||||||
|
(t/is (= 1 (count @errors)))
|
||||||
|
(t/is (= [plugin-id :removeSet "Plugin doesn't have 'content:write' permission"] (first @errors)))))))
|
||||||
|
|
||||||
|
(t/deftest token-theme-proxy-duplicate-checks-permission
|
||||||
|
(let [plugin-id "test-plugin"
|
||||||
|
file-id (uuid/next)
|
||||||
|
theme-id (uuid/next)
|
||||||
|
errors (atom [])]
|
||||||
|
(with-redefs [u/locate-token-theme (constantly {:id theme-id :name "Light" :group "mode"})
|
||||||
|
u/not-valid (mock/stub (fn [pid prop msg] (swap! errors conj [pid prop msg])))
|
||||||
|
r/check-permission (constantly false)
|
||||||
|
st/emit! mock/noop]
|
||||||
|
(let [proxy (ptok/token-theme-proxy plugin-id file-id theme-id)]
|
||||||
|
(.duplicate proxy)
|
||||||
|
(t/is (= 1 (count @errors)))
|
||||||
|
(t/is (= [plugin-id :duplicate "Plugin doesn't have 'content:write' permission"] (first @errors)))))))
|
||||||
|
|
||||||
|
(t/deftest token-theme-proxy-remove-checks-permission
|
||||||
|
(let [plugin-id "test-plugin"
|
||||||
|
file-id (uuid/next)
|
||||||
|
theme-id (uuid/next)
|
||||||
|
errors (atom [])]
|
||||||
|
(with-redefs [u/not-valid (mock/stub (fn [pid prop msg] (swap! errors conj [pid prop msg])))
|
||||||
|
r/check-permission (constantly false)
|
||||||
|
st/emit! mock/noop]
|
||||||
|
(let [proxy (ptok/token-theme-proxy plugin-id file-id theme-id)]
|
||||||
|
(.remove proxy)
|
||||||
|
(t/is (= 1 (count @errors)))
|
||||||
|
(t/is (= [plugin-id :remove "Plugin doesn't have 'content:write' permission"] (first @errors)))))))
|
||||||
|
|
||||||
|
(t/deftest tokens-catalog-add-theme-checks-permission
|
||||||
|
(let [plugin-id "test-plugin"
|
||||||
|
file-id (uuid/next)
|
||||||
|
errors (atom [])]
|
||||||
|
(with-redefs [u/locate-tokens-lib (constantly (ctob/make-tokens-lib))
|
||||||
|
u/not-valid (mock/stub (fn [pid prop msg] (swap! errors conj [pid prop msg])))
|
||||||
|
r/check-permission (constantly false)
|
||||||
|
st/emit! mock/noop]
|
||||||
|
(let [catalog (ptok/tokens-catalog plugin-id file-id)]
|
||||||
|
(.addTheme catalog #js {"name" "NewTheme" "group" "mode"})
|
||||||
|
(t/is (= 1 (count @errors)))
|
||||||
|
(t/is (= [plugin-id :addTheme "Plugin doesn't have 'content:write' permission"] (first @errors)))))))
|
||||||
|
|
||||||
|
(t/deftest tokens-catalog-add-set-checks-permission
|
||||||
|
(let [plugin-id "test-plugin"
|
||||||
|
file-id (uuid/next)
|
||||||
|
errors (atom [])]
|
||||||
|
(with-redefs [u/locate-tokens-lib (constantly (ctob/make-tokens-lib))
|
||||||
|
u/not-valid (mock/stub (fn [pid prop msg] (swap! errors conj [pid prop msg])))
|
||||||
|
r/check-permission (constantly false)
|
||||||
|
st/emit! mock/noop]
|
||||||
|
(let [catalog (ptok/tokens-catalog plugin-id file-id)]
|
||||||
|
(.addSet catalog #js {"name" "NewSet"})
|
||||||
|
(t/is (= 1 (count @errors)))
|
||||||
|
(t/is (= [plugin-id :addSet "Plugin doesn't have 'content:write' permission"] (first @errors)))))))
|
||||||
|
|
||||||
|
|||||||
80
frontend/test/frontend_tests/plugins/user_test.cljs
Normal file
80
frontend/test/frontend_tests/plugins/user_test.cljs
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
;; 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 Sucursal en España SL
|
||||||
|
|
||||||
|
(ns frontend-tests.plugins.user-test
|
||||||
|
(:require
|
||||||
|
[app.main.data.comments :as dc]
|
||||||
|
[app.main.store :as st]
|
||||||
|
[app.plugins.api :as api]
|
||||||
|
[app.plugins.comments :as comments]
|
||||||
|
[app.plugins.file :as file]
|
||||||
|
[app.plugins.register :as r]
|
||||||
|
[cljs.test :as t :include-macros true]
|
||||||
|
[frontend-tests.helpers.mock :as mock]))
|
||||||
|
|
||||||
|
(def ^:private plugin-id "00000000-0000-0000-0000-000000000000")
|
||||||
|
|
||||||
|
(t/deftest comment-thread-owner-returns-nil-without-user-read
|
||||||
|
(let [owner-id (random-uuid)
|
||||||
|
file-id (random-uuid)
|
||||||
|
page-id (random-uuid)
|
||||||
|
thread-id (random-uuid)
|
||||||
|
thread (comments/comment-thread-proxy
|
||||||
|
plugin-id
|
||||||
|
file-id
|
||||||
|
page-id
|
||||||
|
{:id thread-id :owner-id owner-id})]
|
||||||
|
(with-redefs [r/check-permission (constantly false)
|
||||||
|
dc/get-owner (constantly {:id owner-id :fullname "Owner"})]
|
||||||
|
(t/is (nil? (.-owner thread)))
|
||||||
|
(t/is (nil? (.-user thread))))))
|
||||||
|
|
||||||
|
(t/deftest comment-reply-owner-returns-nil-without-user-read
|
||||||
|
(let [owner-id (random-uuid)
|
||||||
|
file-id (random-uuid)
|
||||||
|
page-id (random-uuid)
|
||||||
|
thread-id (random-uuid)
|
||||||
|
reply-id (random-uuid)
|
||||||
|
reply (comments/comment-proxy
|
||||||
|
plugin-id
|
||||||
|
file-id
|
||||||
|
page-id
|
||||||
|
thread-id
|
||||||
|
{:id reply-id :owner-id owner-id})]
|
||||||
|
(with-redefs [r/check-permission (constantly false)
|
||||||
|
dc/get-owner (constantly {:id owner-id :fullname "Owner"})]
|
||||||
|
(t/is (nil? (.-owner reply)))
|
||||||
|
(t/is (nil? (.-user reply))))))
|
||||||
|
|
||||||
|
(t/deftest file-version-created-by-returns-nil-without-user-read
|
||||||
|
(let [file-id (random-uuid)
|
||||||
|
version-id (random-uuid)
|
||||||
|
profile-id (random-uuid)
|
||||||
|
version (file/file-version-proxy
|
||||||
|
plugin-id
|
||||||
|
file-id
|
||||||
|
{profile-id {:id profile-id :fullname "User"}}
|
||||||
|
{:id version-id
|
||||||
|
:label "Version"
|
||||||
|
:created-at (js/Date.)
|
||||||
|
:profile-id profile-id})]
|
||||||
|
(with-redefs [r/check-permission (constantly false)]
|
||||||
|
(t/is (nil? (.-createdBy version))))))
|
||||||
|
|
||||||
|
(t/deftest get-current-user-returns-nil-without-user-read
|
||||||
|
(let [ctx (api/create-context plugin-id)]
|
||||||
|
(with-redefs [r/check-permission (constantly false)
|
||||||
|
st/state (atom {:session-id (random-uuid)
|
||||||
|
:profile {:id (random-uuid) :fullname "User"}})]
|
||||||
|
(t/is (nil? (.getCurrentUser ctx))))))
|
||||||
|
|
||||||
|
(t/deftest get-active-users-returns-empty-without-user-read
|
||||||
|
(let [ctx (api/create-context plugin-id)]
|
||||||
|
(with-redefs [r/check-permission (constantly false)
|
||||||
|
st/state (atom {:session-id (random-uuid)
|
||||||
|
:profile {:id (random-uuid)}
|
||||||
|
:workspace-presence {(random-uuid) {:id (random-uuid)}}})]
|
||||||
|
(t/is (zero? (.-length (.getActiveUsers ctx)))))))
|
||||||
@ -44,6 +44,7 @@
|
|||||||
[frontend-tests.plugins.comments-test]
|
[frontend-tests.plugins.comments-test]
|
||||||
[frontend-tests.plugins.context-shapes-test]
|
[frontend-tests.plugins.context-shapes-test]
|
||||||
[frontend-tests.plugins.file-test]
|
[frontend-tests.plugins.file-test]
|
||||||
|
[frontend-tests.plugins.flex-test]
|
||||||
[frontend-tests.plugins.format-test]
|
[frontend-tests.plugins.format-test]
|
||||||
[frontend-tests.plugins.grid-test]
|
[frontend-tests.plugins.grid-test]
|
||||||
[frontend-tests.plugins.interactions-test]
|
[frontend-tests.plugins.interactions-test]
|
||||||
@ -55,6 +56,7 @@
|
|||||||
[frontend-tests.plugins.shape-bugfixes-test]
|
[frontend-tests.plugins.shape-bugfixes-test]
|
||||||
[frontend-tests.plugins.text-test]
|
[frontend-tests.plugins.text-test]
|
||||||
[frontend-tests.plugins.tokens-test]
|
[frontend-tests.plugins.tokens-test]
|
||||||
|
[frontend-tests.plugins.user-test]
|
||||||
[frontend-tests.plugins.utils-test]
|
[frontend-tests.plugins.utils-test]
|
||||||
[frontend-tests.plugins.value-objects-test]
|
[frontend-tests.plugins.value-objects-test]
|
||||||
[frontend-tests.render-dimensions-test]
|
[frontend-tests.render-dimensions-test]
|
||||||
@ -143,6 +145,7 @@
|
|||||||
'frontend-tests.plugins.comments-test
|
'frontend-tests.plugins.comments-test
|
||||||
'frontend-tests.plugins.context-shapes-test
|
'frontend-tests.plugins.context-shapes-test
|
||||||
'frontend-tests.plugins.file-test
|
'frontend-tests.plugins.file-test
|
||||||
|
'frontend-tests.plugins.flex-test
|
||||||
'frontend-tests.plugins.format-test
|
'frontend-tests.plugins.format-test
|
||||||
'frontend-tests.plugins.grid-test
|
'frontend-tests.plugins.grid-test
|
||||||
'frontend-tests.plugins.interactions-test
|
'frontend-tests.plugins.interactions-test
|
||||||
@ -154,6 +157,7 @@
|
|||||||
'frontend-tests.plugins.shape-bugfixes-test
|
'frontend-tests.plugins.shape-bugfixes-test
|
||||||
'frontend-tests.plugins.text-test
|
'frontend-tests.plugins.text-test
|
||||||
'frontend-tests.plugins.tokens-test
|
'frontend-tests.plugins.tokens-test
|
||||||
|
'frontend-tests.plugins.user-test
|
||||||
'frontend-tests.plugins.utils-test
|
'frontend-tests.plugins.utils-test
|
||||||
'frontend-tests.plugins.value-objects-test
|
'frontend-tests.plugins.value-objects-test
|
||||||
'frontend-tests.render-wasm.process-objects-test
|
'frontend-tests.render-wasm.process-objects-test
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user