diff --git a/CHANGES.md b/CHANGES.md index c978bec22..8234a616c 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -16,9 +16,8 @@ - Add the ability to disable google fonts provider with the `disable-google-fonts-provider` flag - Add the ability to disable dashboard templates section with the `disable-dashboard-templates-section` flag - Add the ability to use the registration whitelist with OICD [Github #3348](https://github.com/penpot/penpot/issues/3348) -- Add support for local caching of google fonts (this avoids exposing - the final user IP to goolge and reduces the amount of request sent - to google) +- Add support for local caching of google fonts (this avoids exposing the final user IP to + goolge and reduces the amount of request sent to google) ### :bug: Bugs fixed @@ -30,8 +29,8 @@ - Fix search font visualitation [Taiga #5523](https://tree.taiga.io/project/penpot/issue/5523) - Fix create and account only with spaces [Taiga #5518](https://tree.taiga.io/project/penpot/issue/5518) - Fix context menu outside screen [Taiga #5524](https://tree.taiga.io/project/penpot/issue/5524) - -### :arrow_up: Deps updates +- Fix graphic item rename on assets pannel [Taiga #5556](https://tree.taiga.io/project/penpot/issue/5556) +- Fix component and media name validation on assets panel [Taiga #5555](https://tree.taiga.io/project/penpot/issue/5555) ### :heart: Community contributions by (Thank you!) diff --git a/backend/src/app/rpc/commands/audit.clj b/backend/src/app/rpc/commands/audit.clj index 4578a74b3..6e0762d0e 100644 --- a/backend/src/app/rpc/commands/audit.clj +++ b/backend/src/app/rpc/commands/audit.clj @@ -9,7 +9,7 @@ (:require [app.common.data :as d] [app.common.logging :as l] - [app.common.spec :as us] + [app.common.schema :as sm] [app.common.uuid :as uuid] [app.config :as cf] [app.db :as db] @@ -19,9 +19,7 @@ [app.rpc.climit :as-alias climit] [app.rpc.doc :as-alias doc] [app.rpc.helpers :as rph] - [app.util.services :as sv] - [app.util.time :as dt] - [clojure.spec.alpha :as s])) + [app.util.services :as sv])) (defn- event->row [event] [(uuid/next) @@ -52,25 +50,25 @@ (when (seq events) (db/insert-multi! pool :audit-log event-columns events)))) -(s/def ::name ::us/string) -(s/def ::type ::us/string) -(s/def ::props (s/map-of ::us/keyword any?)) -(s/def ::timestamp dt/instant?) -(s/def ::context (s/map-of ::us/keyword any?)) +(def schema:event + [:schema {:registry + {::valid-any [:or ::sm/inst :int :double [:string {:max 250}]]}} + [:map {:title "Event"} + [:name [:string {:max 250}]] + [:type [:string {:max 250}]] + [:props + [:map-of :keyword ::valid-any]] + [:context {:optional true} + [:map-of :keyword ::valid-any]]]]) -(s/def ::event - (s/keys :req-un [::type ::name ::props ::timestamp] - :opt-un [::context])) - -(s/def ::events (s/every ::event)) - -(s/def ::push-audit-events - (s/keys :req [::rpc/profile-id] - :req-un [::events])) +(def schema:push-audit-events + [:map {:title "push-audit-events"} + [:events [:vector schema:event]]]) (sv/defmethod ::push-audit-events {::climit/id :submit-audit-events-by-profile ::climit/key-fn ::rpc/profile-id + ::sm/params schema:push-audit-events ::audit/skip true ::doc/added "1.17"} [{:keys [::db/pool] :as cfg} params] diff --git a/backend/src/app/rpc/commands/auth.clj b/backend/src/app/rpc/commands/auth.clj index cbd8394a5..7281cfed2 100644 --- a/backend/src/app/rpc/commands/auth.clj +++ b/backend/src/app/rpc/commands/auth.clj @@ -8,9 +8,10 @@ (:require [app.auth :as auth] [app.common.data :as d] + [app.common.data.macros :as dm] [app.common.exceptions :as ex] [app.common.logging :as l] - [app.common.spec :as us] + [app.common.schema :as sm] [app.common.uuid :as uuid] [app.config :as cf] [app.db :as db] @@ -26,18 +27,13 @@ [app.tokens :as tokens] [app.util.services :as sv] [app.util.time :as dt] - [clojure.spec.alpha :as s] [cuerdas.core :as str])) -(s/def ::email ::us/email) -(s/def ::fullname ::us/not-empty-string) -(s/def ::lang ::us/string) -(s/def ::path ::us/string) -(s/def ::password ::us/not-empty-string) -(s/def ::old-password ::us/not-empty-string) -(s/def ::theme ::us/string) -(s/def ::invitation-token ::us/not-empty-string) -(s/def ::token ::us/not-empty-string) +(def schema:password + [::sm/word-string {:max 500}]) + +(def schema:token + [::sm/word-string {:max 1000}]) ;; ---- COMMAND: login with password @@ -101,22 +97,22 @@ (rph/with-meta {::audit/props (audit/profile->props profile) ::audit/profile-id (:id profile)})))))) -(s/def ::login-with-password - (s/keys :req-un [::email ::password] - :opt-un [::invitation-token])) +(def schema:login-with-password + [:map {:title "login-with-password"} + [:email ::sm/email] + [:password schema:password] + [:invitation-token {:optional true} schema:token]]) (sv/defmethod ::login-with-password "Performs authentication using penpot password." {::rpc/auth false - ::doc/added "1.15"} + ::doc/added "1.15" + ::sm/params schema:login-with-password} [cfg params] (login-with-password cfg params)) ;; ---- COMMAND: Logout -(s/def ::logout - (s/keys :opt [::rpc/profile-id])) - (sv/defmethod ::logout "Clears the authentication cookie and logout the current session." {::rpc/auth false @@ -141,13 +137,15 @@ (update-password conn)) nil))) -(s/def ::token ::us/not-empty-string) -(s/def ::recover-profile - (s/keys :req-un [::token ::password])) +(def schema:recover-profile + [:map {:title "recover-profile"} + [:token schema:token] + [:password schema:password]]) (sv/defmethod ::recover-profile {::rpc/auth false - ::doc/added "1.15"} + ::doc/added "1.15" + ::sm/params schema:recover-profile} [cfg params] (recover-profile cfg params)) @@ -228,13 +226,16 @@ (with-meta {:token token} {::audit/profile-id uuid/zero}))) -(s/def ::prepare-register-profile - (s/keys :req-un [::email ::password] - :opt-un [::invitation-token])) +(def schema:prepare-register-profile + [:map {:title "prepare-register-profile"} + [:email ::sm/email] + [:password schema:password] + [:invitation-token {:optional true} schema:token]]) (sv/defmethod ::prepare-register-profile {::rpc/auth false - ::doc/added "1.15"} + ::doc/added "1.15" + ::sm/params schema:prepare-register-profile} [cfg params] (prepare-register cfg params)) @@ -244,7 +245,7 @@ "Create the profile entry on the database with limited set of input attrs (all the other attrs are filled with default values)." [conn {:keys [email] :as params}] - (us/assert! ::us/email email) + (dm/assert! ::sm/email email) (let [id (or (:id params) (uuid/next)) props (-> (audit/extract-utm-params params) (merge (:props params)) @@ -391,12 +392,16 @@ {::audit/replace-props (audit/profile->props profile) ::audit/profile-id (:id profile)}))))) -(s/def ::register-profile - (s/keys :req-un [::token ::fullname])) + +(def schema:register-profile + [:map {:title "register-profile"} + [:token schema:token] + [:fullname [::sm/word-string {:max 100}]]]) (sv/defmethod ::register-profile {::rpc/auth false - ::doc/added "1.15"} + ::doc/added "1.15" + ::sm/params schema:register-profile} [{:keys [::db/pool] :as cfg} params] (db/with-atomic [conn pool] (-> (assoc cfg ::db/conn conn) @@ -448,12 +453,15 @@ (create-recovery-token) (send-email-notification conn)))))) -(s/def ::request-profile-recovery - (s/keys :req-un [::email])) + +(def schema:request-profile-recovery + [:map {:title "request-profile-recovery"} + [:email ::sm/email]]) (sv/defmethod ::request-profile-recovery {::rpc/auth false - ::doc/added "1.15"} + ::doc/added "1.15" + ::sm/params schema:request-profile-recovery} [cfg params] (request-profile-recovery cfg params)) diff --git a/backend/test/backend_tests/helpers.clj b/backend/test/backend_tests/helpers.clj index ac8b0ce45..d2edaeec9 100644 --- a/backend/test/backend_tests/helpers.clj +++ b/backend/test/backend_tests/helpers.clj @@ -14,6 +14,7 @@ [app.common.pages :as cp] [app.common.pprint :as pp] [app.common.spec :as us] + [app.common.schema :as sm] [app.common.uuid :as uuid] [app.config :as cf] [app.db :as db] @@ -414,6 +415,14 @@ (println (us/pretty-explain data)) + (= :params-validation (:code data)) + (app.common.pprint/pprint + (sm/humanize-data (::sm/explain data))) + + (= :data-validation (:code data)) + (app.common.pprint/pprint + (sm/humanize-data (::sm/explain data))) + (= :service-error (:type data)) (print-error! (.getCause ^Throwable error)) diff --git a/backend/test/backend_tests/rpc_audit_test.clj b/backend/test/backend_tests/rpc_audit_test.clj index df860ca03..233728dac 100644 --- a/backend/test/backend_tests/rpc_audit_test.clj +++ b/backend/test/backend_tests/rpc_audit_test.clj @@ -39,8 +39,8 @@ params {::th/type :push-audit-events ::rpc/profile-id (:id prof) :events [{:name "navigate" - :props {:project-id proj-id - :team-id team-id + :props {:project-id (str proj-id) + :team-id (str team-id) :route "dashboard-files"} :context {:engine "blink"} :profile-id (:id prof) @@ -71,8 +71,8 @@ params {::th/type :push-audit-events ::rpc/profile-id (:id prof) :events [{:name "navigate" - :props {:project-id proj-id - :team-id team-id + :props {:project-id (str proj-id) + :team-id (str team-id) :route "dashboard-files"} :context {:engine "blink"} :profile-id uuid/zero @@ -91,6 +91,8 @@ (t/is (= 1 (count rows))) (t/is (= (:id prof) (:profile-id row))) (t/is (= "navigate" (:name row))) - (t/is (= "frontend" (:source row))))))) + (t/is (= "frontend" (:source row)))) + + ))) diff --git a/backend/test/backend_tests/rpc_file_test.clj b/backend/test/backend_tests/rpc_file_test.clj index 743bbdb40..d39fd2d39 100644 --- a/backend/test/backend_tests/rpc_file_test.clj +++ b/backend/test/backend_tests/rpc_file_test.clj @@ -252,6 +252,7 @@ :components-v2 true :changes changes} out (th/command! params)] + ;; (th/print-result! out) (t/is (nil? (:error out))) (:result out)))] @@ -278,7 +279,7 @@ [{:type :add-obj :page-id page-id :id shid - :parent-id uuid/zero + :parent-id uuid/zero :frame-id uuid/zero :components-v2 true :obj {:id shid @@ -286,7 +287,7 @@ :frame-id uuid/zero :parent-id uuid/zero :type :image - :metadata {:id (:id fmo1)}}}]) + :metadata {:id (:id fmo1) :width 200 :height 200 :mtype "image/jpeg"}}}]) ;; Check that reference storage objects on filemediaobjects ;; are the same because of deduplication feature. diff --git a/backend/test/backend_tests/rpc_profile_test.clj b/backend/test/backend_tests/rpc_profile_test.clj index 846c5e1e9..a28f186c8 100644 --- a/backend/test/backend_tests/rpc_profile_test.clj +++ b/backend/test/backend_tests/rpc_profile_test.clj @@ -278,7 +278,7 @@ (let [error (:error out)] (t/is (th/ex-info? error)) (t/is (th/ex-of-type? error :validation)) - (t/is (th/ex-of-code? error :spec-validation)))) + (t/is (th/ex-of-code? error :params-validation)))) ;; try correct register (let [data {::th/type :register-profile diff --git a/common/src/app/common/schema.cljc b/common/src/app/common/schema.cljc index 8a62947df..19e3046f8 100644 --- a/common/src/app/common/schema.cljc +++ b/common/src/app/common/schema.cljc @@ -282,7 +282,9 @@ (def! ::email {:type ::email :pred (fn [s] - (and (string? s) (re-seq email-re s))) + (and (string? s) + (< (count s) 250) + (re-seq email-re s))) :type-properties {:title "email" :description "string with valid email address" @@ -464,6 +466,7 @@ (def! ::word-string {:type ::word-string :pred #(and (string? %) (not (str/blank? %))) + :property-pred (m/-min-max-pred count) :type-properties {:title "string" :description "string" diff --git a/frontend/src/app/main/data/workspace/libraries.cljs b/frontend/src/app/main/data/workspace/libraries.cljs index 32f69ec02..d27d5794f 100644 --- a/frontend/src/app/main/data/workspace/libraries.cljs +++ b/frontend/src/app/main/data/workspace/libraries.cljs @@ -185,21 +185,22 @@ (defn rename-media [id new-name] - (dm/assert! (uuid? id)) - (dm/assert! (string? new-name)) + (dm/verify! (uuid? id)) + (dm/verify! (string? new-name)) (ptk/reify ::rename-media ptk/WatchEvent (watch [it state _] - (when (and (some? new-name) (not= "" new-name)) - (let [data (get state :workspace-data) - [path name] (cph/parse-path-name new-name) - object (get-in data [:media id]) - new-object (assoc object :path path :name name) - changes (-> (pcb/empty-changes it) - (pcb/with-library-data data) - (pcb/update-media new-object))] - (rx/of (dch/commit-changes changes))))))) - + (let [new-name (str/trim new-name)] + (if (str/empty? new-name) + (rx/empty) + (let [[path name] (cph/parse-path-name new-name) + data (get state :workspace-data) + object (get-in data [:media id]) + new-object (assoc object :path path :name name) + changes (-> (pcb/empty-changes it) + (pcb/with-library-data data) + (pcb/update-media new-object))] + (rx/of (dch/commit-changes changes)))))))) (defn delete-media [{:keys [id] :as params}] diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets.cljs b/frontend/src/app/main/ui/workspace/sidebar/assets.cljs index 339aa0bf6..0f8ff338f 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/assets.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/assets.cljs @@ -1078,7 +1078,8 @@ (mf/use-fn (fn [] (swap! state (fn [state] - (assoc state :renaming (:component-id state)))))) + (assoc state :renaming (:object-id state)))))) + cancel-rename (mf/use-fn (fn []