From e6e3f2cbd5878663ebc2f97f9e14de474bcfb108 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Thu, 13 Jan 2022 15:20:16 +0100 Subject: [PATCH] :sparkles: Add debugging pages for download/upload file data. --- backend/resources/error-list.tmpl | 94 ---------- backend/resources/error-report.tmpl | 169 ------------------ backend/resources/templates/base.tmpl | 18 ++ backend/resources/templates/debug.tmpl | 32 ++++ backend/resources/templates/error-list.tmpl | 18 ++ backend/resources/templates/error-report.tmpl | 86 +++++++++ backend/resources/templates/styles.css | 150 ++++++++++++++++ backend/src/app/http.clj | 9 +- backend/src/app/http/debug.clj | 124 ++++++++----- backend/src/app/rpc/queries/profile.clj | 1 - 10 files changed, 392 insertions(+), 309 deletions(-) delete mode 100644 backend/resources/error-list.tmpl delete mode 100644 backend/resources/error-report.tmpl create mode 100644 backend/resources/templates/base.tmpl create mode 100644 backend/resources/templates/debug.tmpl create mode 100644 backend/resources/templates/error-list.tmpl create mode 100644 backend/resources/templates/error-report.tmpl create mode 100644 backend/resources/templates/styles.css diff --git a/backend/resources/error-list.tmpl b/backend/resources/error-list.tmpl deleted file mode 100644 index 360734e142..0000000000 --- a/backend/resources/error-list.tmpl +++ /dev/null @@ -1,94 +0,0 @@ - - - - - - - penpot - error report {{id}} - - - - - - -
- -
- - - diff --git a/backend/resources/error-report.tmpl b/backend/resources/error-report.tmpl deleted file mode 100644 index 6734df31af..0000000000 --- a/backend/resources/error-report.tmpl +++ /dev/null @@ -1,169 +0,0 @@ - - - - - - - penpot - error report {{id}} - - - - - -
-
-
-
CONTEXT:
- -
-

{{hint}}

-
- -
-
{{context}}
-
-
- - {% if params %} -
-
REQUEST PARAMS:
-
-
{{params}}
-
-
- {% endif %} - - {% if data %} -
-
ERROR DATA:
-
-
{{data}}
-
-
- {% endif %} - - {% if spec-problems %} -
-
SPEC PROBLEMS:
-
-
{{spec-problems}}
-
-
- {% endif %} - - {% if spec-value %} -
-
SPEC VALUE:
-
-
{{spec-value}}
-
-
- {% endif %} - - {% if trace %} -
-
TRACE:
-
-
{{trace}}
-
-
- {% endif %} -
-
- - - diff --git a/backend/resources/templates/base.tmpl b/backend/resources/templates/base.tmpl new file mode 100644 index 0000000000..7f8709dd9f --- /dev/null +++ b/backend/resources/templates/base.tmpl @@ -0,0 +1,18 @@ + + + + + + + {% block title %}{% endblock %} + + + + + {% block content %} + {% endblock %} + + + diff --git a/backend/resources/templates/debug.tmpl b/backend/resources/templates/debug.tmpl new file mode 100644 index 0000000000..a3044dba54 --- /dev/null +++ b/backend/resources/templates/debug.tmpl @@ -0,0 +1,32 @@ +{% extends "templates/base.tmpl" %} + +{% block title %} +Debug Main Page +{% endblock %} + +{% block content %} + +
+
+

Download file data:

+ Given an FILE-ID, downloads the file data as file. The file data is encoded using transit. +
+ + + +
+
+ +
+

Upload File Data:

+ Create a new file on your draft projects using the file downloaded from the previous section. +
+ + +
+
+
+{% endblock %} diff --git a/backend/resources/templates/error-list.tmpl b/backend/resources/templates/error-list.tmpl new file mode 100644 index 0000000000..66835867a7 --- /dev/null +++ b/backend/resources/templates/error-list.tmpl @@ -0,0 +1,18 @@ +{% extends "templates/base.tmpl" %} + +{% block title %} +penpot - error list +{% endblock %} + +{% block content %} + +
+ +
+{% endblock %} diff --git a/backend/resources/templates/error-report.tmpl b/backend/resources/templates/error-report.tmpl new file mode 100644 index 0000000000..bf97488623 --- /dev/null +++ b/backend/resources/templates/error-report.tmpl @@ -0,0 +1,86 @@ +{% extends "templates/base.tmpl" %} + +{% block title %} +penpot - error report {{id}} +{% endblock %} + +{% block content %} + +
+
+
+
CONTEXT:
+ +
+

{{hint}}

+
+ +
+
{{context}}
+
+
+ + {% if params %} +
+
REQUEST PARAMS:
+
+
{{params}}
+
+
+ {% endif %} + + {% if data %} +
+
ERROR DATA:
+
+
{{data}}
+
+
+ {% endif %} + + {% if spec-problems %} +
+
SPEC PROBLEMS:
+
+
{{spec-problems}}
+
+
+ {% endif %} + + {% if spec-value %} +
+
SPEC VALUE:
+
+
{{spec-value}}
+
+
+ {% endif %} + + {% if trace %} +
+
TRACE:
+
+
{{trace}}
+
+
+ {% endif %} +
+
+{% endblock %} diff --git a/backend/resources/templates/styles.css b/backend/resources/templates/styles.css new file mode 100644 index 0000000000..60db4b548e --- /dev/null +++ b/backend/resources/templates/styles.css @@ -0,0 +1,150 @@ +* { + font-family: "JetBrains Mono", monospace; + font-size: 12px; +} + +body { + margin: 0px; + padding: 0px; +} + +pre { + margin: 0px; + line-height: 16px; +} + +desc { + display: flex; + margin-bottom: 10px; + font-size: 10px; + color: #666; +} + +input[type=text], input[type=submit] { + padding: 3px; +} + +main { + margin: 20px; +} + +nav { + position: fixed; + width: 100vw; + top: 0; + left: 0; + padding: 5px 20px; + display: flex; + background: #e3e3e3; +} + +nav > h1 { + padding: 0px; + margin: 0px; + font-size: 11px; +} + +nav > div { + text-transform: uppercase; + font-weight: bold; +} + +nav > div:not(:last-child) { + margin-right: 10px; +} + +.table { + margin-top: 25px; + display: flex; + flex-direction: column; +} + +.table-row { + display: flex; + padding-bottom: 15px; + /* width: 100%; */ + /* border: 1px solid red; */ +} + +.table-key { + font-weight: 600; + width: 60px; + padding: 4px; + + padding-top: 40px; + margin-top: -40px; +} + +.table-val { + font-weight: 200; + color: #333; + padding: 4px; +} + +.multiline { + margin-top: 15px; + flex-direction: column; +} + +.multiline .table-key { + margin-bottom: 10px; + border-bottom: 1px dashed #dddddd; + /* padding: 4px; */ + width: unset; +} + +.index { + margin-top: 40px; +} + +.index > section { + padding: 10px; + background-color: #e3e3e3; +} + +.index > section:not(:last-child) { + margin-bottom: 10px; +} + + +.index > section > h2 { + margin-top: 0px; +} + +.horizontal-list { + margin: 20px; + margin-top: 40px; +} + +.horizontal-list ul { + display: flex; + margin: 0px; + padding: 0px; + flex-direction: column; + flex-wrap: wrap; + height: calc(100vh - 75px); + justify-content: flex-start; +} + +.horizontal-list li { + list-style: none; + padding: 0px; + margin: 0px; + line-height: 18px; + min-width: 210px; + margin: 0px 20px; + cursor: pointer; + display: flex; + justify-content: center; + border-radius: 3px; +} + +.horizontal-list li:hover { + background-color: #e9e9e9; +} + +.horizontal-list li > a { + text-decoration: none; + color: inherit; +} + diff --git a/backend/src/app/http.clj b/backend/src/app/http.clj index 5a814132fb..e826b6c883 100644 --- a/backend/src/app/http.clj +++ b/backend/src/app/http.clj @@ -111,17 +111,20 @@ ["/by-file-media-id/:id" {:get (:file-objects-handler assets)}] ["/by-file-media-id/:id/thumbnail" {:get (:file-thumbnails-handler assets)}]] - ["/dbg" {:middleware [[middleware/params] + ["/dbg" {:middleware [[middleware/multipart-params] + [middleware/params] [middleware/keyword-params] [middleware/format-response-body] [middleware/errors errors/handle] [middleware/cookies] [(:middleware session)]]} + ["" {:get (:index debug)}] ["/error-by-id/:id" {:get (:retrieve-error debug)}] ["/error/:id" {:get (:retrieve-error debug)}] ["/error" {:get (:retrieve-error-list debug)}] - ["/file/data/:id" {:get (:retrieve-file-data debug)}] - ["/file/changes/:id" {:get (:retrieve-file-changes debug)}]] + ["/file/data" {:get (:retrieve-file-data debug) + :post (:upload-file-data debug)}] + ["/file/changes" {:get (:retrieve-file-changes debug)}]] ["/webhooks" ["/sns" {:post (:sns-webhook cfg)}]] diff --git a/backend/src/app/http/debug.clj b/backend/src/app/http/debug.clj index 7d12829b0c..d13e38be95 100644 --- a/backend/src/app/http/debug.clj +++ b/backend/src/app/http/debug.clj @@ -12,6 +12,7 @@ [app.common.uuid :as uuid] [app.config :as cf] [app.db :as db] + [app.rpc.mutations.files :as m.files] [app.rpc.queries.profile :as profile] [app.util.blob :as blob] [app.util.template :as tmpl] @@ -19,13 +20,10 @@ [clojure.java.io :as io] [clojure.pprint :as ppr] [cuerdas.core :as str] + [datoteka.core :as fs] [integrant.core :as ig])) -(def sql:retrieve-range-of-changes - "select revn, changes from file_change where file_id=? and revn >= ? and revn <= ? order by revn") - -(def sql:retrieve-single-change - "select revn, changes, data from file_change where file_id=? and revn = ?") +;; (selmer.parser/cache-off!) (defn authorized? [pool {:keys [profile-id]}] @@ -34,35 +32,73 @@ admins (or (cf/get :admins) #{})] (contains? admins (:email profile))))) -(defn prepare-response - [body] - (when-not body - (ex/raise :type :not-found - :code :enpty-data - :hint "empty response")) - - {:status 200 - :headers {"content-type" "application/transit+json"} - :body body}) - -(defn retrieve-file-data +(defn index [{:keys [pool]} request] (when-not (authorized? pool request) (ex/raise :type :authentication :code :only-admins-allowed)) - (let [id (some-> (get-in request [:path-params :id]) uuid/uuid) - revn (some-> (get-in request [:params :revn]) d/parse-integer)] - (when-not id + {:status 200 + :headers {"content-type" "text/html"} + :body (-> (io/resource "templates/debug.tmpl") + (tmpl/render {}))}) + + +(def sql:retrieve-range-of-changes + "select revn, changes from file_change where file_id=? and revn >= ? and revn <= ? order by revn") + +(def sql:retrieve-single-change + "select revn, changes, data from file_change where file_id=? and revn = ?") + +(defn prepare-response + [{:keys [params] :as request} body] + (when-not body + (ex/raise :type :not-found + :code :enpty-data + :hint "empty response")) + + (cond-> {:status 200 + :headers {"content-type" "application/transit+json"} + :body body} + (contains? params :download) + (update :headers assoc "content-disposition" "attachment"))) + +(defn retrieve-file-data + [{:keys [pool]} {:keys [params] :as request}] + (when-not (authorized? pool request) + (ex/raise :type :authentication + :code :only-admins-allowed)) + + (let [file-id (some-> (get-in request [:params :file-id]) uuid/uuid) + revn (some-> (get-in request [:params :revn]) d/parse-integer)] + (when-not file-id (ex/raise :type :validation :code :missing-arguments)) - (if (integer? revn) - (let [fchange (db/exec-one! pool [sql:retrieve-single-change id revn])] - (prepare-response (some-> fchange :data blob/decode))) + (let [data (if (integer? revn) + (some-> (db/exec-one! pool [sql:retrieve-single-change file-id revn]) :data) + (some-> (db/get-by-id pool :file file-id) :data))] + (if (contains? params :download) + (-> (prepare-response request data) + (update :headers assoc "content-type" "application/octet-stream")) + (prepare-response request (some-> data blob/decode)))))) - (let [file (db/get-by-id pool :file id)] - (prepare-response (some-> file :data blob/decode)))))) +(defn upload-file-data + [{:keys [pool]} {:keys [profile-id params] :as request}] + (let [project-id (some-> (profile/retrieve-additional-data pool profile-id) :default-project-id) + data (some-> params :file :tempfile fs/slurp-bytes blob/decode)] + + (if (and data project-id) + (do + (m.files/create-file pool {:id (uuid/next) + :name "imported-file" + :project-id project-id + :profile-id profile-id + :data data}) + {:status 200 + :body "OK"}) + {:status 500 + :body "error"}))) (defn retrieve-file-changes [{:keys [pool]} request] @@ -70,30 +106,30 @@ (ex/raise :type :authentication :code :only-admins-allowed)) - (let [id (some-> (get-in request [:path-params :id]) uuid/uuid) - revn (get-in request [:params :revn] "latest")] + (let [file-id (some-> (get-in request [:params :id]) uuid/uuid) + revn (or (get-in request [:params :revn]) "latest")] - (when (or (not id) (not revn)) + (when (or (not file-id) (not revn)) (ex/raise :type :validation :code :invalid-arguments :hint "missing arguments")) (cond (d/num-string? revn) - (let [item (db/exec-one! pool [sql:retrieve-single-change id (d/parse-integer revn)])] - (prepare-response (some-> item :changes blob/decode vec))) + (let [item (db/exec-one! pool [sql:retrieve-single-change file-id (d/parse-integer revn)])] + (prepare-response request (some-> item :changes blob/decode vec))) (str/includes? revn ":") (let [[start end] (->> (str/split revn #":") (map str/trim) (map d/parse-integer)) - items (db/exec! pool [sql:retrieve-range-of-changes id start end])] - (prepare-response (some->> items - (map :changes) - (map blob/decode) - (mapcat identity) - (vec)))) - + items (db/exec! pool [sql:retrieve-range-of-changes file-id start end])] + (prepare-response request + (some->> items + (map :changes) + (map blob/decode) + (mapcat identity) + (vec)))) :else (ex/raise :type :validation :code :invalid-arguments)))) @@ -112,7 +148,9 @@ (render-template [report] (binding [ppr/*print-right-margin* 300] - (let [context (dissoc report :trace :cause :params :data :spec-problems :spec-value :error :explain :hint :message) + (let [context (dissoc report + :trace :cause :params :data :spec-problems + :spec-value :error :explain :hint :message) params {:context (with-out-str (ppr/pprint context)) :hint (:hint report) :spec-problems (:spec-problems report) @@ -122,7 +160,7 @@ (:trace report) (some-> report :error :trace)) :params (:params report)}] - (-> (io/resource "error-report.tmpl") + (-> (io/resource "templates/error-report.tmpl") (tmpl/render params))))) ] @@ -154,12 +192,14 @@ {:status 200 :headers {"content-type" "text/html; charset=utf-8" "x-robots-tag" "noindex"} - :body (-> (io/resource "error-list.tmpl") + :body (-> (io/resource "templates/error-list.tmpl") (tmpl/render {:items items}))})) (defmethod ig/init-key ::handlers [_ cfg] - {:retrieve-file-data (partial retrieve-file-data cfg) + {:index (partial index cfg) + :retrieve-file-data (partial retrieve-file-data cfg) :retrieve-file-changes (partial retrieve-file-changes cfg) :retrieve-error (partial retrieve-error cfg) - :retrieve-error-list (partial retrieve-error-list cfg)}) + :retrieve-error-list (partial retrieve-error-list cfg) + :upload-file-data (partial upload-file-data cfg)}) diff --git a/backend/src/app/rpc/queries/profile.clj b/backend/src/app/rpc/queries/profile.clj index 212c9ee9ad..5c4c338767 100644 --- a/backend/src/app/rpc/queries/profile.clj +++ b/backend/src/app/rpc/queries/profile.clj @@ -37,7 +37,6 @@ (sv/defmethod ::profile {:auth false} [{:keys [pool] :as cfg} {:keys [profile-id] :as params}] - ;; We need to return the anonymous profile object in two cases, when ;; no profile-id is in session, and when db call raises not found. In all other ;; cases we need to reraise the exception.