From a1fccd46ff0b810be047f357b8a869d8f013a5bc Mon Sep 17 00:00:00 2001
From: Andrey Antukh <niwi@niwi.nz>
Date: Mon, 5 Sep 2022 09:41:19 +0200
Subject: [PATCH] :sparkles: Improve public-uri handling

This enables use penpot under subdirectory
---
 common/src/app/common/transit.cljc            | 22 ++++++++++++++++---
 frontend/src/app/config.cljs                  | 18 ++++++++-------
 frontend/src/app/main.cljs                    |  2 +-
 frontend/src/app/main/data/events.cljs        |  2 +-
 frontend/src/app/main/data/websocket.cljs     |  3 ++-
 frontend/src/app/main/errors.cljs             |  2 +-
 frontend/src/app/main/fonts.cljs              |  4 ++--
 frontend/src/app/main/repo.cljs               | 16 ++++++--------
 .../src/app/main/ui/onboarding/templates.cljs |  2 +-
 .../src/app/main/ui/viewer/share_link.cljs    |  4 ++--
 frontend/src/app/main/worker.cljs             | 15 +++++++++----
 frontend/src/app/render.cljs                  |  5 -----
 frontend/src/app/util/router.cljs             |  5 ++---
 frontend/src/app/util/worker.cljs             |  7 ------
 frontend/src/app/worker/impl.cljs             | 16 +++++++++-----
 frontend/src/app/worker/thumbnails.cljs       |  8 +++----
 16 files changed, 73 insertions(+), 58 deletions(-)

diff --git a/common/src/app/common/transit.cljc b/common/src/app/common/transit.cljc
index 4333051ee..1f17cd289 100644
--- a/common/src/app/common/transit.cljc
+++ b/common/src/app/common/transit.cljc
@@ -8,9 +8,12 @@
   (:require
    [app.common.geom.matrix :as gmt]
    [app.common.geom.point :as gpt]
+   [app.common.uri :as uri]
    [cognitect.transit :as t]
+   [lambdaisland.uri :as luri]
    [linked.core :as lk]
    [linked.set :as lks]
+
    #?(:cljs ["luxon" :as lxn]))
   #?(:clj
      (:import
@@ -19,9 +22,10 @@
       java.io.ByteArrayInputStream
       java.io.ByteArrayOutputStream
       java.io.File
-      java.time.Instant
       java.time.Duration
+      java.time.Instant
       java.time.OffsetDateTime
+      lambdaisland.uri.URI
       linked.set.LinkedSet)))
 
 ;; --- MISC
@@ -121,6 +125,16 @@
    (constantly "m")
    (fn [v] (str (inst-ms v)))))
 
+;; --- URI
+
+(def uri-read-handler
+  (t/read-handler uri/uri))
+
+(def uri-write-handler
+  (t/write-handler
+   (constantly "uri")
+   (fn [v] (str v))))
+
 ;; --- HANDLERS
 
 (def +read-handlers+
@@ -129,6 +143,7 @@
    "point"       point-read-handler
    "duration"    duration-read-handler
    "m"           instant-read-handler
+   "uri"         uri-read-handler
    #?@(:cljs ["n" bigint-read-handler
               "u" uuid-read-handler])
    })
@@ -139,7 +154,7 @@
       Point          point-write-handler
       Instant        instant-write-handler
       LinkedSet      ordered-set-write-handler
-
+      URI            uri-write-handler
       File           file-write-handler
       OffsetDateTime instant-write-handler}
      :cljs
@@ -147,7 +162,8 @@
       gpt/Point      point-write-handler
       lxn/DateTime   instant-write-handler
       lxn/Duration   duration-write-handler
-      lks/LinkedSet  ordered-set-write-handler}
+      lks/LinkedSet  ordered-set-write-handler
+      luri/URI       uri-write-handler}
      ))
 
 ;; --- Low-Level Api
diff --git a/frontend/src/app/config.cljs b/frontend/src/app/config.cljs
index a9e99252b..0deb401de 100644
--- a/frontend/src/app/config.cljs
+++ b/frontend/src/app/config.cljs
@@ -102,17 +102,19 @@
 (def terms-of-service-uri (obj/get global "penpotTermsOfServiceURI" nil))
 (def privacy-policy-uri   (obj/get global "penpotPrivacyPolicyURI" nil))
 
-(defn get-public-uri
-  []
-  (let [uri (u/uri (or (obj/get global "penpotPublicURI")
-                       (.-origin ^js location)))]
+(defn- normalize-uri
+  [uri-str]
+  (let [uri (u/uri uri-str)]
     ;; Ensure that the path always ends with "/"; this ensures that
     ;; all path join operations works as expected.
     (cond-> uri
       (not (str/ends-with? (:path uri) "/"))
       (update :path #(str % "/")))))
 
-(def public-uri (get-public-uri))
+(def public-uri
+  (atom
+   (normalize-uri (or (obj/get global "penpotPublicURI")
+                      (.-origin ^js location)))))
 
 ;; --- Helper Functions
 
@@ -128,18 +130,18 @@
   [{:keys [photo-id fullname name] :as profile}]
   (if (nil? photo-id)
     (avatars/generate {:name (or fullname name)})
-    (str (u/join public-uri "assets/by-id/" photo-id))))
+    (str (u/join @public-uri "assets/by-id/" photo-id))))
 
 (defn resolve-team-photo-url
   [{:keys [photo-id name] :as team}]
   (if (nil? photo-id)
     (avatars/generate {:name name})
-    (str (u/join public-uri "assets/by-id/" photo-id))))
+    (str (u/join @public-uri "assets/by-id/" photo-id))))
 
 (defn resolve-file-media
   ([media]
    (resolve-file-media media false))
   ([{:keys [id] :as media} thumbnail?]
-   (str (cond-> (u/join public-uri "assets/by-file-media-id/")
+   (str (cond-> (u/join @public-uri "assets/by-file-media-id/")
           (true? thumbnail?) (u/join (str id "/thumbnail"))
           (false? thumbnail?) (u/join (str id))))))
diff --git a/frontend/src/app/main.cljs b/frontend/src/app/main.cljs
index a72475f79..8bf8240ef 100644
--- a/frontend/src/app/main.cljs
+++ b/frontend/src/app/main.cljs
@@ -39,7 +39,7 @@
   (log/info :message "Welcome to penpot"
             :version (:full @cf/version)
             :build-date cf/build-date
-            :public-uri (str cf/public-uri)))
+            :public-uri (str @cf/public-uri)))
 
 (declare reinit)
 
diff --git a/frontend/src/app/main/data/events.cljs b/frontend/src/app/main/data/events.cljs
index 4c85decb8..0f0a54efb 100644
--- a/frontend/src/app/main/data/events.cljs
+++ b/frontend/src/app/main/data/events.cljs
@@ -215,7 +215,7 @@
 (defn- persist-events
   [events]
   (if (seq events)
-    (let [uri    (u/join cf/public-uri "api/audit/events")
+    (let [uri    (u/join @cf/public-uri "api/audit/events")
           params {:uri uri
                   :method :post
                   :body (http/transit-data {:events events})}]
diff --git a/frontend/src/app/main/data/websocket.cljs b/frontend/src/app/main/data/websocket.cljs
index a0b552393..e002dd515 100644
--- a/frontend/src/app/main/data/websocket.cljs
+++ b/frontend/src/app/main/data/websocket.cljs
@@ -22,7 +22,8 @@
 
 (defn- prepare-uri
   [params]
-  (let [base (-> (u/join cf/public-uri "ws/notifications")
+  (let [base (-> @cf/public-uri
+                 (u/join "ws/notifications")
                  (assoc :query (u/map->query-string params)))]
     (cond-> base
       (= "https" (:scheme base))
diff --git a/frontend/src/app/main/errors.cljs b/frontend/src/app/main/errors.cljs
index abfde9001..07f3b5c86 100644
--- a/frontend/src/app/main/errors.cljs
+++ b/frontend/src/app/main/errors.cljs
@@ -141,7 +141,7 @@
         context (dm/fmt "ns: '%'\nname: '%'\nfile: '%:%'"
                         (:ns error)
                         (:name error)
-                        (dm/str cf/public-uri "js/cljs-runtime/" (:file error))
+                        (dm/str @cf/public-uri "js/cljs-runtime/" (:file error))
                         (:line error))]
 
     (ts/schedule
diff --git a/frontend/src/app/main/fonts.cljs b/frontend/src/app/main/fonts.cljs
index 24a156382..aaef6d58f 100644
--- a/frontend/src/app/main/fonts.cljs
+++ b/frontend/src/app/main/fonts.cljs
@@ -162,7 +162,7 @@
 
 (defn- asset-id->uri
   [asset-id]
-  (str (u/join cf/public-uri "assets/by-id/" asset-id)))
+  (str (u/join @cf/public-uri "assets/by-id/" asset-id)))
 
 (defn generate-custom-font-variant-css
   [family variant]
@@ -294,7 +294,7 @@
       :else
       (let [{:keys [weight style suffix] :as variant}
             (d/seek #(= (:id %) font-variant-id) variants)
-            font-data {:baseurl (str cf/public-uri)
+            font-data {:baseurl (str @cf/public-uri)
                        :family family
                        :style style
                        :suffix (or suffix font-variant-id)
diff --git a/frontend/src/app/main/repo.cljs b/frontend/src/app/main/repo.cljs
index a5e0b115a..8c1d1ea65 100644
--- a/frontend/src/app/main/repo.cljs
+++ b/frontend/src/app/main/repo.cljs
@@ -43,8 +43,6 @@
                :status status
                :data body})))
 
-(def ^:private base-uri cf/public-uri)
-
 (defn- send-query!
   "A simple helper for send and receive transit data on the penpot
   query api."
@@ -56,7 +54,7 @@
                           http/conditional-error-decode-transit
                           http/conditional-decode-transit)]
      (->> (http/send! {:method :get
-                       :uri (u/join base-uri "api/rpc/query/" (name id))
+                       :uri (u/join @cf/public-uri "api/rpc/query/" (name id))
                        :credentials "include"
                        :query params})
           (rx/map decode-transit)
@@ -67,7 +65,7 @@
   data to the penpot mutation api."
   [id params]
   (->> (http/send! {:method :post
-                    :uri (u/join base-uri "api/rpc/mutation/" (name id))
+                    :uri (u/join @cf/public-uri "api/rpc/mutation/" (name id))
                     :credentials "include"
                     :body (http/transit-data params)})
        (rx/map http/conditional-decode-transit)
@@ -78,7 +76,7 @@
   data to the penpot mutation api."
   [id params {:keys [response-type form-data?]}]
   (->> (http/send! {:method :post
-                    :uri (u/join base-uri "api/rpc/command/" (name id))
+                    :uri (u/join @cf/public-uri "api/rpc/command/" (name id))
                     :credentials "include"
                     :body (if form-data? (http/form-data params) (http/transit-data params))
                     :response-type (or response-type :text)})
@@ -133,7 +131,7 @@
 
 (defmethod command :login-with-oidc
   [_ {:keys [provider] :as params}]
-  (let [uri    (u/join base-uri "api/auth/oauth/" (d/name provider))
+  (let [uri    (u/join @cf/public-uri "api/auth/oauth/" (d/name provider))
         params (dissoc params :provider)]
     (->> (http/send! {:method :post
                       :uri uri
@@ -145,7 +143,7 @@
 (defmethod command :send-feedback
   [_ params]
   (->> (http/send! {:method :post
-                    :uri (u/join base-uri "api/feedback")
+                    :uri (u/join @cf/public-uri "api/feedback")
                     :credentials "include"
                     :body (http/transit-data params)})
        (rx/map http/conditional-decode-transit)
@@ -154,7 +152,7 @@
 (defn- send-export
   [{:keys [blob?] :as params}]
   (->> (http/send! {:method :post
-                    :uri (u/join base-uri "api/export")
+                    :uri (u/join @cf/public-uri "api/export")
                     :body (http/transit-data (dissoc params :blob?))
                     :credentials "include"
                     :response-type (if blob? :blob :text)})
@@ -173,7 +171,7 @@
 (defmethod mutation ::multipart-upload
   [id params]
   (->> (http/send! {:method :post
-                    :uri  (u/join base-uri "api/rpc/mutation/" (name id))
+                    :uri  (u/join @cf/public-uri "api/rpc/mutation/" (name id))
                     :credentials "include"
                     :body (http/form-data params)})
        (rx/map http/conditional-decode-transit)
diff --git a/frontend/src/app/main/ui/onboarding/templates.cljs b/frontend/src/app/main/ui/onboarding/templates.cljs
index 3afe89386..d2abc531b 100644
--- a/frontend/src/app/main/ui/onboarding/templates.cljs
+++ b/frontend/src/app/main/ui/onboarding/templates.cljs
@@ -21,7 +21,7 @@
 (mf/defc template-item
   [{:keys [name path image project-id]}]
   (let [downloading? (mf/use-state false)
-        link         (str (assoc cf/public-uri :path path))
+        link         (str (assoc @cf/public-uri :path path))
 
         on-finish-import
         (fn []
diff --git a/frontend/src/app/main/ui/viewer/share_link.cljs b/frontend/src/app/main/ui/viewer/share_link.cljs
index d45129a9b..16ef6aacb 100644
--- a/frontend/src/app/main/ui/viewer/share_link.cljs
+++ b/frontend/src/app/main/ui/viewer/share_link.cljs
@@ -27,7 +27,7 @@
 
 (defn prepare-params
   [{:keys [pages who-comment who-inspect]}]
-  
+
    {:pages pages
     :who-comment who-comment
     :who-inspect who-inspect})
@@ -145,7 +145,7 @@
                                       (assoc qparams :zoom zoom-type))
 
                             href    (rt/resolve router :viewer pparams qparams)]
-                        (assoc cf/public-uri :fragment href)))]
+                        (assoc @cf/public-uri :fragment href)))]
          (reset! link (some-> href str)))))
 
     [:div.modal-overlay.transparent.share-modal
diff --git a/frontend/src/app/main/worker.cljs b/frontend/src/app/main/worker.cljs
index 40e07456b..e930abbed 100644
--- a/frontend/src/app/main/worker.cljs
+++ b/frontend/src/app/main/worker.cljs
@@ -6,17 +6,24 @@
 
 (ns app.main.worker
   (:require
-   [app.config :as cfg]
+   [app.config :as cf]
    [app.main.errors :as err]
    [app.util.worker :as uw]))
 
 (defonce instance (atom nil))
 
+(defn- update-public-uri!
+  [instance val]
+  (uw/ask! instance {:cmd :configure
+                     :key :public-uri
+                     :val val}))
+
 (defn init!
   []
-  (reset!
-   instance
-   (uw/init cfg/worker-uri err/on-error)))
+  (let [worker (uw/init cf/worker-uri err/on-error)]
+    (update-public-uri! worker @cf/public-uri)
+    (add-watch cf/public-uri ::worker-public-uri (fn [_ _ _ val] (update-public-uri! worker val)))
+    (reset! instance worker)))
 
 (defn ask!
   [message]
diff --git a/frontend/src/app/render.cljs b/frontend/src/app/render.cljs
index 8e4f98182..b6a20404b 100644
--- a/frontend/src/app/render.cljs
+++ b/frontend/src/app/render.cljs
@@ -11,7 +11,6 @@
    [app.common.math :as mth]
    [app.common.spec :as us]
    [app.common.uri :as u]
-   [app.config :as cf]
    [app.main.data.fonts :as df]
    [app.main.features :as features]
    [app.main.render :as render]
@@ -37,10 +36,6 @@
 (declare ^:private render-components)
 (declare ^:private render-objects)
 
-(l/info :hint "Welcome to penpot (Export)"
-        :version (:full @cf/version)
-        :public-uri (str cf/public-uri))
-
 (defn- parse-params
   [loc]
   (let [href (unchecked-get loc "href")]
diff --git a/frontend/src/app/util/router.cljs b/frontend/src/app/util/router.cljs
index 21a89434c..907270db3 100644
--- a/frontend/src/app/util/router.cljs
+++ b/frontend/src/app/util/router.cljs
@@ -8,7 +8,7 @@
   (:refer-clojure :exclude [resolve])
   (:require
    [app.common.uri :as u]
-   [app.config :as cfg]
+   [app.config :as cf]
    [app.util.browser-history :as bhistory]
    [app.util.dom :as dom]
    [app.util.timers :as ts]
@@ -117,8 +117,7 @@
       (let [router (:router state)
             path   (resolve router rname path-params query-params)
             name   (or name "_blank")
-            uri    (-> (u/uri cfg/public-uri)
-                       (assoc :fragment path))]
+            uri    (assoc @cf/public-uri :fragment path)]
         (dom/open-new-window uri name nil)))))
 
 (defn nav-back
diff --git a/frontend/src/app/util/worker.cljs b/frontend/src/app/util/worker.cljs
index 59d98f5b5..9824f395e 100644
--- a/frontend/src/app/util/worker.cljs
+++ b/frontend/src/app/util/worker.cljs
@@ -8,8 +8,6 @@
   "A lightweight layer on top of webworkers api."
   (:require
    [app.common.uuid :as uuid]
-   [app.util.globals :refer [global]]
-   [app.util.object :as obj]
    [app.worker.messages :as wm]
    [beicon.core :as rx]))
 
@@ -83,11 +81,6 @@
     (.addEventListener instance "message" handle-message)
     (.addEventListener instance "error" handle-error)
 
-    (ask! worker
-          {:cmd :configure
-           :params
-           {"penpotPublicURI" (obj/get global "penpotPublicURI")}})
-
     worker))
 
 (defn- handle-response
diff --git a/frontend/src/app/worker/impl.cljs b/frontend/src/app/worker/impl.cljs
index cfef2e3e2..df790dab6 100644
--- a/frontend/src/app/worker/impl.cljs
+++ b/frontend/src/app/worker/impl.cljs
@@ -6,12 +6,14 @@
 
 (ns app.worker.impl
   (:require
+   [app.common.logging :as log]
    [app.common.pages.changes :as ch]
    [app.common.transit :as t]
-   [app.util.globals :refer [global]]
-   [app.util.object :as obj]
+   [app.config :as cf]
    [okulary.core :as l]))
 
+(log/set-level! :info)
+
 (enable-console-print!)
 
 (defonce state (l/atom {:pages-index {}}))
@@ -22,7 +24,7 @@
 
 (defmethod handler :default
   [message]
-  (println "Unexpected message:" message))
+  (log/warn :hint "unexpected message" :message message))
 
 (defmethod handler :echo
   [message]
@@ -55,6 +57,8 @@
                    (assoc :cmd :snaps/update-index))))))
 
 (defmethod handler :configure
-  [{:keys [params]}]
-  (doseq [[param-key param-value] params]
-    (obj/set! global param-key param-value)))
+  [{:keys [key val]}]
+  (log/info :hint "configure worker" :key key :val val)
+  (case key
+    :public-uri
+    (reset! cf/public-uri val)))
diff --git a/frontend/src/app/worker/thumbnails.cljs b/frontend/src/app/worker/thumbnails.cljs
index 1dc58811c..2a7f78a08 100644
--- a/frontend/src/app/worker/thumbnails.cljs
+++ b/frontend/src/app/worker/thumbnails.cljs
@@ -8,7 +8,7 @@
   (:require
    ["react-dom/server" :as rds]
    [app.common.uri :as u]
-   [app.config :as cfg]
+   [app.config :as cf]
    [app.main.fonts :as fonts]
    [app.main.render :as render]
    [app.util.http :as http]
@@ -55,7 +55,7 @@
                  :strip-frames-with-thumbnails true
                  :components-v2 components-v2}
         request {:method :get
-                 :uri (u/join (cfg/get-public-uri) path)
+                 :uri (u/join @cf/public-uri path)
                  :credentials "include"
                  :query params}]
     (->> (http/send! request)
@@ -68,7 +68,7 @@
         params  {:file-id file-id
                  :revn revn}
         request {:method :get
-                 :uri (u/join (cfg/get-public-uri) path)
+                 :uri (u/join @cf/public-uri path)
                  :credentials "include"
                  :query params}]
 
@@ -97,7 +97,7 @@
                  :props {:fonts fonts}
                  :data data}
         request {:method :post
-                 :uri (u/join (cfg/get-public-uri) path)
+                 :uri (u/join @cf/public-uri path)
                  :credentials "include"
                  :body (http/transit-data params)}]