diff --git a/src/metabase/models/setting.clj b/src/metabase/models/setting.clj index 6cae36c2d9ed9c387eefcd424441941e453ed553..4edd42ce4096c72013e0dbd837d732dfed7df519 100644 --- a/src/metabase/models/setting.clj +++ b/src/metabase/models/setting.clj @@ -32,6 +32,7 @@ (:require [cheshire.core :as json] [clojure [core :as core] + [data :as data] [string :as str]] [clojure.data.csv :as csv] [clojure.tools.logging :as log] @@ -82,7 +83,12 @@ :tag (s/maybe Class) ; type annotation, e.g. ^String, to be applied. Defaults to tag based on :type :sensitive? s/Bool ; is this sensitive (never show in plaintext), like a password? (default: false) :internal? s/Bool ; should the API never return this setting? (default: false) - :cache? s/Bool}) ; should the getter always fetch this value "fresh" from the DB? (default: false) + :cache? s/Bool ; should the getter always fetch this value "fresh" from the DB? (default: false) + + ;; called whenever setting value changes, whether from update-setting! or a cache refresh. used to handle cases + ;; where a change to the cache necessitates a change to some value outside the cache, like when a change the + ;; `:site-locale` setting requires a call to `java.util.Locale/setDefault` + :on-change (s/maybe clojure.lang.IFn)}) (defonce ^:private registered-settings @@ -98,6 +104,18 @@ (tru "Setting {0} does not exist.\nFound: {1}" k (sort (keys @registered-settings))))))))) +(defn- call-on-change + "Cache watcher that applies `:on-change` callback for all settings that have changed." + [_key _ref old new] + (let [rs @registered-settings + [d1 d2] (data/diff old new)] + (doseq [changed-setting (into (set (keys d1)) + (set (keys d2)))] + (when-let [on-change (get-in rs [(keyword changed-setting) :on-change])] + (on-change (clojure.core/get old changed-setting) (clojure.core/get new changed-setting)))))) + +(add-watch @#'cache/cache* :call-on-change call-on-change) + ;;; +----------------------------------------------------------------------------------------------------------------+ ;;; | get | ;;; +----------------------------------------------------------------------------------------------------------------+ @@ -382,6 +400,7 @@ :description nil :type setting-type :default default + :on-change nil :getter (partial (default-getter-for-type setting-type) setting-name) :setter (partial (default-setter-for-type setting-type) setting-name) :tag (default-tag-for-type setting-type) diff --git a/src/metabase/public_settings.clj b/src/metabase/public_settings.clj index 1c852be0b37b43a39035355e463565ccb297c42e..c73cf77e1506c97c22dadbc914043a0bb3f42cb6 100644 --- a/src/metabase/public_settings.clj +++ b/src/metabase/public_settings.clj @@ -73,11 +73,9 @@ (str (deferred-tru "The default language for this Metabase instance.") " " (deferred-tru "This only applies to emails, Pulses, etc. Users'' browsers will specify the language used in the user interface.")) - :type :string - :setter (fn [new-value] - (setting/set-string! :site-locale new-value) - (set-locale new-value)) - :default "en") + :type :string + :on-change (fn [_ new-value] (when new-value (set-locale new-value))) + :default "en") (defsetting admin-email (deferred-tru "The email address users should be referred to if they encounter a problem.")) diff --git a/test/metabase/models/setting/cache_test.clj b/test/metabase/models/setting/cache_test.clj index 1cc922cd229fc47255d985ebe037ef1b75e2d32d..706e1b2d662035bbf36641eb66ebbb14fa39fc00 100644 --- a/test/metabase/models/setting/cache_test.clj +++ b/test/metabase/models/setting/cache_test.clj @@ -2,7 +2,9 @@ (:require [clojure.core.memoize :as memoize] [expectations :refer [expect]] [honeysql.core :as hsql] - [metabase.db :as mdb] + [metabase + [db :as mdb] + [public-settings :as public-settings]] [metabase.models [setting :refer [Setting]] [setting-test :as setting-test]] @@ -122,3 +124,28 @@ ;; detect a cache out-of-date situation and flush the cache as appropriate, giving us the updated value when we ;; call! :wow: (setting-test/toucan-name))) + +;; sets site locale setting +(expect + "fr" + (let [original-locale (java.util.Locale/getDefault)] + (try (let [new-language (do (clear-cache!) + (public-settings/site-locale "en") + (simulate-another-instance-updating-setting! :site-locale "fr") + (flush-memoized-results-for-should-restore-cache!) + (public-settings/site-locale))] + new-language) + (finally (java.util.Locale/setDefault original-locale))))) + +;; sets java util locale +(expect + "fr" + (let [original-locale (java.util.Locale/getDefault)] + (try (let [new-language (do (clear-cache!) + (public-settings/site-locale "en") + (simulate-another-instance-updating-setting! :site-locale "fr") + (flush-memoized-results-for-should-restore-cache!) + (public-settings/site-locale) + (.getLanguage (java.util.Locale/getDefault)))] + new-language) + (finally (java.util.Locale/setDefault original-locale)))))