Skip to content
Snippets Groups Projects
Unverified Commit 6b6fe582 authored by Chris Truter's avatar Chris Truter Committed by GitHub
Browse files

Allow :base to be a map of inherited options for defsetting (#38088)

parent b9229a77
No related branches found
No related tags found
No related merge requests found
......@@ -74,10 +74,7 @@
(str "Unique identifier to be used in Snowplow analytics, to identify this instance of Metabase. "
"This is a public setting since some analytics events are sent prior to initial setup."))
:visibility :public
:type :string
:setter :none
:audit :never
:init setting/random-uuid-str
:base setting/uuid-nonce-base
:doc false)
(defsetting snowplow-available
......
......@@ -618,9 +618,17 @@
(throw (Exception.
(tru "Invalid value for string: must be either \"true\" or \"false\" (case-insensitive)."))))))
(defn ^{:doc "The string representation of a type 4 random uuid"} random-uuid-str []
(defn- random-uuid-str []
(str (random-uuid)))
;; This base allows the bundling of a number of attributes together. In some sense it is defining a subtype / mixin.
(def uuid-nonce-base
"A random uuid value that should never change again"
{:type :string
:setter :none
:audit :never
:init random-uuid-str})
;; Strings are parsed as follows:
;;
;; * `true` if *lowercased* string value is `true`
......@@ -1079,6 +1087,14 @@
(not= (:setter setting-definition) :none)
(not (ns-in-test? (:namespace setting-definition)))))
(defn merge-base
"Use values in the optional `:base` map as default values for `setting-options`"
[{:keys [base] :as setting-options}]
(if-not base
setting-options
(do (assert (not (contains? base :export)) ":export? must not be set in :base")
(merge base (dissoc setting-options :base)))))
(defmacro defsetting
"Defines a new Setting that will be added to the DB at some point in the future.
Conveniently can be used as a getter/setter as well
......@@ -1187,7 +1203,13 @@
should be used for most non-sensitive settings, and will log the value returned by its getter, which may be
the default getter or a custom one. `:raw-value` will audit the raw string value of the setting in the database.
(default: `:no-value` for most settings; `:never` for user- and database-local settings, settings with no setter,
and `:sensitive` settings.)"
and `:sensitive` settings.)
###### `base`
A map which can provide values for any of the above options, except for :export?.
Any top level options will override what's in this base map.
The use case for this map is sharing strongly coupled options between similar settings, see [[uuid-nonce-base]].
"
{:style/indent 1}
[setting-symbol description & {:as options}]
{:pre [(symbol? setting-symbol)
......@@ -1208,7 +1230,7 @@
setting-setter-fn-symbol (-> (symbol (str (name setting-symbol) \!))
(with-meta (meta setting-symbol)))
setting-definition-symbol (gensym "setting-")]
`(let [setting-options# (merge ~options ~setting-metadata)
`(let [setting-options# (merge (merge-base ~options) ~setting-metadata)
~setting-definition-symbol (register-setting! setting-options#)]
~(when maybe-i18n-exception
`(when (#'requires-i18n? ~setting-definition-symbol)
......
......@@ -126,10 +126,7 @@
"Unique identifier used for this instance of {0}. This is set once and only once the first time it is fetched via
its magic getter. Nice!"
:visibility :authenticated
:type :string
:setter :none
:audit :never
:init setting/random-uuid-str
:base setting/uuid-nonce-base
:doc false)
(defsetting site-uuid-for-premium-features-token-checks
......@@ -140,29 +137,20 @@
analytics/stats and if we sent it along with the premium features token check API request it would no longer be
anonymous.)"
:visibility :internal
:type :string
:setter :none
:audit :never
:init setting/random-uuid-str
:base setting/uuid-nonce-base
:doc false)
(defsetting site-uuid-for-version-info-fetching
"A *different* site-wide UUID that we use for the version info fetching API calls. Do not use this for any other
applications. (See [[site-uuid-for-premium-features-token-checks]] for more reasoning.)"
:visibility :internal
:type :string
:setter :none
:audit :never
:init setting/random-uuid-str)
:base setting/uuid-nonce-base)
(defsetting site-uuid-for-unsubscribing-url
"UUID that we use for generating urls users to unsubscribe from alerts. The hash is generated by
hash(secret_uuid + email + subscription_id) = url. Do not use this for any other applications. (See #29955)"
:visibility :internal
:type :string
:setter :none
:audit :never
:init setting/random-uuid-str)
:base setting/uuid-nonce-base)
(defn- normalize-site-url [^String s]
(let [ ;; remove trailing slashes
......
......@@ -42,9 +42,7 @@
:user-local :never,
:default nil,
:name :analytics-uuid,
:type :string
:setter :none
:init setting/random-uuid-str
:base metabase.models.setting/uuid-nonce-base,
:enabled? nil,
:deprecated nil,
:sensitive? false,
......
......@@ -199,6 +199,42 @@
#"Cannot initialize setting before the db is set up"
(setting/get :test-setting-custom-init)))))))
(def ^:private base-options
{:setter :none
:default "totally-basic"})
(defsetting test-no-default-with-base-setting
"Setting to test the `:base` property of settings. This only shows up in dev."
:visibility :internal
:base base-options)
(defsetting test-default-with-base-setting
"Setting to test the `:base` property of settings. This only shows up in dev."
:visibility :internal
:base base-options
:default "fully-bespoke")
(deftest ^:parallel defsetting-with-base-test
(testing "A setting which specifies some base options"
(testing "Uses base options when no top-level options are specified"
(let [without-override (setting/resolve-setting :test-no-default-with-base-setting)]
(is (= "totally-basic" (:default without-override)))
(is (= "totally-basic" (test-no-default-with-base-setting)))))
(testing "Uses top-level options when they are specified"
(let [with-override (setting/resolve-setting :test-default-with-base-setting)]
(is (= "fully-bespoke" (:default with-override)))
(is (= "fully-bespoke" (test-default-with-base-setting)))))))
;; Avoid a false positive from `deftest-check-parallel` due to referencing the setter function.
;; Even though we only resolve the (non-existent) setter, and don't call anything, the linter flags it.
#_{:clj-kondo/ignore [:metabase/validate-deftest]}
(deftest ^:parallel defsetting-with-setter-in-base-test
(testing "A setting which inherits :setter from the base options"
(let [setting (setting/resolve-setting :test-default-with-base-setting)]
(testing "Does not generate a setter"
(is (= :none (:setter setting)))
(is (nil? (resolve 'test-default-with-base-setting!)))))))
(deftest defsetting-setter-fn-test
(test-setting-2! "FANCY NEW VALUE <3")
(is (= "FANCY NEW VALUE <3"
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment