From f90899ab71cf221a892f4136ee406326a0792245 Mon Sep 17 00:00:00 2001
From: Cam Saul <cammsaul@gmail.com>
Date: Tue, 7 May 2019 15:21:56 -0700
Subject: [PATCH] Move index.html template code -> new metabase.routes.index ns
 :twisted_rightwards_arrows:

---
 src/metabase/public_settings.clj |  2 +-
 src/metabase/routes.clj          | 94 ++++----------------------------
 src/metabase/routes/index.clj    | 85 +++++++++++++++++++++++++++++
 3 files changed, 96 insertions(+), 85 deletions(-)
 create mode 100644 src/metabase/routes/index.clj

diff --git a/src/metabase/public_settings.clj b/src/metabase/public_settings.clj
index 66b06c528d5..066dbd30d2f 100644
--- a/src/metabase/public_settings.clj
+++ b/src/metabase/public_settings.clj
@@ -175,7 +175,7 @@
 
 (def ^:private short-timezone-name (memoize short-timezone-name*))
 
-
+;; TODO - it seems like it would be a nice performance win to cache this a little bit
 (defn public-settings
   "Return a simple map of key/value pairs which represent the public settings (`MetabaseBootstrap`) for the front-end
    application."
diff --git a/src/metabase/routes.clj b/src/metabase/routes.clj
index c9d31f68b71..8b61fa85cfc 100644
--- a/src/metabase/routes.clj
+++ b/src/metabase/routes.clj
@@ -1,14 +1,9 @@
 (ns metabase.routes
   "Main Compojure routes tables. See https://github.com/weavejester/compojure/wiki/Routes-In-Detail for details about
    how these work. `/api/` routes are in `metabase.api.routes`."
-  (:require [cheshire.core :as json]
-            [clojure.java.io :as io]
-            [clojure.string :as str]
-            [clojure.tools.logging :as log]
-            [compojure
+  (:require [compojure
              [core :refer [context defroutes GET]]
              [route :as route]]
-            [hiccup.util :as h.util]
             [metabase
              [public-settings :as public-settings]
              [util :as u]]
@@ -16,80 +11,8 @@
              [dataset :as dataset-api]
              [routes :as api]]
             [metabase.core.initialization-status :as init-status]
-            [metabase.util
-             [embed :as embed]
-             [i18n :refer [trs]]]
-            [puppetlabs.i18n.core :refer [*locale*]]
-            [ring.util.response :as resp]
-            [stencil.core :as stencil]))
-
-(defn- base-href []
-  (let [path (some-> (public-settings/site-url) io/as-url .getPath)]
-    (str path "/")))
-
-(defn- escape-script [s]
-  ;; Escapes text to be included in an inline <script> tag, in particular the string '</script'
-  ;; https://stackoverflow.com/questions/14780858/escape-in-script-tag-contents/23983448#23983448
-  (str/replace s #"(?i)</script" "</scr\\\\ipt"))
-
-(defn- load-template [path variables]
-  (try
-    (stencil/render-file path variables)
-    (catch IllegalArgumentException e
-      (let [message (str (trs "Failed to load template ''{0}''. Did you remember to build the Metabase frontend?" path))]
-        (log/error e message)
-        (throw (Exception. message e))))))
-
-(defn- fallback-localization [locale]
-  (json/generate-string
-   {"headers"
-    {"language"     locale
-     "plural-forms" "nplurals=2; plural=(n != 1);"}
-
-    "translations"
-    {"" {"Metabase" {"msgid"  "Metabase"
-                     "msgstr" ["Metabase"]}}}}))
-
-(defn- load-localization* [locale]
-  (if (or (not locale)
-          (= (str locale) "en"))
-    (fallback-localization locale)
-    (try
-      (load-file-at-path (str "frontend_client/app/locales/" locale ".json"))
-      (catch Throwable e
-        (log/warn (trs "Locale ''{0}'' not found." locale))
-        (fallback-localization locale)))))
-
-(def ^:private ^{:arglists '([])} load-localization
-  (let [memoized-load-localization (memoize load-localization*)]
-    (fn []
-      (memoized-load-localization *locale*))))
-
-(defn- load-entrypoint-template [entrypoint-name embeddable? uri]
-  (load-template
-   (str "frontend_client/" entrypoint-name ".html")
-   (let [{:keys [anon_tracking_enabled google_auth_client_id], :as public-settings} (public-settings/public-settings)]
-     {:bootstrapJSON      (escape-script (json/generate-string public-settings))
-      :localizationJSON   (escape-script (load-localization))
-      :uri                (h.util/escape-html uri)
-      :baseHref           (h.util/escape-html (base-href))
-      :embedCode          (when embeddable? (embed/head uri))
-      :enableGoogleAuth   (boolean google_auth_client_id)
-      :enableAnonTracking (boolean anon_tracking_enabled)})))
-
-(defn- entrypoint
-  "Repsonse that serves up an entrypoint into the Metabase application, e.g. `index.html`."
-  [entrypoint-name embeddable? {:keys [uri]} respond raise]
-  (respond
-   (-> (if (init-status/complete?)
-         (load-entrypoint-template entrypoint-name embeddable? uri)
-         (load-file-at-path "frontend_client/init.html"))
-       resp/response
-       (resp/content-type "text/html; charset=utf-8"))))
-
-(def ^:private index  (partial entrypoint "index"  (not :embeddable)))
-(def ^:private public (partial entrypoint "public" :embeddable))
-(def ^:private embed  (partial entrypoint "embed"  :embeddable))
+            [metabase.routes.index :as index]
+            [ring.util.response :as resp]))
 
 (defn- redirect-including-query-string
   "Like `resp/redirect`, but passes along query string URL params as well. This is important because the public and
@@ -98,24 +21,27 @@
   (fn [{:keys [query-string]} respond _]
     (respond (resp/redirect (str url "?" query-string)))))
 
+
 ;; /public routes. /public/question/:uuid.:export-format redirects to /api/public/card/:uuid/query/:export-format
 (defroutes ^:private public-routes
   (GET ["/question/:uuid.:export-format", :uuid u/uuid-regex, :export-format dataset-api/export-format-regex]
        [uuid export-format]
        (redirect-including-query-string (format "%s/api/public/card/%s/query/%s" (public-settings/site-url) uuid export-format)))
-  (GET "*" [] public))
+  (GET "*" [] index/public))
+
 
 ;; /embed routes. /embed/question/:token.:export-format redirects to /api/public/card/:token/query/:export-format
 (defroutes ^:private embed-routes
   (GET ["/question/:token.:export-format", :export-format dataset-api/export-format-regex]
        [token export-format]
        (redirect-including-query-string (format "%s/api/embed/card/%s/query/%s" (public-settings/site-url) token export-format)))
-  (GET "*" [] embed))
+  (GET "*" [] index/embed))
+
 
 ;; Redirect naughty users who try to visit a page other than setup if setup is not yet complete
 (defroutes ^{:doc "Top-level ring routes for Metabase."} routes
   ;; ^/$ -> index.html
-  (GET "/" [] index)
+  (GET "/" [] index/index)
   (GET "/favicon.ico" [] (resp/resource-response "frontend_client/favicon.ico"))
   ;; ^/api/health -> Health Check Endpoint
   (GET "/api/health" [] (if (init-status/complete?)
@@ -138,4 +64,4 @@
   ;; ^/emebed/ -> Embed frontend and download routes
   (context "/embed" [] embed-routes)
   ;; Anything else (e.g. /user/edit_current) should serve up index.html; React app will handle the rest
-  (GET "*" [] index))
+  (GET "*" [] index/index))
diff --git a/src/metabase/routes/index.clj b/src/metabase/routes/index.clj
new file mode 100644
index 00000000000..528b11f4286
--- /dev/null
+++ b/src/metabase/routes/index.clj
@@ -0,0 +1,85 @@
+(ns metabase.routes.index
+  "Logic related to loading various versions of the index.html template. The actual template lives in
+  `resources/frontend_client/index_template.html`; when the frontend is built (e.g. via `./bin/build frontend`)
+  different versions that include the FE app are created as `index.html`, `public.html`, and `embed.html`."
+  (:require [cheshire.core :as json]
+            [clojure.java.io :as io]
+            [clojure.string :as str]
+            [clojure.tools.logging :as log]
+            [hiccup.util :as h.util]
+            [metabase.core.initialization-status :as init-status]
+            [metabase.public-settings :as public-settings]
+            [metabase.util
+             [embed :as embed]
+             [i18n :refer [trs]]]
+            [puppetlabs.i18n.core :refer [*locale*]]
+            [ring.util.response :as resp]
+            [stencil.core :as stencil]))
+
+(defn- base-href []
+  (let [path (some-> (public-settings/site-url) io/as-url .getPath)]
+    (str path "/")))
+
+(defn- escape-script [s]
+  ;; Escapes text to be included in an inline <script> tag, in particular the string '</script'
+  ;; https://stackoverflow.com/questions/14780858/escape-in-script-tag-contents/23983448#23983448
+  (str/replace s #"(?i)</script" "</scr\\\\ipt"))
+
+
+(defn- fallback-localization [locale]
+  (json/generate-string
+   {"headers"
+    {"language"     locale
+     "plural-forms" "nplurals=2; plural=(n != 1);"}
+
+    "translations"
+    {"" {"Metabase" {"msgid"  "Metabase"
+                     "msgstr" ["Metabase"]}}}}))
+
+(defn- load-localization* [locale]
+  (or
+   (when (and locale (not= locale "en"))
+     (try
+       (slurp (str "frontend_client/app/locales/" locale ".json"))
+       (catch Throwable e
+         (log/warn (trs "Locale ''{0}'' not found." locale)))))
+   (fallback-localization locale)))
+
+(def ^:private ^{:arglists '([])} load-localization
+  (let [memoized-load-localization (memoize load-localization*)]
+    (fn []
+      (memoized-load-localization *locale*))))
+
+
+(defn- load-template [path variables]
+  (try
+    (stencil/render-file path variables)
+    (catch IllegalArgumentException e
+      (let [message (str (trs "Failed to load template ''{0}''. Did you remember to build the Metabase frontend?" path))]
+        (log/error e message)
+        (throw (Exception. message e))))))
+
+(defn- load-entrypoint-template [entrypoint-name embeddable? uri]
+  (load-template
+   (str "frontend_client/" entrypoint-name ".html")
+   (let [{:keys [anon_tracking_enabled google_auth_client_id], :as public-settings} (public-settings/public-settings)]
+     {:bootstrapJSON      (escape-script (json/generate-string public-settings))
+      :localizationJSON   (escape-script (load-localization))
+      :uri                (h.util/escape-html uri)
+      :baseHref           (h.util/escape-html (base-href))
+      :embedCode          (when embeddable? (embed/head uri))
+      :enableGoogleAuth   (boolean google_auth_client_id)
+      :enableAnonTracking (boolean anon_tracking_enabled)})))
+
+(defn- entrypoint
+  "Repsonse that serves up an entrypoint into the Metabase application, e.g. `index.html`."
+  [entrypoint-name embeddable? {:keys [uri]} respond raise]
+  (respond
+   (-> (if (init-status/complete?)
+         (resp/response (load-entrypoint-template entrypoint-name embeddable? uri))
+         (resp/resource-response "frontend_client/init.html"))
+       (resp/content-type "text/html; charset=utf-8"))))
+
+(def index  "main index.html entrypoint."    (partial entrypoint "index"  (not :embeddable)))
+(def public "/public index.html entrypoint." (partial entrypoint "public" :embeddable))
+(def embed  "/embed index.html entrypoint."  (partial entrypoint "embed"  :embeddable))
-- 
GitLab