mirror of
https://github.com/penpot/penpot.git
synced 2026-08-19 03:08:40 +00:00
🐛 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
This commit is contained in:
parent
26b786df72
commit
796a76ff32
@ -325,7 +325,12 @@
|
||||
|
||||
:remove
|
||||
(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
|
||||
(fn [child]
|
||||
@ -350,6 +355,9 @@
|
||||
(u/changes-component-copy-structure? objects shape child-shape)
|
||||
(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
|
||||
(st/emit!
|
||||
(dwsh/relocate-shapes #{child-id} id index)
|
||||
|
||||
@ -64,6 +64,9 @@
|
||||
(or (not (string? value)) (empty? 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
|
||||
(st/emit! (dwi/update-flow page-id id #(assoc % :name value)))))}
|
||||
|
||||
@ -79,12 +82,20 @@
|
||||
(not (shape/shape-proxy? 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
|
||||
(st/emit! (dwi/update-flow page-id id #(assoc % :starting-frame (obj/get value "$id"))))))}
|
||||
|
||||
:remove
|
||||
(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]
|
||||
(obj/type-of? proxy "PageProxy"))
|
||||
@ -315,6 +326,9 @@
|
||||
(not (shape/shape-proxy? 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
|
||||
(let [flow-id (uuid/next)]
|
||||
(st/emit!
|
||||
@ -328,6 +342,9 @@
|
||||
(not (flow-proxy? 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
|
||||
(st/emit!
|
||||
(dwi/remove-flow id (obj/get flow "$id"))
|
||||
|
||||
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.
|
||||
@ -9,12 +9,17 @@
|
||||
[app.common.test-helpers.files :as cthf]
|
||||
[app.common.test-helpers.ids-map :as thi]
|
||||
[app.common.test-helpers.shapes :as cths]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.main.data.workspace.pages :as dwpg]
|
||||
[app.main.store :as st]
|
||||
[app.plugins.api :as api]
|
||||
[app.plugins.page :as page]
|
||||
[app.plugins.register :as r]
|
||||
[app.plugins.shape :as shape]
|
||||
[app.plugins.utils :as u]
|
||||
[app.util.object :as obj]
|
||||
[cljs.test :as t :include-macros true]
|
||||
[frontend-tests.helpers.mock :as mock]
|
||||
[frontend-tests.helpers.state :as ths]
|
||||
[frontend-tests.helpers.wasm :as thw]
|
||||
[potok.v2.core :as ptk]))
|
||||
@ -151,3 +156,85 @@
|
||||
(done))))
|
||||
(mock-page-initialized store page2-id))
|
||||
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)))))))
|
||||
|
||||
@ -41,6 +41,7 @@
|
||||
[frontend-tests.plugins.comments-test]
|
||||
[frontend-tests.plugins.context-shapes-test]
|
||||
[frontend-tests.plugins.file-test]
|
||||
[frontend-tests.plugins.flex-test]
|
||||
[frontend-tests.plugins.format-test]
|
||||
[frontend-tests.plugins.grid-test]
|
||||
[frontend-tests.plugins.interactions-test]
|
||||
@ -137,6 +138,7 @@
|
||||
'frontend-tests.plugins.comments-test
|
||||
'frontend-tests.plugins.context-shapes-test
|
||||
'frontend-tests.plugins.file-test
|
||||
'frontend-tests.plugins.flex-test
|
||||
'frontend-tests.plugins.format-test
|
||||
'frontend-tests.plugins.grid-test
|
||||
'frontend-tests.plugins.interactions-test
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user