Merge remote-tracking branch 'origin/staging' into develop

This commit is contained in:
Andrey Antukh 2023-08-09 13:36:42 +02:00
commit 31323703a8
21 changed files with 77 additions and 53 deletions

View file

@ -22,11 +22,7 @@
{% endif %} {% endif %}
{% if item.params-schema-js %} {% if item.params-schema-js %}
<span class="tag"> <span class="tag">
<span>SC</span> <span>SCHEMA</span>
</span>
{% else %}
<span class="tag">
<span>SP</span>
</span> </span>
{% endif %} {% endif %}
</div> </div>

View file

@ -38,7 +38,7 @@
<h2>GENERAL NOTES</h2> <h2>GENERAL NOTES</h2>
<h3>Authentication</h3> <h3>Authentication</h3>
<p>The penpot backend right now offerts two way for authenticate the request: <p>The penpot backend right now offers two way for authenticate the request:
<b>cookies</b> (the same mechanism that we use ourselves on accessing the API from the <b>cookies</b> (the same mechanism that we use ourselves on accessing the API from the
web application) and <b>access tokens</b>.</p> web application) and <b>access tokens</b>.</p>

View file

@ -6,13 +6,19 @@ penpot - error list
{% block content %} {% block content %}
<nav> <nav>
<h1>Latest error reports:</h1> <div class="title">
<h1>Error reports (last 200)</h1>
</div>
</nav> </nav>
<main class="horizontal-list"> <main class="horizontal-list">
<ul> <ul>
{% for item in items %} {% for item in items %}
<li><a class="date" href="/dbg/error/{{item.id}}">{{item.created-at}}</a> <li>
<span class="title">{{item.hint|abbreviate:150}}</span></li> <a class="date" href="/dbg/error/{{item.id}}">{{item.created-at}}</a>
<a class="hint" href="/dbg/error/{{item.id}}">
<span class="title">{{item.hint|abbreviate:150}}</span>
</a>
</li>
{% endfor %} {% endfor %}
</ul> </ul>
</main> </main>

View file

@ -1,7 +1,7 @@
{% extends "app/templates/base.tmpl" %} {% extends "app/templates/base.tmpl" %}
{% block title %} {% block title %}
penpot - error report v2 {{id}} Report: {{hint|abbreviate:150}} - {{id}} - Penpot Error Report (v3)
{% endblock %} {% endblock %}
{% block content %} {% block content %}

View file

@ -50,7 +50,13 @@ nav {
background: #e3e3e3; background: #e3e3e3;
} }
nav > h1 { nav > .title {
display: flex;
justify-content: center;
width: 100%;
}
nav > .title > h1 {
padding: 0px; padding: 0px;
margin: 0px; margin: 0px;
font-size: 11px; font-size: 11px;
@ -151,7 +157,6 @@ nav > div:not(:last-child) {
line-height: 18px; line-height: 18px;
min-width: 210px; min-width: 210px;
margin: 0px 20px; margin: 0px 20px;
cursor: pointer;
display: flex; display: flex;
border-radius: 3px; border-radius: 3px;
} }

View file

@ -391,13 +391,14 @@
(defn- get-user-info (defn- get-user-info
[{:keys [provider]} tdata] [{:keys [provider]} tdata]
(try (try
(let [{:keys [kid alg] :as theader} (jwt/decode-header (:token/id tdata))] (when (:token/id tdata)
(when-let [key (if (str/starts-with? (name alg) "hs") (let [{:keys [kid alg] :as theader} (jwt/decode-header (:token/id tdata))]
(:client-secret provider) (when-let [key (if (str/starts-with? (name alg) "hs")
(get-in provider [:jwks kid]))] (:client-secret provider)
(get-in provider [:jwks kid]))]
(let [claims (jwt/unsign (:token/id tdata) key {:alg alg})] (let [claims (jwt/unsign (:token/id tdata) key {:alg alg})]
(dissoc claims :exp :iss :iat :sid :aud :sub)))) (dissoc claims :exp :iss :iat :sid :aud :sub)))))
(catch Throwable cause (catch Throwable cause
(l/warn :hint "unable to get user info from JWT token (unexpected exception)" (l/warn :hint "unable to get user info from JWT token (unexpected exception)"
:cause cause)))) :cause cause))))

View file

@ -238,9 +238,9 @@
(-> (io/resource "app/templates/error-report.v2.tmpl") (-> (io/resource "app/templates/error-report.v2.tmpl")
(tmpl/render report))) (tmpl/render report)))
(render-template-v3 [{report :content}] (render-template-v3 [{report :content id :id}]
(-> (io/resource "app/templates/error-report.v3.tmpl") (-> (io/resource "app/templates/error-report.v3.tmpl")
(tmpl/render report))) (tmpl/render (assoc report :id id))))
] ]
(when-not (authorized? pool request) (when-not (authorized? pool request)

View file

@ -74,7 +74,7 @@
::yrs/headers headers})) ::yrs/headers headers}))
(defmethod handle-exception :validation (defmethod handle-exception :validation
[err _] [err request]
(let [{:keys [code] :as data} (ex-data err)] (let [{:keys [code] :as data} (ex-data err)]
(cond (cond
(= code :spec-validation) (= code :spec-validation)
@ -95,6 +95,11 @@
(= code :request-body-too-large) (= code :request-body-too-large)
{::yrs/status 413 ::yrs/body data} {::yrs/status 413 ::yrs/body data}
(= code :invalid-image)
(binding [l/*context* (request->context request)]
(l/error :hint "unexpected error on processing image" :cause err)
{::yrs/status 400 ::yrs/body data})
:else :else
{::yrs/status 400 ::yrs/body data}))) {::yrs/status 400 ::yrs/body data})))

View file

@ -56,7 +56,7 @@
:trace (ex/format-throwable cause :data? false :explain? false :header? false :summary? false)} :trace (ex/format-throwable cause :data? false :explain? false :header? false :summary? false)}
(when-let [params (or (:request/params context) (:params context))] (when-let [params (or (:request/params context) (:params context))]
{:params (pp/pprint-str params :width 200)}) {:params (pp/pprint-str params :width 200 :length 50 :level 10)})
(when-let [value (:value context)] (when-let [value (:value context)]
{:value (pp/pprint-str value :width 200 :length 50 :level 10)}) {:value (pp/pprint-str value :width 200 :length 50 :level 10)})

View file

@ -9,7 +9,6 @@
(:require (:require
[app.common.data :as d] [app.common.data :as d]
[app.common.exceptions :as ex] [app.common.exceptions :as ex]
[app.common.logging :as l]
[app.common.media :as cm] [app.common.media :as cm]
[app.common.schema :as sm] [app.common.schema :as sm]
[app.common.schema.generators :as sg] [app.common.schema.generators :as sg]
@ -227,7 +226,6 @@
(defmethod process-error org.im4java.core.InfoException (defmethod process-error org.im4java.core.InfoException
[error] [error]
(l/error :hint "unexpected error on processing image" :cause error)
(ex/raise :type :validation (ex/raise :type :validation
:code :invalid-image :code :invalid-image
:hint "invalid image" :hint "invalid image"

View file

@ -67,6 +67,7 @@
(sv/defmethod ::get-file-object-thumbnails (sv/defmethod ::get-file-object-thumbnails
"Retrieve a file object thumbnails." "Retrieve a file object thumbnails."
{::doc/added "1.17" {::doc/added "1.17"
::doc/module :files
::sm/params [:map {:title "get-file-object-thumbnails"} ::sm/params [:map {:title "get-file-object-thumbnails"}
[:file-id ::sm/uuid]] [:file-id ::sm/uuid]]
::sm/result [:map-of :string :string] ::sm/result [:map-of :string :string]
@ -112,6 +113,7 @@
(sv/defmethod ::get-file-thumbnail (sv/defmethod ::get-file-thumbnail
{::doc/added "1.17" {::doc/added "1.17"
::doc/module :files
::doc/deprecated "1.19"} ::doc/deprecated "1.19"}
[{:keys [::db/pool]} {:keys [::rpc/profile-id file-id revn]}] [{:keys [::db/pool]} {:keys [::rpc/profile-id file-id revn]}]
(dm/with-open [conn (db/open pool)] (dm/with-open [conn (db/open pool)]
@ -229,11 +231,10 @@
(sv/defmethod ::get-file-data-for-thumbnail (sv/defmethod ::get-file-data-for-thumbnail
"Retrieves the data for generate the thumbnail of the file. Used "Retrieves the data for generate the thumbnail of the file. Used
mainly for render thumbnails on dashboard." mainly for render thumbnails on dashboard."
{::doc/added "1.17" {::doc/added "1.17"
::doc/module :files
::sm/params schema:get-file-data-for-thumbnail ::sm/params schema:get-file-data-for-thumbnail
::sm/result schema:partial-file} ::sm/result schema:partial-file}
[{:keys [::db/pool] :as cfg} {:keys [::rpc/profile-id file-id features] :as props}] [{:keys [::db/pool] :as cfg} {:keys [::rpc/profile-id file-id features] :as props}]
(dm/with-open [conn (db/open pool)] (dm/with-open [conn (db/open pool)]
(files/check-read-permissions! conn profile-id file-id) (files/check-read-permissions! conn profile-id file-id)
@ -274,6 +275,7 @@
(sv/defmethod ::upsert-file-object-thumbnail (sv/defmethod ::upsert-file-object-thumbnail
{::doc/added "1.17" {::doc/added "1.17"
::doc/module :files
::doc/deprecated "1.19" ::doc/deprecated "1.19"
::audit/skip true} ::audit/skip true}
[{:keys [::db/pool] :as cfg} {:keys [::rpc/profile-id file-id] :as params}] [{:keys [::db/pool] :as cfg} {:keys [::rpc/profile-id file-id] :as params}]
@ -319,6 +321,7 @@
(sv/defmethod ::create-file-object-thumbnail (sv/defmethod ::create-file-object-thumbnail
{:doc/added "1.19" {:doc/added "1.19"
::doc/module :files
::audit/skip true ::audit/skip true
::sm/params schema:create-file-object-thumbnail} ::sm/params schema:create-file-object-thumbnail}
@ -357,6 +360,7 @@
(sv/defmethod ::delete-file-object-thumbnail (sv/defmethod ::delete-file-object-thumbnail
{:doc/added "1.19" {:doc/added "1.19"
::doc/module :files
::audit/skip true} ::audit/skip true}
[{:keys [::db/pool] :as cfg} {:keys [::rpc/profile-id file-id object-id]}] [{:keys [::db/pool] :as cfg} {:keys [::rpc/profile-id file-id object-id]}]
@ -395,6 +399,7 @@
"Creates or updates the file thumbnail. Mainly used for paint the "Creates or updates the file thumbnail. Mainly used for paint the
grid thumbnails." grid thumbnails."
{::doc/added "1.17" {::doc/added "1.17"
::doc/module :files
::doc/deprecated "1.19" ::doc/deprecated "1.19"
::audit/skip true} ::audit/skip true}
[{:keys [::db/pool] :as cfg} {:keys [::rpc/profile-id file-id] :as params}] [{:keys [::db/pool] :as cfg} {:keys [::rpc/profile-id file-id] :as params}]
@ -437,6 +442,7 @@
"Creates or updates the file thumbnail. Mainly used for paint the "Creates or updates the file thumbnail. Mainly used for paint the
grid thumbnails." grid thumbnails."
{::doc/added "1.19" {::doc/added "1.19"
::doc/module :files
::audit/skip true ::audit/skip true
::sm/params [:map {:title "create-file-thumbnail"} ::sm/params [:map {:title "create-file-thumbnail"}
[:file-id ::sm/uuid] [:file-id ::sm/uuid]

View file

@ -38,7 +38,8 @@
"Performs the authentication using LDAP backend. Only works if LDAP "Performs the authentication using LDAP backend. Only works if LDAP
is properly configured and enabled with `login-with-ldap` flag." is properly configured and enabled with `login-with-ldap` flag."
{::rpc/auth false {::rpc/auth false
::doc/added "1.15"} ::doc/added "1.15"
::doc/module :auth}
[{:keys [::main/props ::ldap/provider] :as cfg} params] [{:keys [::main/props ::ldap/provider] :as cfg} params]
(when-not provider (when-not provider
(ex/raise :type :restriction (ex/raise :type :restriction

View file

@ -171,7 +171,8 @@
:opt-un [::id ::name])) :opt-un [::id ::name]))
(sv/defmethod ::create-file-media-object-from-url (sv/defmethod ::create-file-media-object-from-url
{::doc/added "1.17"} {::doc/added "1.17"
::doc/deprecated "1.19"}
[{:keys [::db/pool] :as cfg} {:keys [::rpc/profile-id file-id] :as params}] [{:keys [::db/pool] :as cfg} {:keys [::rpc/profile-id file-id] :as params}]
(let [cfg (update cfg ::sto/storage media/configure-assets-storage)] (let [cfg (update cfg ::sto/storage media/configure-assets-storage)]
(files/check-edition-permissions! pool profile-id file-id) (files/check-edition-permissions! pool profile-id file-id)

View file

@ -64,6 +64,7 @@
:opt-un [::search-term])) :opt-un [::search-term]))
(sv/defmethod ::search-files (sv/defmethod ::search-files
{::doc/added "1.17"} {::doc/added "1.17"
::doc/module :files}
[{:keys [::db/pool]} {:keys [::rpc/profile-id team-id search-term]}] [{:keys [::db/pool]} {:keys [::rpc/profile-id team-id search-term]}]
(some->> search-term (search-files pool profile-id team-id))) (some->> search-term (search-files pool profile-id team-id)))

View file

@ -34,7 +34,8 @@
(sv/defmethod ::verify-token (sv/defmethod ::verify-token
{::rpc/auth false {::rpc/auth false
::doc/added "1.15"} ::doc/added "1.15"
::doc/module :auth}
[{:keys [::db/pool] :as cfg} {:keys [token] :as params}] [{:keys [::db/pool] :as cfg} {:keys [token] :as params}]
(db/with-atomic [conn pool] (db/with-atomic [conn pool]
(let [claims (tokens/verify (::main/props cfg) {:token token}) (let [claims (tokens/verify (::main/props cfg) {:token token})

View file

@ -54,14 +54,14 @@
{:name (::sv/name mdata) {:name (::sv/name mdata)
:module (or (some-> (::module mdata) d/name) :module (or (some-> (::module mdata) d/name)
(-> (:ns mdata) (str/split ".") last)) (-> (:ns mdata) (str/split ".") last))
:auth (:auth mdata true) :auth (::rpc/auth mdata true)
:webhook (::webhooks/event? mdata false) :webhook (::webhooks/event? mdata false)
:docs (::sv/docstring mdata) :docs (::sv/docstring mdata)
:deprecated (::deprecated mdata) :deprecated (::deprecated mdata)
:added (::added mdata) :added (::added mdata)
:changes (some->> (::changes mdata) (partition-all 2) (map vec)) :changes (some->> (::changes mdata) (partition-all 2) (map vec))
:spec (fmt-spec mdata) :spec (fmt-spec mdata)
:entrypoint (str (cf/get :public-uri) "/api/rpc/commands/" (::sv/name mdata)) :entrypoint (str (cf/get :public-uri) "/api/rpc/command/" (::sv/name mdata))
:params-schema-js (fmt-schema :js mdata ::sm/params) :params-schema-js (fmt-schema :js mdata ::sm/params)
:result-schema-js (fmt-schema :js mdata ::sm/result) :result-schema-js (fmt-schema :js mdata ::sm/result)
@ -156,7 +156,7 @@
(map (partial gen-method-doc options)) (map (partial gen-method-doc options))
(sort-by (juxt :module :name)) (sort-by (juxt :module :name))
(map (fn [doc] (map (fn [doc]
[(str/ffmt "/commands/%" (:name doc)) (:repr doc)])) [(str/ffmt "/command/%" (:name doc)) (:repr doc)]))
(into {})))] (into {})))]
{:openapi "3.0.0" {:openapi "3.0.0"
:info {:version (:main cf/version)} :info {:version (:main cf/version)}

View file

@ -248,7 +248,7 @@
[:map [:map
[:width :int] [:width :int]
[:height :int] [:height :int]
[:mtype :string] [:mtype {:optional true} [:maybe :string]]
[:id ::sm/uuid]]]]) [:id ::sm/uuid]]]])
(sm/def! ::path-attrs (sm/def! ::path-attrs

View file

@ -73,16 +73,20 @@
(rx/map #(svg/add-svg-shapes (assoc svg-data :image-data %) position)))))) (rx/map #(svg/add-svg-shapes (assoc svg-data :image-data %) position))))))
(defn- process-uris (defn- process-uris
[{:keys [file-id local? name uris mtype on-image on-svg]}] [{:keys [file-id local? name uris mtype on-image on-svg] }]
(letfn [(svg-url? [url] (letfn [(svg-url? [url]
(or (and mtype (= mtype "image/svg+xml")) (or (and mtype (= mtype "image/svg+xml"))
(str/ends-with? url ".svg"))) (str/ends-with? url ".svg")))
(prepare [uri] (upload [uri]
{:file-id file-id (->> (http/send! {:method :get :uri uri :mode :no-cors :response-type :blob})
:is-local local? (rx/map :body)
:name (or name (svg/extract-name uri)) (rx/map (fn [content]
:url uri}) {:file-id file-id
:name (or name (svg/extract-name uri))
:is-local local?
:content content}))
(rx/mapcat #(rp/cmd! :upload-file-media-object %))))
(fetch-svg [name uri] (fetch-svg [name uri]
(->> (http/send! {:method :get :uri uri :mode :no-cors}) (->> (http/send! {:method :get :uri uri :mode :no-cors})
@ -93,8 +97,7 @@
(rx/merge (rx/merge
(->> (rx/from uris) (->> (rx/from uris)
(rx/filter (comp not svg-url?)) (rx/filter (comp not svg-url?))
(rx/map prepare) (rx/mapcat upload)
(rx/mapcat #(rp/cmd! :create-file-media-object-from-url %))
(rx/do on-image)) (rx/do on-image))
(->> (rx/from uris) (->> (rx/from uris)
@ -142,7 +145,7 @@
[:local? :boolean] [:local? :boolean]
[:name {:optional true} :string] [:name {:optional true} :string]
[:data {:optional true} :any] ; FIXME [:data {:optional true} :any] ; FIXME
[:uris {:optional true} [:vector :string]] [:uris {:optional true} [:sequential :string]]
[:mtype {:optional true} :string]]) [:mtype {:optional true} :string]])
(defn- process-media-objects (defn- process-media-objects
@ -213,8 +216,6 @@
:on-image #(st/emit! (dwl/add-media %)))] :on-image #(st/emit! (dwl/add-media %)))]
(process-media-objects params))) (process-media-objects params)))
;; TODO: it is really need handle SVG here, looks like it already
;; handled separately
(defn upload-media-workspace (defn upload-media-workspace
[{:keys [position file-id] :as params}] [{:keys [position file-id] :as params}]
(let [params (assoc params (let [params (assoc params

View file

@ -458,8 +458,8 @@
(dnd/has-type? event "text/uri-list") (dnd/has-type? event "text/uri-list")
(let [data (dnd/get-data event "text/uri-list") (let [data (dnd/get-data event "text/uri-list")
lines (str/lines data) lines (str/lines data)
uris (->> lines (filter #(str/starts-with? % "http"))) uris (filterv #(str/starts-with? % "http") lines)
data (->> lines (filter #(str/starts-with? % "data:image/"))) data (filterv #(str/starts-with? % "data:image/") lines)
params {:file-id (:id file) params {:file-id (:id file)
:position viewport-coord} :position viewport-coord}
params (if (seq uris) params (if (seq uris)

View file

@ -151,9 +151,9 @@
(rx/tap (fn [[fonts]] (rx/tap (fn [[fonts]]
(when (seq fonts) (when (seq fonts)
(st/emit! (df/fonts-fetched fonts))))) (st/emit! (df/fonts-fetched fonts)))))
(rx/map (comp :objects second)))))) (rx/map (fn [[_ page]] {:objects (:objects page)}))))))
objects (use-resource fetch-state)] {:keys [objects]} (use-resource fetch-state)]
(when objects (when objects
(for [object-id object-ids] (for [object-id object-ids]

View file

@ -737,12 +737,13 @@
:fill-color-ref-file (get-meta fill-node :fill-color-ref-file uuid/uuid) :fill-color-ref-file (get-meta fill-node :fill-color-ref-file uuid/uuid)
:fill-color-ref-id (get-meta fill-node :fill-color-ref-id uuid/uuid) :fill-color-ref-id (get-meta fill-node :fill-color-ref-id uuid/uuid)
:fill-opacity (get-meta fill-node :fill-opacity d/parse-double)})) :fill-opacity (get-meta fill-node :fill-opacity d/parse-double)}))
(mapv d/without-nils))] (mapv d/without-nils)
(filterv #(not= (:fill-color %) "none")))]
(if (seq fills) (if (seq fills)
fills fills
(->> [(-> (add-fill {} node svg-data) (->> [(-> (add-fill {} node svg-data)
(d/without-nils))] (d/without-nils))]
(filterv not-empty))))) (filterv #(and (not-empty %) (not= (:fill-color %) "none")))))))
(defn parse-strokes (defn parse-strokes
[node svg-data] [node svg-data]
@ -761,12 +762,13 @@
:stroke-alignment (get-meta stroke-node :stroke-alignment keyword) :stroke-alignment (get-meta stroke-node :stroke-alignment keyword)
:stroke-cap-start (get-meta stroke-node :stroke-cap-start keyword) :stroke-cap-start (get-meta stroke-node :stroke-cap-start keyword)
:stroke-cap-end (get-meta stroke-node :stroke-cap-end keyword)})) :stroke-cap-end (get-meta stroke-node :stroke-cap-end keyword)}))
(mapv d/without-nils))] (mapv d/without-nils)
(filterv #(not= (:stroke-color %) "none")))]
(if (seq strokes) (if (seq strokes)
strokes strokes
(->> [(-> (add-stroke {} node svg-data) (->> [(-> (add-stroke {} node svg-data)
(d/without-nils))] (d/without-nils))]
(filterv #(and (not-empty %) (not= (:stroke-style %) :none))))))) (filterv #(and (not-empty %) (not= (:stroke-color %) "none") (not= (:stroke-style %) :none)))))))
(defn add-svg-content (defn add-svg-content
[props node] [props node]