diff --git a/frontend/src/app/plugins/api.cljs b/frontend/src/app/plugins/api.cljs index 6582b76e62..6bf90aa8c8 100644 --- a/frontend/src/app/plugins/api.cljs +++ b/frontend/src/app/plugins/api.cljs @@ -47,6 +47,7 @@ [app.plugins.page :as page] [app.plugins.parser :as parser] [app.plugins.reflow :as wrfp] + [app.plugins.register :as r] [app.plugins.shape :as shape] [app.plugins.system-events :as se] [app.plugins.user :as user] @@ -242,15 +243,18 @@ :getCurrentUser (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 (fn [] - (apply array - (->> (:workspace-presence @st/state) - (vals) - (remove #(= (:id %) (:session-id @st/state))) - (map #(user/active-user-proxy plugin-id (:id %)))))) + (if (r/check-permission plugin-id "user:read") + (apply array + (->> (:workspace-presence @st/state) + (vals) + (remove #(= (:id %) (:session-id @st/state))) + (map #(user/active-user-proxy plugin-id (:id %))))) + (array))) :uploadMediaUrl (fn [name url] diff --git a/frontend/src/app/plugins/comments.cljs b/frontend/src/app/plugins/comments.cljs index 71e8a0311b..b45b36b552 100644 --- a/frontend/src/app/plugins/comments.cljs +++ b/frontend/src/app/plugins/comments.cljs @@ -40,12 +40,14 @@ ;; FIXME: inconsistent with comment-thread: owner :user - {:get #(->> (dc/get-owner data) - (user/user-proxy plugin-id))} + {:get #(when (r/check-permission plugin-id "user:read") + (->> (dc/get-owner data) + (user/user-proxy plugin-id)))} :owner - {:get #(->> (dc/get-owner data) - (user/user-proxy plugin-id))} + {:get #(when (r/check-permission plugin-id "user:read") + (->> (dc/get-owner data) + (user/user-proxy plugin-id)))} :date {:get @@ -116,8 +118,9 @@ :board {:get #(shape/shape-proxy plugin-id file-id page-id (:frame-id data))} :owner - {:get #(->> (dc/get-owner data) - (user/user-proxy plugin-id))} + {:get #(when (r/check-permission plugin-id "user:read") + (->> (dc/get-owner data) + (user/user-proxy plugin-id)))} :position {:get diff --git a/frontend/src/app/plugins/file.cljs b/frontend/src/app/plugins/file.cljs index 12049611bd..10d6895d65 100644 --- a/frontend/src/app/plugins/file.cljs +++ b/frontend/src/app/plugins/file.cljs @@ -61,8 +61,9 @@ :createdBy {:get (fn [] - (when-let [user-data (get users (:profile-id @data))] - (user/user-proxy plugin-id user-data)))} + (when (r/check-permission plugin-id "user:read") + (when-let [user-data (get users (:profile-id @data))] + (user/user-proxy plugin-id user-data))))} :createdAt {:get #(:created-at @data)} diff --git a/frontend/src/app/plugins/flex.cljs b/frontend/src/app/plugins/flex.cljs index 0967edcbec..be3a3b74c7 100644 --- a/frontend/src/app/plugins/flex.cljs +++ b/frontend/src/app/plugins/flex.cljs @@ -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) diff --git a/frontend/src/app/plugins/library.cljs b/frontend/src/app/plugins/library.cljs index 5839ed57a4..388ba89b69 100644 --- a/frontend/src/app/plugins/library.cljs +++ b/frontend/src/app/plugins/library.cljs @@ -698,21 +698,37 @@ :addVariant (fn [] - (st/emit! - (se/event plugin-id "add-new-variant") - (dwv/add-new-variant id))) + (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! + (se/event plugin-id "add-new-variant") + (dwv/add-new-variant id)))) :addProperty (fn [] - (st/emit! - (se/event plugin-id "add-new-property") - (dwv/add-new-property id {:property-value "Value 1"}))) + (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! + (se/event plugin-id "add-new-property") + (dwv/add-new-property id {:property-value "Value 1"})))) :removeProperty (fn [pos] (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) + + (not (r/check-permission plugin-id "library:write")) + (u/not-valid plugin-id :removeProperty "Plugin doesn't have 'library:write' permission") + + :else (st/emit! (se/event plugin-id "remove-property") (dwv/remove-property id pos))))) @@ -727,6 +743,9 @@ (not (string? 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 (st/emit! (dwv/update-property-name id pos name {:trigger "plugin:rename-property"}))))))) @@ -923,8 +942,15 @@ :transformInVariant (fn [] (let [component (u/locate-library-component file-id id)] - (when (and component - (not (ctk/is-variant? component))) + (cond + (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! (se/event plugin-id "transform-in-variant") (dwv/transform-in-variant (:main-instance-id component)))))) @@ -932,8 +958,15 @@ :addVariant (fn [] (let [component (u/locate-library-component file-id id)] - (when (and component - (ctk/is-variant? component)) + (cond + (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! (se/event plugin-id "add-new-variant") (dwv/add-new-variant (:main-instance-id component)))))) @@ -948,6 +981,9 @@ (not (string? 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 (st/emit! (se/event plugin-id "variant-edit-property-value") diff --git a/frontend/src/app/plugins/page.cljs b/frontend/src/app/plugins/page.cljs index e668bc8756..ea55398dd6 100644 --- a/frontend/src/app/plugins/page.cljs +++ b/frontend/src/app/plugins/page.cljs @@ -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")) diff --git a/frontend/src/app/plugins/shape.cljs b/frontend/src/app/plugins/shape.cljs index 205f7d0d97..9031f021c0 100644 --- a/frontend/src/app/plugins/shape.cljs +++ b/frontend/src/app/plugins/shape.cljs @@ -103,6 +103,9 @@ (not (contains? ctsi/event-types 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 (st/emit! (dwi/update-interaction (u/locate-shape file-id page-id shape-id) @@ -119,6 +122,9 @@ (or (not (sm/valid-safe-int? value)) (neg? 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 (st/emit! (dwi/update-interaction (u/locate-shape file-id page-id shape-id) @@ -139,6 +145,9 @@ (not (sm/validate ctsi/schema:interaction 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 (st/emit! (dwi/update-interaction (u/locate-shape file-id page-id shape-id) @@ -148,7 +157,12 @@ :remove (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-component-proxy nil) @@ -200,15 +214,15 @@ (not (sm/validate [:vector types.fills/schema:fill] 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"))) (u/not-valid plugin-id :fills "Cannot modify a page that is not currently active") (cfh/text-shape? shape) (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 (st/emit! (dwsh/update-shapes [id] #(assoc % :fills value)))))) @@ -1475,6 +1489,9 @@ :detach (fn [] (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)) (u/not-valid plugin-id :detach "Cannot modify a page that is not currently active") @@ -1485,12 +1502,12 @@ (fn [component] (let [shape (u/locate-shape file-id page-id id)] (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")) (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")) (u/not-valid plugin-id :swapComponent "Component not valid") @@ -1507,12 +1524,12 @@ (fn [] (let [shape (u/locate-shape file-id page-id id)] (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")) (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)) (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)) (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 (if (and (contains? cf/flags :wasm-export) (contains? #{:jpeg :webp :png} (:type value :png))) @@ -1598,6 +1618,9 @@ (not (sm/validate ctsi/schema:interaction 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 (let [index (-> (u/locate-shape file-id page-id id) (:interactions []) count)] (st/emit! @@ -1611,6 +1634,9 @@ (not (interaction-proxy? 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 (st/emit! (dwi/remove-interaction {:id id} (obj/get interaction "$index")) @@ -1691,8 +1717,14 @@ :fn (fn [token attrs] (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))] - (if (some #(not (token-attr? %)) kw-attrs) + (cond + (some #(not (token-attr? %)) kw-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! (-> (dwta/toggle-token {:token token :attrs kw-attrs @@ -1720,6 +1752,9 @@ (not (string? 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 (let [shape (u/locate-shape file-id page-id id) component (u/locate-library-component file-id (:component-id shape))] @@ -1733,6 +1768,9 @@ (or (not (seq ids)) (not (every? uuid/parse* 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 (let [;; Keep the input order (head shape first): it determines ;; the order of the resulting variant components (see diff --git a/frontend/src/app/plugins/tokens.cljs b/frontend/src/app/plugins/tokens.cljs index 64bc69695f..31361117eb 100644 --- a/frontend/src/app/plugins/tokens.cljs +++ b/frontend/src/app/plugins/tokens.cljs @@ -17,6 +17,7 @@ [app.main.data.workspace.tokens.application :as dwta] [app.main.data.workspace.tokens.library-edit :as dwtl] [app.main.store :as st] + [app.plugins.register :as r] [app.plugins.system-events :as se] [app.plugins.utils :as u] [app.util.object :as obj] @@ -85,16 +86,20 @@ (defn- apply-token-to-shapes [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") - (let [token (u/locate-token file-id set-id id)] - (if (some #(not (token-attr? %)) attrs) - (u/not-valid plugin-id :applyToSelected attrs) - (st/emit! - (-> (dwta/toggle-token {:token token - :attrs (into #{} (map token-attr-plugin->token-attr) attrs) - :shape-ids shape-ids - :expand-with-children false}) - (se/add-event plugin-id)))))) + :else + (let [token (u/locate-token file-id set-id id)] + (if (some #(not (token-attr? %)) attrs) + (u/not-valid plugin-id :applyToSelected attrs) + (st/emit! + (-> (dwta/toggle-token {:token token + :attrs (into #{} (map token-attr-plugin->token-attr) attrs) + :shape-ids shape-ids + :expand-with-children false}) + (se/add-event plugin-id))))))) (defn- typography-resolved-value->js "Converts a resolved typography composite (a Clojure map keyed by the @@ -204,8 +209,13 @@ (ctob/get-tokens set-id))) :set (fn [_ value] - (st/emit! (-> (dwtl/update-token set-id id {:name value}) - (se/add-event plugin-id))))} + (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}) + (se/add-event plugin-id)))))} :type {:this true @@ -230,11 +240,16 @@ base)) :set (fn [_ value] - (let [token (u/locate-token file-id set-id id) - value (cond-> value - (= :font-family (:type token)) - (ctob/convert-dtcg-font-family))] - (st/emit! (dwtl/update-token set-id id {:value 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) + value (cond-> value + (= :font-family (:type token)) + (ctob/convert-dtcg-font-family))] + (st/emit! (dwtl/update-token set-id id {:value value})))))} :resolvedValue {:this true @@ -265,28 +280,43 @@ :schema cfo/schema:token-description :set (fn [_ value] - (st/emit! (-> (dwtl/update-token set-id id {:description value}) - (se/add-event :plugin-id))))} + (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}) + (se/add-event plugin-id)))))} :duplicate (fn [] - ;; TODO: - ;; - add function duplicate-token in tokens-lib, that allows to specify the new id - ;; - use this function in dwtl/duplicate-token - ;; - return the new token proxy using the locally forced id - ;; - do the same with sets and themes - (let [token (u/locate-token file-id set-id id) - token' (ctob/make-token (-> (datafy token) - (dissoc :id - :modified-at)))] - (st/emit! (-> (dwtl/create-token set-id token') - (se/add-event plugin-id))) - (token-proxy plugin-id file-id set-id (:id token')))) + (cond + (not (r/check-permission plugin-id "content:write")) + (u/not-valid plugin-id :duplicate "Plugin doesn't have 'content:write' permission") + + :else + ;; TODO: + ;; - add function duplicate-token in tokens-lib, that allows to specify the new id + ;; - use this function in dwtl/duplicate-token + ;; - return the new token proxy using the locally forced id + ;; - do the same with sets and themes + (let [token (u/locate-token file-id set-id id) + token' (ctob/make-token (-> (datafy token) + (dissoc :id + :modified-at)))] + (st/emit! (-> (dwtl/create-token set-id token') + (se/add-event plugin-id))) + (token-proxy plugin-id file-id set-id (:id token'))))) :remove (fn [] - (st/emit! (-> (dwtl/delete-token set-id id) - (se/add-event plugin-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 id) + (se/add-event plugin-id))))) :applyToShapes {:enumerable false @@ -337,8 +367,13 @@ id) :set (fn [_ name] - (let [set (u/locate-token-set file-id id)] - (st/emit! (dwtl/rename-token-set set 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)] + (st/emit! (dwtl/rename-token-set set name)))))} :active {:this true @@ -351,13 +386,23 @@ :schema ::sm/boolean :set (fn [_ value] - (let [set (u/locate-token-set file-id id)] - (st/emit! (dwtl/set-enabled-token-set (ctob/get-name set) 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)] + (st/emit! (dwtl/set-enabled-token-set (ctob/get-name set) value)))))} :toggleActive - (fn [_] - (let [set (u/locate-token-set file-id id)] - (st/emit! (dwtl/toggle-token-set (ctob/get-name set))))) + (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)] + (st/emit! (dwtl/toggle-token-set (ctob/get-name set)))))) :tokens {:this true @@ -416,39 +461,54 @@ (sm/update-properties assoc :decode/json cfo/convert-dtcg-token))])) :decode/options {:key-fn identity} :fn (fn [attrs] - (let [tokens-lib (u/locate-tokens-lib file-id) - token (ctob/make-token attrs) - ;; Resolve against all tokens in the library (including those - ;; in inactive sets) so that references to structurally - ;; existing tokens resolve even if their set is not active. - ;; The target set's tokens take precedence over equally named - ;; tokens in other sets, and the new token takes precedence - ;; over all. - tokens-tree (-> (merge (ctob/get-all-tokens-map tokens-lib) - (ctob/get-tokens tokens-lib id)) - (assoc (:name token) token)) - resolved-tokens (ts/resolve-tokens tokens-tree) + (cond + (not (r/check-permission plugin-id "content:write")) + (u/not-valid plugin-id :addToken "Plugin doesn't have 'content:write' permission") - {:keys [errors resolved-value] :as resolved-token} - (get resolved-tokens (:name token))] + :else + (let [tokens-lib (u/locate-tokens-lib file-id) + token (ctob/make-token attrs) + ;; Resolve against all tokens in the library (including those + ;; in inactive sets) so that references to structurally + ;; existing tokens resolve even if their set is not active. + ;; The target set's tokens take precedence over equally named + ;; tokens in other sets, and the new token takes precedence + ;; over all. + tokens-tree (-> (merge (ctob/get-all-tokens-map tokens-lib) + (ctob/get-tokens tokens-lib id)) + (assoc (:name token) token)) + resolved-tokens (ts/resolve-tokens tokens-tree) - (if resolved-value - (do (st/emit! (-> (dwtl/create-token id token) - (se/add-event plugin-id))) - (token-proxy plugin-id file-id id (:id token))) - (do (u/not-valid plugin-id :addToken (str errors)) - nil))))} + {:keys [errors resolved-value] :as resolved-token} + (get resolved-tokens (:name token))] + + (if resolved-value + (do (st/emit! (-> (dwtl/create-token id token) + (se/add-event plugin-id))) + (token-proxy plugin-id file-id id (:id token))) + (do (u/not-valid plugin-id :addToken (str errors)) + nil)))))} :duplicate (fn [] - (let [id-ref (atom nil)] - (st/emit! (dwtl/duplicate-token-set id {:id-ref id-ref})) - (when (some? @id-ref) - (token-set-proxy plugin-id file-id @id-ref)))) + (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)] + (st/emit! (dwtl/duplicate-token-set id {:id-ref id-ref})) + (when (some? @id-ref) + (token-set-proxy plugin-id file-id @id-ref))))) :remove (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] (obj/type-of? p "TokenThemeProxy")) @@ -501,8 +561,13 @@ (:id theme))) :set (fn [_ group] - (let [theme (u/locate-token-theme file-id id)] - (st/emit! (dwtl/update-token-theme id (assoc theme :group 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)] + (st/emit! (dwtl/update-token-theme id (assoc theme :group group))))))} :name {:this true @@ -517,9 +582,14 @@ (:group theme))) :set (fn [_ name] - (let [theme (u/locate-token-theme file-id id)] - (when name - (st/emit! (dwtl/update-token-theme id (assoc theme :name 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)] + (when name + (st/emit! (dwtl/update-token-theme id (assoc theme :name name)))))))} :active {:this true @@ -531,11 +601,21 @@ :schema ::sm/boolean :set (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 - (fn [_] - (st/emit! (dwtl/toggle-token-theme-active id))) + (fn [] + (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 {:this true @@ -554,32 +634,52 @@ {:enumerable false :schema [:tuple [:or [:fn token-set-proxy?] ::sm/uuid]] :fn (fn [set-arg] - (let [set-name (token-set-name (resolve-token-set file-id set-arg)) - theme (u/locate-token-theme file-id id)] - (when (and set-name theme) - (st/emit! (dwtl/update-token-theme id (ctob/enable-set theme set-name))))))} + (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)) + theme (u/locate-token-theme file-id id)] + (when (and set-name theme) + (st/emit! (dwtl/update-token-theme id (ctob/enable-set theme set-name)))))))} :removeSet {:enumerable false :schema [:tuple [:or [:fn token-set-proxy?] ::sm/uuid]] :fn (fn [set-arg] - (let [set-name (token-set-name (resolve-token-set file-id set-arg)) - theme (u/locate-token-theme file-id id)] - (when (and set-name theme) - (st/emit! (dwtl/update-token-theme id (ctob/disable-set theme set-name))))))} + (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)) + theme (u/locate-token-theme file-id id)] + (when (and set-name theme) + (st/emit! (dwtl/update-token-theme id (ctob/disable-set theme set-name)))))))} :duplicate (fn [] - (let [theme (u/locate-token-theme file-id id) - theme' (ctob/make-token-theme (-> (datafy theme) - (dissoc :id - :modified-at)))] - (st/emit! (dwtl/create-token-theme theme')) - (token-theme-proxy plugin-id file-id (:id theme')))) + (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) + theme' (ctob/make-token-theme (-> (datafy theme) + (dissoc :id + :modified-at)))] + (st/emit! (dwtl/create-token-theme theme')) + (token-theme-proxy plugin-id file-id (:id theme'))))) :remove (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 [plugin-id file-id] @@ -619,9 +719,14 @@ nil) (sm/dissoc-key :id))]) ;; We don't allow plugins to set the id :fn (fn [attrs] - (let [theme (ctob/make-token-theme attrs)] - (st/emit! (dwtl/create-token-theme theme)) - (token-theme-proxy plugin-id file-id (:id theme))))} + (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)] + (st/emit! (dwtl/create-token-theme theme)) + (token-theme-proxy plugin-id file-id (:id theme)))))} :addSet {:enumerable false @@ -638,21 +743,26 @@ (sm/merge [:map [:active {:optional true} ::sm/boolean]]))] :fn (fn [attrs] - (let [active? (boolean (:active attrs)) - attrs (-> attrs - (dissoc :active) - (update :name ctob/normalize-set-name)) - set (ctob/make-token-set attrs)] - (st/emit! (dwtl/create-token-set set)) - ;; Newly created sets are inactive by default; activate it when - ;; requested. Enabling only adds the set name to the hidden theme, - ;; so it does not depend on the create event having propagated yet. - (when active? - (st/emit! (dwtl/set-enabled-token-set (ctob/get-name set) true))) - ;; Pass the set name as `initial-name` so the proxy can resolve - ;; it immediately, before the async `st/emit!` above propagates - ;; the new set into `@st/state`. - (token-set-proxy plugin-id file-id (ctob/get-id set) (ctob/get-name set))))} + (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)) + attrs (-> attrs + (dissoc :active) + (update :name ctob/normalize-set-name)) + set (ctob/make-token-set attrs)] + (st/emit! (dwtl/create-token-set set)) + ;; Newly created sets are inactive by default; activate it when + ;; requested. Enabling only adds the set name to the hidden theme, + ;; so it does not depend on the create event having propagated yet. + (when active? + (st/emit! (dwtl/set-enabled-token-set (ctob/get-name set) true))) + ;; Pass the set name as `initial-name` so the proxy can resolve + ;; it immediately, before the async `st/emit!` above propagates + ;; the new set into `@st/state`. + (token-set-proxy plugin-id file-id (ctob/get-id set) (ctob/get-name set)))))} :getThemeById {:enumerable false diff --git a/frontend/test/frontend_tests/plugins/flex_test.cljs b/frontend/test/frontend_tests/plugins/flex_test.cljs new file mode 100644 index 0000000000..8bfd3ceac0 --- /dev/null +++ b/frontend/test/frontend_tests/plugins/flex_test.cljs @@ -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. diff --git a/frontend/test/frontend_tests/plugins/library_test.cljs b/frontend/test/frontend_tests/plugins/library_test.cljs index 47d5869b1a..2e604e851e 100644 --- a/frontend/test/frontend_tests/plugins/library_test.cljs +++ b/frontend/test/frontend_tests/plugins/library_test.cljs @@ -6,8 +6,11 @@ (ns frontend-tests.plugins.library-test (:require + [app.common.types.component :as ctk] + [app.common.uuid :as uuid] [app.main.data.workspace.libraries :as dwl] [app.main.data.workspace.texts :as dwt] + [app.main.data.workspace.variants :as dwv] [app.main.store :as st] [app.plugins.library :as library] [app.plugins.register :as r] @@ -93,3 +96,112 @@ (t/is (contains? (:color @captured) :image)) (t/is (not (contains? (:color @captured) :color))) (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))))))) diff --git a/frontend/test/frontend_tests/plugins/page_test.cljs b/frontend/test/frontend_tests/plugins/page_test.cljs index d29149e846..4a3b983f15 100644 --- a/frontend/test/frontend_tests/plugins/page_test.cljs +++ b/frontend/test/frontend_tests/plugins/page_test.cljs @@ -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))))))) diff --git a/frontend/test/frontend_tests/plugins/shape_bugfixes_test.cljs b/frontend/test/frontend_tests/plugins/shape_bugfixes_test.cljs index c854e4942c..e877c4cc44 100644 --- a/frontend/test/frontend_tests/plugins/shape_bugfixes_test.cljs +++ b/frontend/test/frontend_tests/plugins/shape_bugfixes_test.cljs @@ -11,10 +11,15 @@ [app.common.types.component :as ctk] [app.common.uuid :as uuid] [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.store :as st] [app.plugins.api :as api] [app.plugins.public-utils :as public-utils] + [app.plugins.register :as r] [app.plugins.shape :as shape] [app.plugins.utils :as u] [cljs.test :as t :include-macros true] @@ -204,3 +209,202 @@ (t/deftest group-empty-input-returns-nil (let [context (api/create-context plugin-id)] (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))))))) diff --git a/frontend/test/frontend_tests/plugins/tokens_test.cljs b/frontend/test/frontend_tests/plugins/tokens_test.cljs index 5c6122f346..4707b34279 100644 --- a/frontend/test/frontend_tests/plugins/tokens_test.cljs +++ b/frontend/test/frontend_tests/plugins/tokens_test.cljs @@ -16,6 +16,7 @@ [app.main.data.workspace.tokens.library-edit :as dwtl] [app.main.store :as st] [app.plugins.api :as api] + [app.plugins.register :as r] [app.plugins.tokens :as ptok] [app.plugins.utils :as u] [cljs.test :as t :include-macros true] @@ -236,7 +237,8 @@ set-id (cthi/new-id! :set) dup-id (cthi/new-id! :dup) 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]}] (t/is (= set-id id)) (reset! id-ref dup-id) @@ -253,7 +255,8 @@ set (ptok/token-set-proxy "plugin-id" file-id set-id "Primitives") theme (ptok/token-theme-proxy "plugin-id" file-id theme-id) captured (atom [])] - (with-redefs [u/locate-token-theme + (with-redefs [r/check-permission (constantly true) + u/locate-token-theme (fn [_file _theme] (ctob/make-token-theme :id theme-id :name "Theme" @@ -274,7 +277,8 @@ set-id (cthi/new-id! :set) token-id (cthi/new-id! :token) 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" :type :font-family :value ["Inter"]}) @@ -347,7 +351,8 @@ theme (ctob/make-token-theme :id theme-id :group "mode" :name "Light") emitted (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/not-valid (fn [_ code value] (swap! invalid conj [code value])) 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") emitted (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/not-valid (fn [_ code value] (swap! invalid conj [code value])) dwtl/update-token-theme (fn [id theme] {:id id :theme theme}) @@ -400,3 +406,304 @@ (t/is (= 2 (count @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))))))) + diff --git a/frontend/test/frontend_tests/plugins/user_test.cljs b/frontend/test/frontend_tests/plugins/user_test.cljs new file mode 100644 index 0000000000..99c83081bd --- /dev/null +++ b/frontend/test/frontend_tests/plugins/user_test.cljs @@ -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))))))) diff --git a/frontend/test/frontend_tests/runner.cljs b/frontend/test/frontend_tests/runner.cljs index 3430ceb41a..5927bfabfd 100644 --- a/frontend/test/frontend_tests/runner.cljs +++ b/frontend/test/frontend_tests/runner.cljs @@ -44,6 +44,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] @@ -55,6 +56,7 @@ [frontend-tests.plugins.shape-bugfixes-test] [frontend-tests.plugins.text-test] [frontend-tests.plugins.tokens-test] + [frontend-tests.plugins.user-test] [frontend-tests.plugins.utils-test] [frontend-tests.plugins.value-objects-test] [frontend-tests.render-dimensions-test] @@ -143,6 +145,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 @@ -154,6 +157,7 @@ 'frontend-tests.plugins.shape-bugfixes-test 'frontend-tests.plugins.text-test 'frontend-tests.plugins.tokens-test + 'frontend-tests.plugins.user-test 'frontend-tests.plugins.utils-test 'frontend-tests.plugins.value-objects-test 'frontend-tests.render-wasm.process-objects-test