Compare commits
8 Commits
python-sec
...
cljs-compi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
34c0ffc16d | ||
|
|
86c9db9758 | ||
|
|
e47ec36236 | ||
|
|
2a59e48e40 | ||
|
|
8fb10653e4 | ||
|
|
4b4737700b | ||
|
|
44283cc889 | ||
|
|
5799665131 |
@@ -680,8 +680,10 @@
|
||||
metabase.test/with-temporary-setting-values hooks.metabase.test.util/with-temporary-setting-values
|
||||
metabase.tracing.test-util/with-span-exporter hooks.common/with-one-binding
|
||||
metabase.users-rest.api-test/with-temp-user-email! hooks.common/with-one-binding
|
||||
metabase.util.i18n/deferred-trs hooks.metabase.util.i18n/deferred-trs
|
||||
metabase.util.i18n/deferred-tru hooks.metabase.util.i18n/deferred-tru
|
||||
metabase.util.i18n-be.core/deferred-trs hooks.metabase.util.i18n/deferred-trs
|
||||
metabase.util.i18n-be.core/deferred-tru hooks.metabase.util.i18n/deferred-tru
|
||||
metabase.util.i18n-be.macros/deferred-trs hooks.metabase.util.i18n/deferred-trs
|
||||
metabase.util.i18n-be.macros/deferred-tru hooks.metabase.util.i18n/deferred-tru
|
||||
metabase.util.i18n/trs hooks.metabase.util.i18n/trs
|
||||
metabase.util.i18n/tru hooks.metabase.util.i18n/tru
|
||||
metabase.util.log.capture/with-log-messages-for-level hooks.metabase.util.log.capture/with-log-messages-for-level
|
||||
@@ -723,6 +725,7 @@
|
||||
metabase.embedding-rest.api.embed-test/with-embedding-enabled-and-temp-card-referencing! macros.metabase.embedding-rest.api.embed-test/with-embedding-enabled-and-temp-card-referencing!
|
||||
metabase.embedding-rest.api.embed-test/with-embedding-enabled-and-temp-dashcard-referencing! macros.metabase.embedding-rest.api.embed-test/with-embedding-enabled-and-temp-dashcard-referencing!
|
||||
metabase.lib.common/defop macros.metabase.lib.common/defop
|
||||
metabase.lib.common.macros/defop macros.metabase.lib.common/defop
|
||||
metabase.lib.filter/deffilter macros.metabase.lib.filter/deffilter
|
||||
metabase.parameters.chain-filter-test/chain-filter macros.metabase.parameters.chain-filter-test/chain-filter
|
||||
metabase.parameters.chain-filter-test/chain-filter-search macros.metabase.parameters.chain-filter-test/chain-filter
|
||||
|
||||
@@ -109,6 +109,7 @@
|
||||
search
|
||||
settings
|
||||
util
|
||||
util-be
|
||||
warehouses
|
||||
workspaces}
|
||||
:model-exports #{:model/Action}
|
||||
@@ -174,7 +175,8 @@
|
||||
request
|
||||
server
|
||||
settings
|
||||
util}
|
||||
util
|
||||
util-be}
|
||||
:model-imports #{:model/Card
|
||||
:model/Dashboard
|
||||
:model/DashboardCard
|
||||
@@ -310,7 +312,8 @@
|
||||
models
|
||||
permissions
|
||||
users
|
||||
util}
|
||||
util
|
||||
util-be}
|
||||
:model-exports #{:model/ApiKey}
|
||||
:model-imports #{:model/User}}
|
||||
|
||||
@@ -337,7 +340,8 @@
|
||||
config
|
||||
connection-pool
|
||||
task
|
||||
util}
|
||||
util
|
||||
util-be}
|
||||
:model-imports #{:model/Database
|
||||
:model/Field
|
||||
:model/QueryCache
|
||||
@@ -506,7 +510,8 @@
|
||||
task
|
||||
timeline
|
||||
types
|
||||
util}
|
||||
util
|
||||
util-be}
|
||||
:model-exports #{:model/Channel :model/ChannelTemplate}
|
||||
:model-imports #{:model/Dashboard
|
||||
:model/Database
|
||||
@@ -533,7 +538,8 @@
|
||||
settings
|
||||
store-api
|
||||
task
|
||||
util}
|
||||
util
|
||||
util-be}
|
||||
:model-imports #{:model/AuditLog
|
||||
:model/Card
|
||||
:model/LoginHistory
|
||||
@@ -854,6 +860,7 @@
|
||||
system
|
||||
tracing
|
||||
util
|
||||
util-be
|
||||
warehouse-schema
|
||||
warehouses
|
||||
;; `metabase.driver.sync/include-schema?` skips workspace iso schemas
|
||||
@@ -949,7 +956,8 @@
|
||||
query-processor
|
||||
request
|
||||
tiles
|
||||
util}
|
||||
util
|
||||
util-be}
|
||||
:model-imports #{:model/Card :model/Dashboard :model/EmbeddingTheme}}
|
||||
|
||||
events
|
||||
@@ -1467,6 +1475,7 @@
|
||||
models
|
||||
query-processor
|
||||
util
|
||||
util-be
|
||||
warehouse-schema
|
||||
warehouses}
|
||||
:model-imports #{:model/Card
|
||||
@@ -1536,7 +1545,8 @@
|
||||
:api #{metabase.plugins.core}
|
||||
:uses #{classloader
|
||||
driver
|
||||
util}}
|
||||
util
|
||||
util-be}}
|
||||
|
||||
premium-features
|
||||
{:team "UX West"
|
||||
@@ -1811,6 +1821,7 @@
|
||||
tracing
|
||||
users
|
||||
util
|
||||
util-be
|
||||
workspaces}
|
||||
:model-imports #{:model/Card
|
||||
:model/Dashboard
|
||||
@@ -1846,7 +1857,8 @@
|
||||
session
|
||||
settings
|
||||
users
|
||||
util}
|
||||
util
|
||||
util-be}
|
||||
:model-imports #{:model/User}}
|
||||
|
||||
revisions
|
||||
@@ -1862,7 +1874,8 @@
|
||||
models
|
||||
queries
|
||||
query-permissions
|
||||
util}
|
||||
util
|
||||
util-be}
|
||||
:model-exports #{:model/Revision}
|
||||
:model-imports #{:model/Card
|
||||
:model/Dashboard
|
||||
@@ -1918,7 +1931,8 @@
|
||||
task
|
||||
tracing
|
||||
transforms
|
||||
util}
|
||||
util
|
||||
util-be}
|
||||
:model-imports #{:model/Card
|
||||
:model/Collection
|
||||
:model/Dashboard
|
||||
@@ -1928,7 +1942,7 @@
|
||||
secrets
|
||||
{:team "Graphy"
|
||||
:api #{metabase.secrets.core}
|
||||
:uses #{api driver models premium-features util}
|
||||
:uses #{api driver models premium-features util util-be}
|
||||
:model-exports #{:model/Secret}}
|
||||
|
||||
segments
|
||||
@@ -2206,7 +2220,8 @@
|
||||
request
|
||||
task
|
||||
tracing
|
||||
util}
|
||||
util
|
||||
util-be}
|
||||
:model-exports #{:model/TaskHistory}
|
||||
:model-imports #{:model/Card :model/Dashboard :model/Database}}
|
||||
|
||||
@@ -2409,7 +2424,8 @@
|
||||
:uses #{api
|
||||
config
|
||||
lib
|
||||
util}}
|
||||
util
|
||||
util-be}}
|
||||
|
||||
users
|
||||
{:team "UX West"
|
||||
@@ -2477,6 +2493,11 @@
|
||||
settings
|
||||
system}}
|
||||
|
||||
util-be
|
||||
{:team "DevEx"
|
||||
:api :any
|
||||
:uses #{util}}
|
||||
|
||||
version
|
||||
{:team "UX West"
|
||||
:api #{metabase.version.core
|
||||
@@ -2590,7 +2611,8 @@
|
||||
secrets
|
||||
settings
|
||||
sync
|
||||
util}
|
||||
util
|
||||
util-be}
|
||||
:model-exports #{:model/Database}
|
||||
:model-imports #{:model/Card
|
||||
:model/Field
|
||||
@@ -2785,6 +2807,7 @@
|
||||
sync
|
||||
users
|
||||
util
|
||||
util-be
|
||||
enterprise/serialization}
|
||||
:model-imports #{:model/AuditLog
|
||||
:model/Card
|
||||
@@ -3276,6 +3299,7 @@
|
||||
tenants
|
||||
users
|
||||
util
|
||||
util-be
|
||||
warehouse-schema
|
||||
warehouses
|
||||
enterprise/api}
|
||||
@@ -3359,7 +3383,8 @@
|
||||
settings
|
||||
task
|
||||
tracing
|
||||
util}
|
||||
util
|
||||
util-be}
|
||||
:model-imports #{:model/Card :model/Collection :model/Dashboard}}
|
||||
|
||||
enterprise/serialization
|
||||
@@ -3417,6 +3442,7 @@
|
||||
sso
|
||||
system
|
||||
util
|
||||
util-be
|
||||
enterprise/scim}
|
||||
:model-imports #{:model/PermissionsGroup :model/Session}}
|
||||
|
||||
@@ -3513,7 +3539,8 @@
|
||||
tracing
|
||||
transforms
|
||||
transforms-base
|
||||
util}
|
||||
util
|
||||
util-be}
|
||||
:model-exports #{:model/PythonLibrary}
|
||||
:model-imports #{:model/Database
|
||||
:model/Field
|
||||
|
||||
@@ -50,12 +50,16 @@
|
||||
"Vars that are looked for for translations strings"
|
||||
#{'metabase.util.i18n/trs
|
||||
'metabase.util.i18n/tru
|
||||
'metabase.util.i18n/deferred-trs
|
||||
'metabase.util.i18n/deferred-tru
|
||||
'metabase.util.i18n/trsn
|
||||
'metabase.util.i18n/trun
|
||||
'metabase.util.i18n/deferred-trsn
|
||||
'metabase.util.i18n/deferred-trun})
|
||||
'metabase.util.i18n-be.core/deferred-trs
|
||||
'metabase.util.i18n-be.core/deferred-tru
|
||||
'metabase.util.i18n-be.core/deferred-trsn
|
||||
'metabase.util.i18n-be.core/deferred-trun
|
||||
'metabase.util.i18n-be.macros/deferred-trs
|
||||
'metabase.util.i18n-be.macros/deferred-tru
|
||||
'metabase.util.i18n-be.macros/deferred-trsn
|
||||
'metabase.util.i18n-be.macros/deferred-trun})
|
||||
|
||||
(def ^:private plural-translation-macro-names
|
||||
#{"trsn" "trun" "deferred-trsn" "deferred-trun"})
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
fix the originals in Crowdin.
|
||||
|
||||
The pure predicates live in `metabase.util.i18n.validation` so they can be shared with the
|
||||
macro-time call-site check (`metabase.util.i18n/validate-number-of-args`) and the regression-
|
||||
macro-time call-site check (`metabase.util.i18n.validation/validate-number-of-args`) and the regression-
|
||||
guard test (`metabase.util.i18n.validation-test`) without pulling in jgettext."
|
||||
(:require
|
||||
[clojure.string :as str]
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
[metabase.api.common :as api]
|
||||
[metabase.api.macros :as api.macros]
|
||||
[metabase.app-db.core :as mdb]
|
||||
[metabase.util.i18n :refer [deferred-tru]]
|
||||
[metabase.util.i18n-be.core :refer [deferred-tru]]
|
||||
[metabase.util.malli :as mu]
|
||||
[metabase.util.malli.schema :as ms]
|
||||
[toucan2.core :as t2]))
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
[clojure.string :as str]
|
||||
[metabase.settings.core :as setting :refer [defsetting]]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.i18n :refer [deferred-tru]]))
|
||||
[metabase.util.i18n-be.core :refer [deferred-tru]]))
|
||||
|
||||
(defsetting config-from-file-sync-databases
|
||||
"Whether to (asynchronously) sync newly created Databases during config-from-file initialization. By default, true,
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
(:require
|
||||
[metabase.api.open-api :as open-api]
|
||||
[metabase.premium-features.core :as premium-features]
|
||||
[metabase.util.i18n :as i18n]))
|
||||
[metabase.util.i18n-be.core :as i18n-be]))
|
||||
|
||||
(defn +require-premium-feature
|
||||
"Wraps Ring `handler`. Check that we have a premium token with `feature` (a keyword; see
|
||||
@@ -16,7 +16,7 @@
|
||||
Use [[when-premium-feature]] instead if you want the handler to apply if we have the premium feature but pass-thru
|
||||
if we do not."
|
||||
[feature feature-name handler]
|
||||
(assert (i18n/localized-string? feature-name), "`feature-name` must be i18ned")
|
||||
(assert (i18n-be/localized-string? feature-name), "`feature-name` must be i18ned")
|
||||
(open-api/handler-with-open-api-spec
|
||||
(fn [request respond raise]
|
||||
(premium-features/assert-has-feature feature feature-name)
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
[metabase-enterprise.workspaces.api]
|
||||
[metabase.api.macros :as api.macros]
|
||||
[metabase.api.util.handlers :as handlers]
|
||||
[metabase.util.i18n :refer [deferred-tru]]))
|
||||
[metabase.util.i18n-be.core :refer [deferred-tru]]))
|
||||
|
||||
(comment metabase-enterprise.advanced-config.api.logs/keep-me)
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
[metabase.sync.core :as sync]
|
||||
[metabase.sync.util :as sync-util]
|
||||
[metabase.util :as u]
|
||||
[metabase.util-be.core :as util-be]
|
||||
[metabase.util.files :as u.files]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.log :as log]
|
||||
@@ -214,10 +215,10 @@
|
||||
files (single hash over sorted pairs)."
|
||||
([root] (directory-content-checksum root ""))
|
||||
([^Path root suffix]
|
||||
(with-open [stream (Files/walk root (u/varargs FileVisitOption))]
|
||||
(with-open [stream (Files/walk root (util-be/varargs FileVisitOption))]
|
||||
(->> (iterator-seq (.iterator stream))
|
||||
(filter (fn [^Path p]
|
||||
(and (Files/isRegularFile p (u/varargs LinkOption))
|
||||
(and (Files/isRegularFile p (util-be/varargs LinkOption))
|
||||
(str/ends-with? (str (.getFileName p)) suffix))))
|
||||
(mapv (fn [^Path path]
|
||||
[(str (.relativize root path))
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
[metabase.store-api.core :as store-api]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.date-2.parse :as u.date.parse]
|
||||
[metabase.util.i18n :as i18n]
|
||||
[metabase.util.i18n-be.core :as i18n-be]
|
||||
[metabase.util.json :as json]
|
||||
[toucan2.core :as t2])
|
||||
(:import
|
||||
@@ -67,7 +67,7 @@
|
||||
[]
|
||||
(let [token (premium-features/premium-embedding-token)
|
||||
email (t2/select-one-fn :email :model/User :id api/*current-user-id*)
|
||||
language (i18n/user-locale-string)]
|
||||
language (i18n-be/user-locale-string)]
|
||||
(if (and token (str/starts-with? token "airgap_"))
|
||||
(billing-status)
|
||||
(fetch-billing-status* token email language))))
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
[metabase.events.core :as events]
|
||||
[metabase.premium-features.core :as premium-features]
|
||||
[metabase.store-api.core :as store-api]
|
||||
[metabase.util.i18n :refer [deferred-tru tru]]
|
||||
[metabase.util.i18n :refer [tru]]
|
||||
[metabase.util.i18n-be.core :refer [deferred-tru]]
|
||||
[metabase.util.log :as log]))
|
||||
|
||||
(def ^:private requires-terms-of-service?
|
||||
|
||||
@@ -7,7 +7,8 @@
|
||||
[clojure.string :as str]
|
||||
[metabase.premium-features.core :as premium-features]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.i18n :as i18n :refer [tru]]
|
||||
[metabase.util.i18n :refer [tru]]
|
||||
[metabase.util.i18n-be.core :as i18n-be]
|
||||
[toucan2.core :as t2]))
|
||||
|
||||
(set! *warn-on-reflection* true)
|
||||
@@ -30,7 +31,7 @@
|
||||
(defn- collect-locale-error
|
||||
"Returns an error message if a row does not have a valid locale."
|
||||
[_state index {:keys [locale]}]
|
||||
(when (not (i18n/included-locale? locale))
|
||||
(when (not (i18n-be/included-locale? locale))
|
||||
(tru "Row {0}: Invalid locale: {1}" (adjust-index index) locale)))
|
||||
|
||||
(defn- collect-duplication-error
|
||||
@@ -58,7 +59,7 @@
|
||||
(get row-with-headers "locale code"))
|
||||
msgid (get row-with-headers "string")
|
||||
msgstr (get row-with-headers "translation")
|
||||
normalized-locale (i18n/normalized-locale-string (str/trim locale))
|
||||
normalized-locale (i18n-be/normalized-locale-string (str/trim locale))
|
||||
formatted-locale (if (nil? normalized-locale)
|
||||
(str/trim locale)
|
||||
normalized-locale)
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
[metabase.api.macros :as api.macros]
|
||||
[metabase.content-translation.models :as ct]
|
||||
[metabase.embedding.jwt :as embedding.jwt]
|
||||
[metabase.util.i18n :as i18n :refer [deferred-tru tru]]
|
||||
[metabase.util.i18n :refer [tru]]
|
||||
[metabase.util.i18n-be.core :as i18n-be :refer [deferred-tru]]
|
||||
[metabase.util.malli.schema :as ms]))
|
||||
|
||||
(set! *warn-on-reflection* true)
|
||||
@@ -98,7 +99,7 @@
|
||||
;; this will error if bad
|
||||
(embedding.jwt/unsign token)
|
||||
(if locale
|
||||
{:data (ct/get-translations (i18n/normalized-locale-string (str/trim locale)))}
|
||||
{:data (ct/get-translations (i18n-be/normalized-locale-string (str/trim locale)))}
|
||||
(throw (ex-info (str (tru "Locale is required.")) {:status-code 400}))))
|
||||
|
||||
(api.macros/defendpoint :get "/dictionary" :- DictionaryResponse
|
||||
@@ -106,7 +107,7 @@
|
||||
[_route-params
|
||||
{:keys [locale]} :- [:map [:locale :string]]]
|
||||
(api/check api/*current-user-id* 401 "Unauthenticated")
|
||||
{:data (ct/get-translations (i18n/normalized-locale-string (str/trim locale)))})
|
||||
{:data (ct/get-translations (i18n-be/normalized-locale-string (str/trim locale)))})
|
||||
|
||||
(defn- +require-content-translation [handler]
|
||||
(ee.api/+require-premium-feature :content-translation (deferred-tru "Content translation") handler))
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
[metabase-enterprise.content-verification.api.moderation-review]
|
||||
[metabase.api.macros :as api.macros]
|
||||
[metabase.api.routes.common :refer [+auth]]
|
||||
[metabase.util.i18n :refer [deferred-tru]]))
|
||||
[metabase.util.i18n-be.core :refer [deferred-tru]]))
|
||||
|
||||
(comment metabase-enterprise.content-verification.api.moderation-review/keep-me)
|
||||
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
[metabase.premium-features.core :refer [defenterprise]]
|
||||
[metabase.server.settings :as server.settings]
|
||||
[metabase.settings.core :as setting :refer [defsetting]]
|
||||
[metabase.util.i18n :refer [deferred-tru tru]]))
|
||||
[metabase.util.i18n :refer [tru]]
|
||||
[metabase.util.i18n-be.core :refer [deferred-tru]]))
|
||||
|
||||
(defsetting custom-viz-plugin-dev-mode-enabled
|
||||
(deferred-tru "Whether custom visualization plugin dev mode is enabled. When false, the dev endpoints are disabled.")
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
(:require
|
||||
[metabase.premium-features.core :as premium-features]
|
||||
[metabase.settings.core :refer [defsetting]]
|
||||
[metabase.util.i18n :refer [deferred-tru]]))
|
||||
[metabase.util.i18n-be.core :refer [deferred-tru]]))
|
||||
|
||||
(defsetting ^:deprecated data-complexity-scoring-enabled
|
||||
(deferred-tru
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
(:require
|
||||
[metabase.premium-features.core :as premium-features]
|
||||
[metabase.settings.core :as setting :refer [defsetting]]
|
||||
[metabase.util.i18n :refer [deferred-tru]]))
|
||||
[metabase.util.i18n-be.core :refer [deferred-tru]]))
|
||||
|
||||
(defsetting database-replication-enabled
|
||||
(deferred-tru "When enabled, we show users a button to replicate their database to a data warehouse.")
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
[metabase.premium-features.core :as premium-features]
|
||||
[metabase.settings.core :as setting :refer [defsetting]]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.i18n :refer [deferred-tru]]
|
||||
[metabase.util.i18n-be.core :refer [deferred-tru]]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.malli :as mu]
|
||||
[metabase.util.malli.registry :as mr]
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"Enterprise-only metabot settings for usage limits."
|
||||
(:require
|
||||
[metabase.settings.core :as setting :refer [defsetting]]
|
||||
[metabase.util.i18n :refer [deferred-tru]]))
|
||||
[metabase.util.i18n-be.core :refer [deferred-tru]]))
|
||||
|
||||
(def ^:private valid-limit-units #{:tokens :messages})
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
[metabase-enterprise.remote-sync.source.git :as git]
|
||||
[metabase.collections.models.collection :as collection]
|
||||
[metabase.settings.core :as setting :refer [defsetting]]
|
||||
[metabase.util.i18n :refer [deferred-tru]]
|
||||
[metabase.util.i18n-be.core :refer [deferred-tru]]
|
||||
[toucan2.core :as t2]))
|
||||
|
||||
(set! *warn-on-reflection* true)
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
[metabase.api.macros :as api.macros]
|
||||
[metabase.api.routes.common :refer [+auth]]
|
||||
[metabase.api.util.handlers :as handlers]
|
||||
[metabase.util.i18n :refer [deferred-tru]]))
|
||||
[metabase.util.i18n-be.core :refer [deferred-tru]]))
|
||||
|
||||
(comment metabase-enterprise.sandbox.api.table/keep-me)
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
[metabase.api.common :as api]
|
||||
[metabase.api.macros :as api.macros]
|
||||
[metabase.tenants.core :as tenants]
|
||||
[metabase.util.i18n :refer [deferred-tru]]
|
||||
[metabase.util.i18n-be.core :refer [deferred-tru]]
|
||||
[metabase.util.malli :as mu]
|
||||
[metabase.util.malli.schema :as ms]
|
||||
[toucan2.core :as t2]))
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
[metabase.query-processor.util.persisted-cache :as qp.persisted]
|
||||
[metabase.request.core :as request]
|
||||
[metabase.util :as u]
|
||||
[metabase.util-be.core :as util-be]
|
||||
[metabase.util.i18n :refer [tru]]
|
||||
[metabase.util.log :as log]
|
||||
[metabase.util.malli :as mu]
|
||||
@@ -165,7 +166,7 @@
|
||||
persisted? (qp.persisted/can-substitute? card persisted-info)
|
||||
query (lib/card->underlying-query metadata-providerable card)]
|
||||
;; log the query at this point, it's useful for some purposes
|
||||
(log/debugf "Fetched query from Card %s:\n%s" card-id (u/cprint-to-str (select-keys query [:stages :parameters])))
|
||||
(log/debugf "Fetched query from Card %s:\n%s" card-id (util-be/cprint-to-str (select-keys query [:stages :parameters])))
|
||||
(cond-> query
|
||||
;; This will be applied, if still appropriate, by the persistence middleware
|
||||
persisted?
|
||||
@@ -372,8 +373,8 @@
|
||||
replacement-stages (cond-> new-source-stages
|
||||
wrapper-stage (conj wrapper-stage))]
|
||||
(log/tracef "Applied Sandbox: replaced stage\n\n%s\n\nwith stages\n\n%s"
|
||||
(u/cprint-to-str stage)
|
||||
(u/cprint-to-str replacement-stages))
|
||||
(util-be/cprint-to-str stage)
|
||||
(util-be/cprint-to-str replacement-stages))
|
||||
replacement-stages))
|
||||
|
||||
(mu/defn- apply-sandboxes :- ::lib.schema/query
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
(:require
|
||||
[metabase.settings.core :refer [defsetting]]
|
||||
[metabase.system.core :as system]
|
||||
[metabase.util.i18n :refer [deferred-tru]]))
|
||||
[metabase.util.i18n-be.core :refer [deferred-tru]]))
|
||||
|
||||
(defsetting scim-enabled
|
||||
(deferred-tru "Is SCIM currently enabled?")
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
[metabase.permissions.core :as perms]
|
||||
[metabase.users.schema :as users.schema]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.i18n :as i18n]
|
||||
[metabase.util.i18n-be.core :as i18n-be]
|
||||
[metabase.util.malli :as mu]
|
||||
[metabase.util.malli.schema :as ms]
|
||||
[ring.util.codec :as codec]
|
||||
@@ -183,7 +183,7 @@
|
||||
:is_active is-active?
|
||||
:type :personal
|
||||
:sso_source "scim"}
|
||||
(when (and locale (i18n/available-locale? locale))
|
||||
(when (and locale (i18n-be/available-locale? locale))
|
||||
{:locale locale}))))
|
||||
|
||||
(mu/defn ^:private get-user-by-entity-id
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
(:require
|
||||
[metabase.permissions.core :as perms]
|
||||
[metabase.settings.core :as setting :refer [defsetting]]
|
||||
[metabase.util.i18n :refer [deferred-tru]]))
|
||||
[metabase.util.i18n-be.core :refer [deferred-tru]]))
|
||||
|
||||
(defsetting security-center-email-recipients
|
||||
(deferred-tru "List of email recipients for Security Center notifications.")
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
[metabase.premium-features.core :as premium-features]
|
||||
[metabase.tracing.core :as tracing]
|
||||
[metabase.util :as u]
|
||||
[metabase.util-be.core :as util-be]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.log :as log]
|
||||
[metabase.util.malli :as mu])
|
||||
@@ -75,7 +76,7 @@
|
||||
[data]
|
||||
(vec
|
||||
(for [{:keys [embedding]} data]
|
||||
(let [bytes (u/decode-base64-to-bytes ^String embedding)
|
||||
(let [bytes (util-be/decode-base64-to-bytes ^String embedding)
|
||||
buffer (doto (java.nio.ByteBuffer/wrap bytes)
|
||||
(.order java.nio.ByteOrder/LITTLE_ENDIAN))
|
||||
length (/ (alength bytes) 4)
|
||||
@@ -390,24 +391,24 @@
|
||||
{:search.semantic/provider provider
|
||||
:search.semantic/model-name model-name
|
||||
:search.semantic/text-count (count texts)}
|
||||
(u/profile (str "Generating embeddings " {:model model-name
|
||||
:dimensions vector-dimensions
|
||||
:texts (calc-token-metrics texts)})
|
||||
(if (= "openai" provider)
|
||||
(let [max-tokens-per-batch (semantic-settings/openai-max-tokens-per-batch)
|
||||
batches (create-batches max-tokens-per-batch count-tokens texts)
|
||||
(util-be/profile (str "Generating embeddings " {:model model-name
|
||||
:dimensions vector-dimensions
|
||||
:texts (calc-token-metrics texts)})
|
||||
(if (= "openai" provider)
|
||||
(let [max-tokens-per-batch (semantic-settings/openai-max-tokens-per-batch)
|
||||
batches (create-batches max-tokens-per-batch count-tokens texts)
|
||||
|
||||
process-batch
|
||||
(fn [batch-idx batch-texts]
|
||||
(let [embeddings (u/profile (format "Embedding batch %d/%d %s"
|
||||
(inc batch-idx) (count batches) (str (calc-token-metrics batch-texts)))
|
||||
(get-embeddings-batch embedding-model batch-texts opts))
|
||||
text-embedding-map (zipmap batch-texts embeddings)]
|
||||
(process-fn text-embedding-map)))]
|
||||
(transduce (map-indexed process-batch) (partial merge-with +) batches))
|
||||
(let [embeddings (get-embeddings-batch embedding-model texts opts)
|
||||
text-embedding-map (zipmap texts embeddings)]
|
||||
(process-fn text-embedding-map))))))))
|
||||
process-batch
|
||||
(fn [batch-idx batch-texts]
|
||||
(let [embeddings (util-be/profile (format "Embedding batch %d/%d %s"
|
||||
(inc batch-idx) (count batches) (str (calc-token-metrics batch-texts)))
|
||||
(get-embeddings-batch embedding-model batch-texts opts))
|
||||
text-embedding-map (zipmap batch-texts embeddings)]
|
||||
(process-fn text-embedding-map)))]
|
||||
(transduce (map-indexed process-batch) (partial merge-with +) batches))
|
||||
(let [embeddings (get-embeddings-batch embedding-model texts opts)
|
||||
text-embedding-map (zipmap texts embeddings)]
|
||||
(process-fn text-embedding-map))))))))
|
||||
|
||||
(comment
|
||||
;; Configuration:
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
[metabase-enterprise.semantic-search.settings :as semantic.settings]
|
||||
[metabase.analytics-interface.core :as analytics]
|
||||
[metabase.util :as u]
|
||||
[metabase.util-be.core :as util-be]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.log :as log]
|
||||
[next.jdbc :as jdbc]
|
||||
@@ -62,7 +63,7 @@
|
||||
:updated_at default-updated-at})
|
||||
|
||||
(defn- document-hash [search-doc]
|
||||
(u/encode-base64-bytes (buddy-hash/sha1 (json/encode (into (sorted-map) search-doc)))))
|
||||
(util-be/encode-base64-bytes (buddy-hash/sha1 (json/encode (into (sorted-map) search-doc)))))
|
||||
|
||||
(defn- ->instant
|
||||
^Instant [inst]
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
[metabase.search.core :as search]
|
||||
[metabase.tracing.core :as tracing]
|
||||
[metabase.util :as u]
|
||||
[metabase.util-be.core :as util-be]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.log :as log]
|
||||
[next.jdbc :as jdbc]
|
||||
@@ -220,12 +221,12 @@
|
||||
[connectable table-name records->sql documents]
|
||||
(when (seq documents)
|
||||
(u/prog1 (->> documents (map :model) frequencies)
|
||||
(u/profile (str "Semantic index database update of " (count documents) " documents " <>)
|
||||
(let [owner-ids (batch-resolve-personal-owner-ids (map :collection_id documents))]
|
||||
(doseq [batch (->> (map #(doc->db-record owner-ids %) documents)
|
||||
(partition-all *batch-size*))]
|
||||
(jdbc/execute! connectable (records->sql batch))))
|
||||
(analytics-set-index-size! connectable table-name)))))
|
||||
(util-be/profile (str "Semantic index database update of " (count documents) " documents " <>)
|
||||
(let [owner-ids (batch-resolve-personal-owner-ids (map :collection_id documents))]
|
||||
(doseq [batch (->> (map #(doc->db-record owner-ids %) documents)
|
||||
(partition-all *batch-size*))]
|
||||
(jdbc/execute! connectable (records->sql batch))))
|
||||
(analytics-set-index-size! connectable table-name)))))
|
||||
|
||||
(defn- execute-with-counts [connectable model ids sql]
|
||||
(jdbc/execute! connectable sql)
|
||||
@@ -341,20 +342,20 @@
|
||||
embeddable-texts (keys text->docs)
|
||||
upsert-embedding! (upsert-embedding!-fn connectable index text->docs)
|
||||
[new-texts stats]
|
||||
(u/profile (str "Semantic search embedding caching attempt for " {:docs (count documents) :texts (count embeddable-texts)})
|
||||
(let [[new-texts existing-embeddings] (partition-existing-embeddings connectable index embeddable-texts)]
|
||||
(if-not (seq existing-embeddings)
|
||||
[embeddable-texts nil]
|
||||
(u/profile (str "Semantic search cached embedding db update for " {:texts (count existing-embeddings)})
|
||||
[new-texts (upsert-embedding! existing-embeddings)]))))]
|
||||
(util-be/profile (str "Semantic search embedding caching attempt for " {:docs (count documents) :texts (count embeddable-texts)})
|
||||
(let [[new-texts existing-embeddings] (partition-existing-embeddings connectable index embeddable-texts)]
|
||||
(if-not (seq existing-embeddings)
|
||||
[embeddable-texts nil]
|
||||
(util-be/profile (str "Semantic search cached embedding db update for " {:texts (count existing-embeddings)})
|
||||
[new-texts (upsert-embedding! existing-embeddings)]))))]
|
||||
(->>
|
||||
(when (seq new-texts)
|
||||
(u/profile (str "Semantic search embedding generation and db update for " {:docs (count documents) :texts (count new-texts)})
|
||||
(embedding/process-embeddings-streaming
|
||||
(:embedding-model index)
|
||||
new-texts
|
||||
upsert-embedding!
|
||||
opts)))
|
||||
(util-be/profile (str "Semantic search embedding generation and db update for " {:docs (count documents) :texts (count new-texts)})
|
||||
(embedding/process-embeddings-streaming
|
||||
(:embedding-model index)
|
||||
new-texts
|
||||
upsert-embedding!
|
||||
opts)))
|
||||
(merge-with + stats)))))
|
||||
|
||||
(def ^:private ^:dynamic *retrying* false)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
[metabase.premium-features.core :as premium-features]
|
||||
[metabase.search.config :as search.config]
|
||||
[metabase.settings.core :as setting :refer [defsetting]]
|
||||
[metabase.util.i18n :refer [deferred-tru]]))
|
||||
[metabase.util.i18n-be.core :refer [deferred-tru]]))
|
||||
|
||||
(def ^:private valid-embedding-providers
|
||||
"The set of valid embedding provider names."
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
[metabase.session.core :as session]
|
||||
[metabase.system.core :as system]
|
||||
[metabase.util :as u]
|
||||
[metabase.util-be.core :as util-be]
|
||||
[metabase.util.log :as log]
|
||||
[metabase.util.malli :as mu]
|
||||
[metabase.util.malli.schema :as ms]
|
||||
@@ -105,7 +106,7 @@
|
||||
:idp-url (sso-settings/saml-identity-provider-slo-uri)
|
||||
:issuer (sso-settings/saml-application-name)
|
||||
:user-email email
|
||||
:relay-state (u/encode-base64
|
||||
:relay-state (util-be/encode-base64
|
||||
(str (system/site-url) metabase-slo-redirect-url))))}))
|
||||
|
||||
;; POST /auth/sso/to_session
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
[metabase.session.core :as session]
|
||||
[metabase.system.core :as system]
|
||||
[metabase.util :as u]
|
||||
[metabase.util-be.core :as util-be]
|
||||
[metabase.util.i18n :refer [trs tru]]
|
||||
[metabase.util.log :as log]
|
||||
[ring.util.response :as response]
|
||||
@@ -135,7 +136,7 @@
|
||||
"Process the RelayState to extract continue URL and related parameters"
|
||||
[relay-state]
|
||||
(let [continue-url (u/ignore-exceptions
|
||||
(when-let [s (some-> relay-state u/decode-base64)]
|
||||
(when-let [s (some-> relay-state util-be/decode-base64)]
|
||||
(when-not (str/blank? s)
|
||||
s)))
|
||||
;; Extract token value from URL parameter
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
[metabase.sso.core :as sso]
|
||||
[metabase.system.core :as system]
|
||||
[metabase.util :as u]
|
||||
[metabase.util-be.core :as util-be]
|
||||
[metabase.util.i18n :refer [tru]]
|
||||
[metabase.util.log :as log]
|
||||
[methodical.core :as methodical]
|
||||
@@ -77,7 +78,7 @@
|
||||
(try
|
||||
(let [idp-url (sso-settings/saml-identity-provider-uri)
|
||||
relay-state (when redirect-url
|
||||
(u/encode-base64 redirect-url))
|
||||
(util-be/encode-base64 redirect-url))
|
||||
response (saml/idp-redirect-response {:request-id (str "id-" (random-uuid))
|
||||
:sp-name (sso-settings/saml-application-name)
|
||||
:issuer (sso-settings/saml-application-name)
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
[metabase.appearance.core :as appearance]
|
||||
[metabase.settings.core :as setting :refer [define-multi-setting-impl defsetting]]
|
||||
[metabase.system.core :as system]
|
||||
[metabase.util.i18n :refer [deferred-tru tru]]
|
||||
[metabase.util.i18n :refer [tru]]
|
||||
[metabase.util.i18n-be.core :refer [deferred-tru]]
|
||||
[metabase.util.log :as log]
|
||||
[metabase.util.malli :as mu]
|
||||
[metabase.util.malli.registry :as mr]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
(ns metabase-enterprise.stale.settings
|
||||
(:require
|
||||
[metabase.settings.core :refer [defsetting]]
|
||||
[metabase.util.i18n :refer [deferred-tru]]))
|
||||
[metabase.util.i18n-be.core :refer [deferred-tru]]))
|
||||
|
||||
(defsetting dismissed-collection-cleanup-banner
|
||||
(deferred-tru "Was the collection cleanup banner dismissed?")
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
(ns metabase-enterprise.support-access-grants.settings
|
||||
(:require
|
||||
[metabase.settings.core :refer [defsetting]]
|
||||
[metabase.util.i18n :refer [deferred-tru]]))
|
||||
[metabase.util.i18n-be.core :refer [deferred-tru]]))
|
||||
|
||||
(defsetting support-access-grant-email
|
||||
(deferred-tru "Email to grant temporary access to for support")
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
[metabase.collections.models.collection :as collection]
|
||||
[metabase.events.core :as events]
|
||||
[metabase.request.core :as request]
|
||||
[metabase.util.i18n :refer [deferred-tru]]
|
||||
[metabase.util.i18n-be.core :refer [deferred-tru]]
|
||||
[metabase.util.malli :as mu]
|
||||
[metabase.util.malli.registry :as mr]
|
||||
[metabase.util.malli.schema :as ms]
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
[metabase.models.interface :as mi]
|
||||
[metabase.premium-features.core :refer [defenterprise]]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.i18n :refer [deferred-tru tru]]
|
||||
[metabase.util.i18n :refer [tru]]
|
||||
[metabase.util.i18n-be.core :refer [deferred-tru]]
|
||||
[metabase.util.malli :as mu]
|
||||
[metabase.util.malli.schema :as ms]
|
||||
[methodical.core :as methodical]
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
[metabase.api.util.handlers :as handlers]
|
||||
[metabase.permissions.core :as perms]
|
||||
[metabase.transforms-base.util :as transforms-base.u]
|
||||
[metabase.util.i18n :as i18n]
|
||||
[metabase.util.i18n-be.core :as i18n-be]
|
||||
[metabase.util.malli.schema :as ms]
|
||||
[toucan2.core :as t2]))
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
(api.macros/defendpoint :post "/test-run"
|
||||
:- [:map
|
||||
[:logs :string]
|
||||
[:error {:optional true} [:map [:message i18n/LocalizedString]]]
|
||||
[:error {:optional true} [:map [:message i18n-be/LocalizedString]]]
|
||||
[:output {:optional true} [:map
|
||||
[:cols [:sequential [:map [:name :string]]]]
|
||||
[:rows [:sequential :any]]]]]
|
||||
@@ -68,7 +68,7 @@
|
||||
[:output_row_limit {:optional true} [:and :int [:> 1] [:<= 100]]]
|
||||
[:per_input_row_limit {:optional true} [:and :int [:> 1] [:<= 100]]]]]
|
||||
(let [db-ids (t2/select-fn-set :db_id [:model/Table :db_id] :id [:in (map :table_id source_tables)])]
|
||||
(api/check-400 (= (count db-ids) 1) (i18n/deferred-tru "All source tables must belong to the same database."))
|
||||
(api/check-400 (= (count db-ids) 1) (i18n-be/deferred-tru "All source tables must belong to the same database."))
|
||||
(api/check-403 (perms/has-db-transforms-permission? api/*current-user-id* (first db-ids))))
|
||||
;; NOTE: we do not test database support, as there is no write target.
|
||||
(let [result (python-runner/execute-and-read-output!
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
[metabase.transforms-base.util :as transforms-base.u]
|
||||
[metabase.transforms.instrumentation :as transforms.instrumentation]
|
||||
[metabase.util :as u]
|
||||
[metabase.util-be.core :as util-be]
|
||||
[metabase.util.format :as u.format]
|
||||
[metabase.util.i18n :as i18n]
|
||||
[metabase.util.log :as log]
|
||||
@@ -117,9 +118,9 @@
|
||||
"Transfer data using the rename-tables*! multimethod with atomicity guarantees."
|
||||
[driver db-id table-name metadata data-source]
|
||||
(let [source-table-name (transforms-base.u/temp-table-name driver (namespace table-name))
|
||||
temp-table-name (u/poll {:thunk #(transforms-base.u/temp-table-name driver (namespace table-name))
|
||||
:done? #(not= source-table-name %)
|
||||
:interval-ms 1})]
|
||||
temp-table-name (util-be/poll {:thunk #(transforms-base.u/temp-table-name driver (namespace table-name))
|
||||
:done? #(not= source-table-name %)
|
||||
:interval-ms 1})]
|
||||
(log/info "Using rename-tables strategy with atomicity guarantees")
|
||||
(try
|
||||
(create-table-and-insert-data! driver db-id (table-schema source-table-name metadata) data-source)
|
||||
@@ -261,7 +262,7 @@
|
||||
:events events
|
||||
:timeout (:timeout body)}))
|
||||
(try
|
||||
(let [temp-path (Files/createTempFile "transform-output-" ".jsonl" (u/varargs FileAttribute))
|
||||
(let [temp-path (Files/createTempFile "transform-output-" ".jsonl" (util-be/varargs FileAttribute))
|
||||
temp-file ^File (.toFile temp-path)]
|
||||
(when-not (seq (:fields output-manifest))
|
||||
(throw (ex-info "No fields in metadata"
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
[metabase.transforms.instrumentation :as transforms.instrumentation]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.i18n :as i18n]
|
||||
[metabase.util.i18n-be.core :as i18n-be]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.log :as log]
|
||||
[metabase.util.malli :as mu]
|
||||
@@ -371,12 +372,12 @@
|
||||
(:timeout body)
|
||||
{:status :failed
|
||||
:logs events
|
||||
:message (i18n/deferred-tru "Python execution timed out")}
|
||||
:message (i18n-be/deferred-tru "Python execution timed out")}
|
||||
|
||||
(not= 200 status)
|
||||
{:status :failed
|
||||
:logs events
|
||||
:message (i18n/deferred-tru "Python execution failure (exit code {0})" (:exit_code body "?"))}
|
||||
:message (i18n-be/deferred-tru "Python execution failure (exit code {0})" (:exit_code body "?"))}
|
||||
|
||||
:else
|
||||
(let [output-manifest (read-output-manifest @shared-storage-ref)
|
||||
@@ -386,7 +387,7 @@
|
||||
#_(if-not (seq fields)
|
||||
{:status :failed
|
||||
:logs events
|
||||
:message (i18n/deferred-tru "No fields in output metadata")})
|
||||
:message (i18n-be/deferred-tru "No fields in output metadata")})
|
||||
(with-open [in (open-output @shared-storage-ref)
|
||||
rdr (io/reader in)]
|
||||
(let [cols (mapv (fn [c]
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
(:require
|
||||
[metabase.config.core :as config]
|
||||
[metabase.settings.core :as setting]
|
||||
[metabase.util.i18n :refer [deferred-tru]]))
|
||||
[metabase.util.i18n-be.core :refer [deferred-tru]]))
|
||||
|
||||
(setting/defsetting python-runner-url
|
||||
(deferred-tru "URL for the Python execution server that runs transform functions.")
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
(ns metabase-enterprise.workspaces.settings
|
||||
(:require
|
||||
[metabase.settings.core :refer [defsetting]]
|
||||
[metabase.util.i18n :refer [deferred-tru]]))
|
||||
[metabase.util.i18n-be.core :refer [deferred-tru]]))
|
||||
|
||||
(def keep-me
|
||||
"Marker so callers can `(comment ...keep-me)` to retain the require that registers the settings in this ns."
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
[metabase.test :as mt]
|
||||
[metabase.transforms.core :as transforms]
|
||||
[metabase.transforms.test-util :refer [with-transform-cleanup!]]
|
||||
[metabase.util :as u]
|
||||
[metabase.util-be.core :as util-be]
|
||||
[toucan2.core :as t2]))
|
||||
|
||||
(set! *warn-on-reflection* true)
|
||||
@@ -319,7 +319,7 @@
|
||||
(replacement.protocols/advance! progress)))]
|
||||
;; Poll until done
|
||||
(replacement.execute/execute-async! work-fn progress)
|
||||
(u/deref-with-timeout done? 2000)
|
||||
(util-be/deref-with-timeout done? 2000)
|
||||
(is (=? {:total 3 :so-far 3 :status :succeeded}
|
||||
@state))))))
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
[metabase-enterprise.replacement.models.replacement-run :as replacement-run]
|
||||
[metabase-enterprise.replacement.protocols :as replacement.protocols]
|
||||
[metabase.test :as mt]
|
||||
[metabase.util :as u]
|
||||
[metabase.util-be.core :as util-be]
|
||||
[toucan2.core :as t2]))
|
||||
|
||||
(set! *warn-on-reflection* true)
|
||||
@@ -30,7 +30,7 @@
|
||||
(replacement.protocols/advance! progress)))
|
||||
progress)
|
||||
;; wait for virtual thread
|
||||
(is (= :run/success (u/deref-with-timeout done? 500)))
|
||||
(is (= :run/success (util-be/deref-with-timeout done? 500)))
|
||||
;; Writes at items 50, 100, 120 (final) → progress 50/120, 100/120, 120/120
|
||||
(is (= [(double (/ 50 120)) (double (/ 100 120)) 1.0]
|
||||
@writes))
|
||||
@@ -57,7 +57,7 @@
|
||||
(replacement.protocols/advance! progress 30)
|
||||
(replacement.protocols/advance! progress 10))
|
||||
progress)
|
||||
(is (= :run/success (u/deref-with-timeout done? 500)))
|
||||
(is (= :run/success (util-be/deref-with-timeout done? 500)))
|
||||
;; advance(30): 0→30, crosses 0/50→0/50 boundary? quot(0,50)=0, quot(30,50)=0 → no
|
||||
;; advance(30): 30→60, crosses? quot(30,50)=0, quot(60,50)=1 → yes, writes 0.6
|
||||
;; advance(30): 60→90, crosses? quot(60,50)=1, quot(90,50)=1 → no
|
||||
@@ -91,7 +91,7 @@
|
||||
(replacement-run/cancel-run! (:id record))
|
||||
(deliver pause :continue)
|
||||
;; Poll until run is no longer active (cancel-run! flips is_active)
|
||||
(is (= :run/cancelled (u/deref-with-timeout done? 500)))
|
||||
(is (= :run/cancelled (util-be/deref-with-timeout done? 500)))
|
||||
;; First boundary write at 50/100 succeeds, canceled? is false.
|
||||
;; cancel-run! sets is_active=nil. Next boundary at 100 writes progress,
|
||||
;; then checks canceled? → true → throws. Both writes happen.
|
||||
@@ -112,7 +112,7 @@
|
||||
(throw (ex-info "1 of 5 entities failed\n [:card 42]: boom"
|
||||
{:failures [{:entity [:card 42] :error "boom"}]})))
|
||||
progress)
|
||||
(is (= :run/fail (u/deref-with-timeout done? 500)))
|
||||
(is (= :run/fail (util-be/deref-with-timeout done? 500)))
|
||||
(let [run (t2/select-one :model/ReplacementRun :id (:id record))]
|
||||
(is (= :failed (:status run)))
|
||||
(is (str/starts-with? (:message run) "1 of 5 entities failed"))))))))
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
[metabase-enterprise.semantic-search.index-metadata :as semantic.index-metadata]
|
||||
[metabase-enterprise.semantic-search.test-util :as semantic.tu]
|
||||
[metabase.test :as mt]
|
||||
[metabase.util :as u]
|
||||
[metabase.util-be.core :as util-be]
|
||||
[metabase.util.json :as json]
|
||||
[next.jdbc :as jdbc]
|
||||
[next.jdbc.result-set :as jdbc.rs])
|
||||
@@ -46,7 +46,7 @@
|
||||
:document (doto (PGobject.)
|
||||
(.setType "jsonb")
|
||||
(.setValue (json/encode search-doc)))
|
||||
:document_hash (u/encode-base64-bytes (buddy-hash/sha1 (json/encode (into (sorted-map) search-doc))))
|
||||
:document_hash (util-be/encode-base64-bytes (buddy-hash/sha1 (json/encode (into (sorted-map) search-doc))))
|
||||
:updated_at (:updated_at search-doc)}
|
||||
(sut search-doc t2)))
|
||||
(testing "uses default updated_at when search doc has none"
|
||||
@@ -80,7 +80,7 @@
|
||||
(walk/postwalk
|
||||
(fn [x]
|
||||
(cond
|
||||
(bytes? x) (u/encode-base64-bytes x)
|
||||
(bytes? x) (util-be/encode-base64-bytes x)
|
||||
(inst? x) (inst-ms x)
|
||||
(instance? PGobject x) (json/decode (.getValue ^PGobject x))
|
||||
:else x))
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
[metabase.test.fixtures :as fixtures]
|
||||
[metabase.test.http-client :as client]
|
||||
[metabase.util :as u]
|
||||
[metabase.util-be.core :as util-be]
|
||||
[ring.util.codec :as codec]
|
||||
[saml20-clj.core :as saml]
|
||||
[toucan2.core :as t2])
|
||||
@@ -188,7 +189,7 @@
|
||||
base-64 (-> location uri->params-map :SAMLRequest)
|
||||
xml (-> base-64
|
||||
codec/url-decode
|
||||
u/decode-base64-to-bytes
|
||||
util-be/decode-base64-to-bytes
|
||||
byte-inflate
|
||||
bytes->str
|
||||
(str/replace #"\n+" "")
|
||||
@@ -247,10 +248,10 @@
|
||||
(testing (format "result = %s" (pr-str result))
|
||||
(is (string? redirect-url))
|
||||
(is (= default-redirect-uri
|
||||
(u/decode-base64 (:RelayState (uri->params-map redirect-url))))))))))))
|
||||
(util-be/decode-base64 (:RelayState (uri->params-map redirect-url))))))))))))
|
||||
|
||||
(defn- saml-response-from-file [filename]
|
||||
(u/encode-base64 (slurp filename)))
|
||||
(util-be/encode-base64 (slurp filename)))
|
||||
|
||||
(defn- saml-test-response []
|
||||
(saml-response-from-file "test_resources/saml-test-response.xml"))
|
||||
@@ -280,7 +281,7 @@
|
||||
{:request-options {:content-type :x-www-form-urlencoded
|
||||
:redirect-strategy :none
|
||||
:form-params {:SAMLResponse saml-response
|
||||
:RelayState (u/encode-base64 relay-state)}}})
|
||||
:RelayState (util-be/encode-base64 relay-state)}}})
|
||||
|
||||
(defn- extract-csp-script-nonce
|
||||
"Pull the `'nonce-<value>'` out of the Content-Security-Policy `script-src` directive."
|
||||
@@ -706,12 +707,12 @@
|
||||
(testing (format "\nresult =\n%s" (u/pprint-to-str params-map))
|
||||
(testing "\nRelay state URL should be base-64 encoded"
|
||||
(is (= redirect-url
|
||||
(u/decode-base64 (:RelayState params-map)))))
|
||||
(util-be/decode-base64 (:RelayState params-map)))))
|
||||
(testing "\nPOST request should redirect to the original redirect URL"
|
||||
(do-with-some-validators-disabled!
|
||||
(fn []
|
||||
(let [req-options (saml-post-request-options (saml-test-response)
|
||||
(u/decode-base64 (:RelayState params-map)))
|
||||
(util-be/decode-base64 (:RelayState params-map)))
|
||||
response (client/client-real-response :post 302 "/auth/sso" req-options)]
|
||||
(is (successful-login? response))
|
||||
(is (= redirect-url
|
||||
@@ -737,7 +738,7 @@
|
||||
(do-with-some-validators-disabled!
|
||||
(fn []
|
||||
(let [req-options (saml-post-request-options (saml-test-response)
|
||||
(u/decode-base64 (:RelayState params-map)))
|
||||
(util-be/decode-base64 (:RelayState params-map)))
|
||||
response (client/client-real-response :post 302 "/auth/sso" req-options)]
|
||||
(is (successful-login? response))
|
||||
(is (= (str "http://localhost:3001/path" redirect-url)
|
||||
@@ -837,7 +838,7 @@
|
||||
origin (-> (get-in result [:body :url])
|
||||
uri->params-map
|
||||
:RelayState
|
||||
u/decode-base64
|
||||
util-be/decode-base64
|
||||
uri->params-map
|
||||
:origin)]
|
||||
(is (= "https://app.example.com" origin)))))))
|
||||
@@ -854,7 +855,7 @@
|
||||
token (-> (get-in result [:body :url])
|
||||
uri->params-map
|
||||
:RelayState
|
||||
u/decode-base64
|
||||
util-be/decode-base64
|
||||
uri->params-map
|
||||
:token)]
|
||||
(is (not (nil? token)))))))))
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
[metabase.session.api :as api.session]
|
||||
[metabase.session.core :as session]
|
||||
[metabase.test :as mt]
|
||||
[metabase.util :as u]
|
||||
[metabase.util-be.core :as util-be]
|
||||
[toucan2.core :as t2]))
|
||||
|
||||
(use-fixtures :each (fn [f] (mt/with-premium-features #{:support-access-grants}
|
||||
@@ -314,7 +314,7 @@
|
||||
(testing "POST /api/session/forgot_password - Support user with no active grant gets no email"
|
||||
(with-redefs [api.session/forgot-password-impl
|
||||
(let [orig @#'api.session/forgot-password-impl]
|
||||
(fn [& args] (u/deref-with-timeout (apply orig args) 1000)))]
|
||||
(fn [& args] (util-be/deref-with-timeout (apply orig args) 1000)))]
|
||||
(mt/with-temp [:model/User user {:first_name "support"
|
||||
:last_name "user"
|
||||
:email "support@example.com"}
|
||||
@@ -332,7 +332,7 @@
|
||||
(testing "POST /api/session/forgot_password - Support user with active grant gets a refreshed token"
|
||||
(with-redefs [api.session/forgot-password-impl
|
||||
(let [orig @#'api.session/forgot-password-impl]
|
||||
(fn [& args] (u/deref-with-timeout (apply orig args) 1000)))]
|
||||
(fn [& args] (util-be/deref-with-timeout (apply orig args) 1000)))]
|
||||
(mt/with-temp [:model/User {creator-id :id} {}]
|
||||
(mt/with-model-cleanup [:model/SupportAccessGrantLog :model/AuthIdentity :model/User]
|
||||
(with-redefs [sag.settings/support-access-grant-email (constantly "support-forgot@example.com")
|
||||
@@ -370,7 +370,7 @@
|
||||
(testing "Consuming a refreshed support-access token via reset_password keeps the support-access-grant provider"
|
||||
(with-redefs [api.session/forgot-password-impl
|
||||
(let [orig @#'api.session/forgot-password-impl]
|
||||
(fn [& args] (u/deref-with-timeout (apply orig args) 1000)))]
|
||||
(fn [& args] (util-be/deref-with-timeout (apply orig args) 1000)))]
|
||||
(mt/with-temp [:model/User {creator-id :id} {}]
|
||||
(mt/with-model-cleanup [:model/SupportAccessGrantLog :model/AuthIdentity :model/User]
|
||||
(with-redefs [sag.settings/support-access-grant-email (constantly "support-reset@example.com")
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
[metabase-enterprise.transforms-python.s3 :as s3]
|
||||
[metabase.transforms-base.util :as transforms-base.u]
|
||||
[metabase.transforms.instrumentation :as transforms.instrumentation]
|
||||
[metabase.util :as u])
|
||||
[metabase.util-be.core :as util-be])
|
||||
(:import
|
||||
(java.io ByteArrayInputStream File)
|
||||
(java.nio.file Files)
|
||||
@@ -18,7 +18,7 @@
|
||||
(defn- jsonl-temp-file
|
||||
^File [^String contents]
|
||||
(let [path (Files/createTempFile "transforms-python-base-test-" ".jsonl"
|
||||
(u/varargs FileAttribute))
|
||||
(util-be/varargs FileAttribute))
|
||||
f (.toFile path)]
|
||||
(.deleteOnExit f)
|
||||
(spit f contents)
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
[metabase.transforms.schedule :as transforms.schedule]
|
||||
[metabase.transforms.test-dataset :as transforms-dataset]
|
||||
[metabase.transforms.test-util :as transforms.tu]
|
||||
[metabase.util :as u]
|
||||
[metabase.util-be.core :as util-be]
|
||||
[toucan2.core :as t2]))
|
||||
|
||||
(deftest python-transform-scheduled-job-test
|
||||
@@ -40,14 +40,14 @@
|
||||
:model/TransformJobTransformTag _ {:job_id job-id :tag_id tag-id :position 0}]
|
||||
(transforms.schedule/initialize-job! job)
|
||||
(transforms.schedule/update-job! job-id "* * * * * ? *")
|
||||
(is (true? (u/poll {:thunk (fn [] (driver/table-exists? driver/*driver* (mt/db) target))
|
||||
:done? true?
|
||||
:timeout-ms 20000
|
||||
:interval-ms 1000})))
|
||||
(is (true? (u/poll {:thunk (fn [] (t2/exists? :model/Table :name (:name target)))
|
||||
:done? true?
|
||||
:timeout-ms 10000
|
||||
:interval-ms 1000})))))))))))
|
||||
(is (true? (util-be/poll {:thunk (fn [] (driver/table-exists? driver/*driver* (mt/db) target))
|
||||
:done? true?
|
||||
:timeout-ms 20000
|
||||
:interval-ms 1000})))
|
||||
(is (true? (util-be/poll {:thunk (fn [] (t2/exists? :model/Table :name (:name target)))
|
||||
:done? true?
|
||||
:timeout-ms 10000
|
||||
:interval-ms 1000})))))))))))
|
||||
|
||||
(def ^:private python-source {:type "python"})
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
[metabase.test :as mt]
|
||||
[metabase.transforms.test-dataset :as transforms-dataset]
|
||||
[metabase.transforms.test-util :as transforms.tu :refer [with-transform-cleanup! get-test-schema]]
|
||||
[metabase.util :as u]
|
||||
[metabase.util-be.core :as util-be]
|
||||
[toucan2.core :as t2])
|
||||
(:import
|
||||
(clojure.lang IDeref)
|
||||
@@ -405,10 +405,10 @@
|
||||
;; Cancellation currently overwrites the message, so we should wait for some log output if we expect it
|
||||
;; Ideally we would not use the message field for log output, or otherwise avoid having logs being lost on cancellation.
|
||||
_ (when expect-script
|
||||
(u/poll {:thunk #(deref message-observer)
|
||||
:done? #(some #{"script started"} %)
|
||||
:interval-ms 1
|
||||
:timeout-ms 5000}))
|
||||
(util-be/poll {:thunk #(deref message-observer)
|
||||
:done? #(some #{"script started"} %)
|
||||
:interval-ms 1
|
||||
:timeout-ms 5000}))
|
||||
_ (when redefs (await-signal ready-signal))
|
||||
_ (get-last-run transform-id)
|
||||
_ (mt/user-http-request :crowberto :post 204 (format "transform/%d/cancel" transform-id))
|
||||
|
||||
@@ -344,13 +344,8 @@
|
||||
;; 2. Your module is infrastructure/gating, not driver logic
|
||||
;; -- add it to driver-affecting-overrides in mage.modules
|
||||
;;
|
||||
;; History:
|
||||
;; 2026-02-06 Initial count: 37
|
||||
;; 2026-02-10 Bumped to 38 for sql-tools + sql-parsing
|
||||
;; 2026-03-10 Bumped to 40 for lib-metric + metrics (Metrics Explorer #68961)
|
||||
;; Added premium-features to driver-affecting-overrides (#69561)
|
||||
;; 2026-04-07 Bumped to 41 due to agent-lib addition (Metabot MBQL improvements #71524)
|
||||
max-allowed-count 41]
|
||||
;; For the history see the git logs.
|
||||
max-allowed-count 42]
|
||||
(is (<= (count modules-triggering-drivers) max-allowed-count)
|
||||
(format "Too many modules trigger driver tests! Expected <= %d, got %d.
|
||||
Modules triggering driver tests: %s
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
[metabase.driver.sql.util :as sql.u]
|
||||
[metabase.driver.sync :as driver.s]
|
||||
[metabase.util :as u]
|
||||
[metabase.util-be.core :as util-be]
|
||||
[metabase.util.date-2 :as u.date]
|
||||
[metabase.util.i18n :refer [tru]]
|
||||
[metabase.util.log :as log]
|
||||
@@ -147,7 +148,7 @@
|
||||
[{:keys [dataset-filters-type dataset-filters-patterns] :as details} & {:keys [logging-schema-exclusions?]}]
|
||||
(let [client (database-details->client details)
|
||||
project-id (bigquery.common/get-project-id details)
|
||||
datasets (.listDatasets client project-id (u/varargs BigQuery$DatasetListOption))
|
||||
datasets (.listDatasets client project-id (util-be/varargs BigQuery$DatasetListOption))
|
||||
inclusion-patterns (when (= "inclusion" dataset-filters-type) dataset-filters-patterns)
|
||||
exclusion-patterns (when (= "exclusion" dataset-filters-type) dataset-filters-patterns)]
|
||||
(for [^Dataset dataset (.iterateAll datasets)
|
||||
@@ -178,7 +179,7 @@
|
||||
true)))
|
||||
|
||||
(def ^:private empty-table-options
|
||||
(u/varargs BigQuery$TableOption))
|
||||
(util-be/varargs BigQuery$TableOption))
|
||||
|
||||
(defn- get-table*
|
||||
[^BigQuery client project-id dataset-id table-id]
|
||||
@@ -548,7 +549,7 @@
|
||||
(let [field-idxs (mapv :database_position fields)
|
||||
all-parsers (get-field-parsers (.. bq-table getDefinition getSchema))
|
||||
parsers (mapv all-parsers field-idxs)
|
||||
page (.list bq-table (u/varargs BigQuery$TableDataListOption))]
|
||||
page (.list bq-table (util-be/varargs BigQuery$TableDataListOption))]
|
||||
(transduce
|
||||
(comp (take table-rows-sample/max-sample-rows)
|
||||
(map (partial extract-fingerprint field-idxs parsers)))
|
||||
@@ -743,7 +744,7 @@
|
||||
;; Wrap exception to avoid responding with HTTP 500 and reporting "We're experiencing server issues"
|
||||
;; in the UI. (#71558)
|
||||
^Job job (try
|
||||
(.create client (JobInfo/of request) (u/varargs BigQuery$JobOption))
|
||||
(.create client (JobInfo/of request) (util-be/varargs BigQuery$JobOption))
|
||||
(catch Throwable t
|
||||
(handle-bigquery-exception t sql parameters)))
|
||||
job-id (.getJobId job)
|
||||
@@ -753,7 +754,7 @@
|
||||
(try
|
||||
(*page-callback*)
|
||||
(let [result-options (if *page-size* [(BigQuery$QueryResultsOption/pageSize *page-size*)] [])
|
||||
result (.getQueryResults job (u/varargs BigQuery$QueryResultsOption result-options))]
|
||||
result (.getQueryResults job (util-be/varargs BigQuery$QueryResultsOption result-options))]
|
||||
(if result
|
||||
(deliver result-promise [:ready result])
|
||||
(throw (ex-info "Null response from query" {}))))
|
||||
@@ -799,7 +800,7 @@
|
||||
(try
|
||||
(thunk)
|
||||
(catch Throwable e
|
||||
(let [ex-data (u/all-ex-data e)]
|
||||
(let [ex-data (util-be/all-ex-data e)]
|
||||
(if (:retryable? ex-data)
|
||||
(thunk)
|
||||
(throw e)))))))
|
||||
@@ -1100,7 +1101,7 @@
|
||||
(let [client (database-details->client conn-spec) ;; for bigquery, connection spec *is* the details
|
||||
project-id (bigquery.common/get-project-id conn-spec)
|
||||
dataset-id (DatasetId/of project-id schema)]
|
||||
(when-not (.getDataset client dataset-id (u/varargs BigQuery$DatasetOption))
|
||||
(when-not (.getDataset client dataset-id (util-be/varargs BigQuery$DatasetOption))
|
||||
;; Dataset doesn't exist, try to create it
|
||||
(let [sql [[(format "CREATE SCHEMA IF NOT EXISTS `%s`;" schema)]]]
|
||||
(driver/execute-raw-queries! driver conn-spec sql)))))
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
[metabase.driver.bigquery-cloud-sdk :as bigquery]
|
||||
[metabase.driver.bigquery-cloud-sdk.common :as bigquery.common]
|
||||
[metabase.driver.bigquery-cloud-sdk.workspaces :as bigquery.ws]
|
||||
[metabase.util :as u])
|
||||
[metabase.util-be.core :as util-be])
|
||||
(:import
|
||||
(com.google.api.gax.core CredentialsProvider)
|
||||
(com.google.auth.oauth2 ImpersonatedCredentials ServiceAccountCredentials)
|
||||
@@ -100,7 +100,7 @@
|
||||
[^BigQuery client project-id dataset-name]
|
||||
(.create client
|
||||
(.build (DatasetInfo/newBuilder (DatasetId/of project-id dataset-name)))
|
||||
(u/varargs BigQuery$DatasetOption [])))
|
||||
(util-be/varargs BigQuery$DatasetOption [])))
|
||||
|
||||
(defn drop-dataset!
|
||||
"Drop a BQ dataset and its contents. Idempotent: no-op if not present.
|
||||
@@ -109,18 +109,18 @@
|
||||
that side-effect."
|
||||
[^BigQuery client project-id dataset-name]
|
||||
(let [ds-id (DatasetId/of project-id dataset-name)]
|
||||
(when (.getDataset client ds-id (u/varargs BigQuery$DatasetOption []))
|
||||
(when (.getDataset client ds-id (util-be/varargs BigQuery$DatasetOption []))
|
||||
(.delete client ds-id
|
||||
(u/varargs BigQuery$DatasetDeleteOption
|
||||
[(BigQuery$DatasetDeleteOption/deleteContents)])))))
|
||||
(util-be/varargs BigQuery$DatasetDeleteOption
|
||||
[(BigQuery$DatasetDeleteOption/deleteContents)])))))
|
||||
|
||||
(defn list-tables
|
||||
"Return a vector of `{:schema dataset :table table-id}` maps for every table
|
||||
in `dataset-name`. Empty vector when the dataset doesn't exist."
|
||||
[^BigQuery client project-id dataset-name]
|
||||
(let [ds-id (DatasetId/of project-id dataset-name)]
|
||||
(if-let [_ds (.getDataset client ds-id (u/varargs BigQuery$DatasetOption []))]
|
||||
(vec (for [^Table t (.iterateAll (.listTables client ds-id (u/varargs BigQuery$TableListOption [])))]
|
||||
(if-let [_ds (.getDataset client ds-id (util-be/varargs BigQuery$DatasetOption []))]
|
||||
(vec (for [^Table t (.iterateAll (.listTables client ds-id (util-be/varargs BigQuery$TableListOption [])))]
|
||||
{:schema dataset-name :table (.. t getTableId getTable)}))
|
||||
[])))
|
||||
|
||||
@@ -210,7 +210,7 @@
|
||||
[project-id ^BigQuery admin-client out-dataset]
|
||||
(testing "workspace output dataset is dropped"
|
||||
(let [ds-id (DatasetId/of project-id out-dataset)
|
||||
ds (.getDataset admin-client ds-id (u/varargs BigQuery$DatasetOption []))]
|
||||
ds (.getDataset admin-client ds-id (util-be/varargs BigQuery$DatasetOption []))]
|
||||
(is (nil? ds)
|
||||
(format "output dataset %s should be removed after destroy" out-dataset)))))
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
[metabase.test.data.interface :as tx]
|
||||
[metabase.test.data.sql :as sql.tx]
|
||||
[metabase.util :as u]
|
||||
[metabase.util-be.core :as util-be]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.log :as log]
|
||||
[metabase.util.malli.schema :as ms]
|
||||
@@ -664,11 +665,11 @@
|
||||
the middleware. The distinct values must still come back correctly."
|
||||
(mt/test-driver :bigquery-cloud-sdk
|
||||
(mt/dataset native-dataset
|
||||
(let [category-field-id (u/auto-retry 1
|
||||
(try (mt/id :fv_partitioned_table :category)
|
||||
(catch Exception e
|
||||
(sync/sync-database! (mt/db) {:scan :schema})
|
||||
(throw e))))
|
||||
(let [category-field-id (util-be/auto-retry 1
|
||||
(try (mt/id :fv_partitioned_table :category)
|
||||
(catch Exception e
|
||||
(sync/sync-database! (mt/db) {:scan :schema})
|
||||
(throw e))))
|
||||
category-field (t2/select-one :model/Field :id category-field-id)
|
||||
table (t2/select-one :model/Table :id (:table_id category-field))]
|
||||
(testing "Dispatcher identifies this as a non-batch-able table"
|
||||
@@ -688,13 +689,13 @@
|
||||
:bigquery-cloud-sdk
|
||||
(mt/dataset
|
||||
native-dataset
|
||||
(let [category-field-id (u/auto-retry
|
||||
(let [category-field-id (util-be/auto-retry
|
||||
1
|
||||
(try
|
||||
(mt/id :fv_partitioned_table :category)
|
||||
(catch Exception e
|
||||
(sync/sync-database! (mt/db) {:scan :schema})
|
||||
(throw e))))]
|
||||
(try
|
||||
(mt/id :fv_partitioned_table :category)
|
||||
(catch Exception e
|
||||
(sync/sync-database! (mt/db) {:scan :schema})
|
||||
(throw e))))]
|
||||
(t2/update! :model/Field category-field-id {:has_field_values :search})
|
||||
(t2/delete! :model/FieldValues :field_id category-field-id)
|
||||
(= [["coffee"]]
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
[metabase.test.data.sql :as sql.tx]
|
||||
[metabase.transforms.test-util :as transforms.test-util]
|
||||
[metabase.util :as u]
|
||||
[metabase.util-be.core :as util-be]
|
||||
[metabase.util.date-2 :as u.date]
|
||||
[metabase.util.log :as log]
|
||||
[metabase.util.malli :as mu]
|
||||
@@ -116,7 +117,7 @@
|
||||
(str/replace table-or-field-name #"-" "_"))
|
||||
|
||||
(mu/defn- create-dataset! [^String dataset-id :- ::dataset-id]
|
||||
(.create (bigquery) (DatasetInfo/of (DatasetId/of (project-id) dataset-id)) (u/varargs BigQuery$DatasetOption))
|
||||
(.create (bigquery) (DatasetInfo/of (DatasetId/of (project-id) dataset-id)) (util-be/varargs BigQuery$DatasetOption))
|
||||
(log/info (u/format-color 'blue "Created BigQuery dataset `%s.%s`." (project-id) dataset-id)))
|
||||
|
||||
(defn execute!
|
||||
@@ -147,9 +148,9 @@
|
||||
(println "Deleting dataset: " dataset-id)
|
||||
(when (= dataset-id (test-dataset-id (tx/get-dataset-definition (data.impl/resolve-dataset-definition *ns* 'test-data))))
|
||||
(.printStackTrace (Exception. "This should not happen")))
|
||||
(.delete (bigquery) dataset-id (u/varargs
|
||||
BigQuery$DatasetDeleteOption
|
||||
[(BigQuery$DatasetDeleteOption/deleteContents)]))
|
||||
(.delete (bigquery) dataset-id (util-be/varargs
|
||||
BigQuery$DatasetDeleteOption
|
||||
[(BigQuery$DatasetDeleteOption/deleteContents)]))
|
||||
(execute-params!
|
||||
(format "DELETE FROM `%s.metabase_test_tracking.datasets` WHERE `name` = ?"
|
||||
(project-id))
|
||||
@@ -201,11 +202,11 @@
|
||||
(defn- create-table*!
|
||||
[dataset-id table-id field-definitions]
|
||||
(let [tbl-id (TableId/of dataset-id table-id)
|
||||
schema (Schema/of (u/varargs Field (field-definitions->Fields (cons {:field-name "id"
|
||||
:base-type :type/Integer}
|
||||
field-definitions))))
|
||||
schema (Schema/of (util-be/varargs Field (field-definitions->Fields (cons {:field-name "id"
|
||||
:base-type :type/Integer}
|
||||
field-definitions))))
|
||||
tbl (TableInfo/of tbl-id (StandardTableDefinition/of schema))]
|
||||
(.create (bigquery) tbl (u/varargs BigQuery$TableOption))))
|
||||
(.create (bigquery) tbl (util-be/varargs BigQuery$TableOption))))
|
||||
|
||||
(mu/defn- create-table!
|
||||
[^String dataset-id :- ::lib.schema.common/non-blank-string
|
||||
@@ -213,7 +214,7 @@
|
||||
field-definitions]
|
||||
(create-table*! dataset-id table-id field-definitions)
|
||||
;; now verify that the Table was created
|
||||
(.listTables (bigquery) dataset-id (u/varargs BigQuery$TableListOption))
|
||||
(.listTables (bigquery) dataset-id (util-be/varargs BigQuery$TableListOption))
|
||||
(log/info (u/format-color 'blue "Created BigQuery table `%s.%s.%s`." (project-id) dataset-id table-id)))
|
||||
|
||||
(defn- table-row-count ^Integer [^String dataset-id, ^String table-id]
|
||||
@@ -266,7 +267,7 @@
|
||||
(defn- rows->request ^InsertAllRequest [^String dataset-id ^String table-id row-maps]
|
||||
(let [insert-rows (map (fn [r]
|
||||
(InsertAllRequest$RowToInsert/of (str (get r :id)) (->json r))) row-maps)]
|
||||
(InsertAllRequest/of (TableId/of dataset-id table-id) (u/varargs InsertAllRequest$RowToInsert insert-rows))))
|
||||
(InsertAllRequest/of (TableId/of dataset-id table-id) (util-be/varargs InsertAllRequest$RowToInsert insert-rows))))
|
||||
|
||||
(def ^:private max-rows-per-request
|
||||
"Max number of rows BigQuery lets us insert at once."
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
[metabase.test.data.sql :as sql.tx]
|
||||
[metabase.test.data.sql.ddl :as ddl]
|
||||
[metabase.util :as u]
|
||||
[metabase.util-be.core :as util-be]
|
||||
[metabase.util.date-2 :as u.date]
|
||||
[metabase.util.honey-sql-2 :as h2x]
|
||||
[metabase.util.log :as log]
|
||||
@@ -108,7 +109,7 @@
|
||||
(try (sql-jdbc.conn/connection-details->spec :oracle {:host "localhost"
|
||||
:port 1521})
|
||||
(catch Throwable e
|
||||
(driver/humanize-connection-error-message :oracle (u/all-ex-messages e))))))))
|
||||
(driver/humanize-connection-error-message :oracle (util-be/all-ex-messages e))))))))
|
||||
|
||||
(deftest connection-properties-test
|
||||
(testing "Connection properties should be returned properly (including transformation of secret types)"
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
[metabase.driver.sql.parameters.substitution :as sql.params.substitution]
|
||||
[metabase.driver.sql.query-processor :as sql.qp]
|
||||
[metabase.driver.sql.util :as sql.u]
|
||||
[metabase.util :as u]
|
||||
[metabase.util-be.core :as util-be]
|
||||
[metabase.util.date-2 :as u.date]
|
||||
[metabase.util.honey-sql-2 :as h2x]
|
||||
[metabase.util.i18n :refer [trs]]
|
||||
@@ -161,7 +161,7 @@
|
||||
|
||||
(defmethod sql.qp/->honeysql [:presto-jdbc (Class/forName "[B")]
|
||||
[_driver bs]
|
||||
[:from_base64 (u/encode-base64-bytes bs)])
|
||||
[:from_base64 (util-be/encode-base64-bytes bs)])
|
||||
|
||||
(defmethod sql.qp/->honeysql [:presto-jdbc :time]
|
||||
[_ [_ t]]
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
[metabase.driver.sync :as driver.s]
|
||||
[metabase.driver.util :as driver.u]
|
||||
[metabase.util :as u]
|
||||
[metabase.util-be.core :as util-be]
|
||||
[metabase.util.date-2 :as u.date]
|
||||
[metabase.util.honey-sql-2 :as h2x]
|
||||
[metabase.util.json :as json]
|
||||
@@ -170,15 +171,15 @@
|
||||
;; Redshift sync is super duper flaky and un-robust! This auto-retry is a temporary workaround until we can actually
|
||||
;; fix #45874
|
||||
(try
|
||||
(u/auto-retry (if driver-api/is-prod? 2 5)
|
||||
(try
|
||||
{:tables (into #{} (describe-database-tables database))}
|
||||
(catch Throwable e
|
||||
;; during test/REPL runs, wait a second before throwing the exception, that way when we do our retry there is
|
||||
;; a better chance of it succeeding.
|
||||
(when-not driver-api/is-prod?
|
||||
(Thread/sleep 1000))
|
||||
(throw e))))
|
||||
(util-be/auto-retry (if driver-api/is-prod? 2 5)
|
||||
(try
|
||||
{:tables (into #{} (describe-database-tables database))}
|
||||
(catch Throwable e
|
||||
;; during test/REPL runs, wait a second before throwing the exception, that way when we do our retry there is
|
||||
;; a better chance of it succeeding.
|
||||
(when-not driver-api/is-prod?
|
||||
(Thread/sleep 1000))
|
||||
(throw e))))
|
||||
(catch Throwable e
|
||||
(throw (ex-info (format "Error in %s describe-database: %s" driver (ex-message e))
|
||||
{}
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
[metabase.test.data.sql :as sql.tx]
|
||||
[metabase.test.fixtures :as fixtures]
|
||||
[metabase.util :as u]
|
||||
[metabase.util-be.core :as util-be]
|
||||
[metabase.util.honey-sql-2 :as h2x]
|
||||
[metabase.util.log :as log]
|
||||
[toucan2.core :as t2])
|
||||
@@ -356,13 +357,13 @@
|
||||
qual-tbl-nm
|
||||
qual-mview-nm)
|
||||
(binding [redshift.tx/*override-describe-database-to-filter-by-db-name?* false]
|
||||
(u/auto-retry 3
|
||||
(let [table-names (set (map :name (:tables (driver/describe-database :redshift database))))]
|
||||
(when-not (contains? table-names mview-nm)
|
||||
(Thread/sleep 1000)
|
||||
(throw (ex-info "Materialized view not yet visible in describe-database results"
|
||||
{:expected mview-nm :actual table-names})))
|
||||
(is (contains? table-names mview-nm)))))))))))
|
||||
(util-be/auto-retry 3
|
||||
(let [table-names (set (map :name (:tables (driver/describe-database :redshift database))))]
|
||||
(when-not (contains? table-names mview-nm)
|
||||
(Thread/sleep 1000)
|
||||
(throw (ex-info "Materialized view not yet visible in describe-database results"
|
||||
{:expected mview-nm :actual table-names})))
|
||||
(is (contains? table-names mview-nm)))))))))))
|
||||
|
||||
(mt/defdataset unix-timestamps
|
||||
[["timestamps"
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
[metabase.test.data.sql :as sql.tx]
|
||||
[metabase.test.data.sql.ddl :as ddl]
|
||||
[metabase.util :as u]
|
||||
[metabase.util-be.core :as util-be]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.log :as log]
|
||||
[metabase.util.log.capture :as log.capture]
|
||||
@@ -65,7 +66,7 @@
|
||||
(qp/process-query query)
|
||||
(is false "no statement created")
|
||||
(catch Exception e
|
||||
(-> e u/all-ex-data ::native-query))))))
|
||||
(-> e util-be/all-ex-data ::native-query))))))
|
||||
|
||||
(use-fixtures :each (fn [thunk]
|
||||
;; 1. If sync fails when loading a test dataset, don't swallow the error; throw an Exception so we
|
||||
@@ -752,11 +753,11 @@
|
||||
:model/Secret {upload-secret-id :id} {:name "Private key upload for Snowflake"
|
||||
:kind :pem-cert
|
||||
:source "uploaded"
|
||||
:value (u/string-to-bytes pk-key)}
|
||||
:value (util-be/string-to-bytes pk-key)}
|
||||
:model/Secret {base64-upload-secret-id :id} {:name "Private key base64 upload for Snowflake"
|
||||
:kind :pem-cert
|
||||
:source "uploaded"
|
||||
:value (mt/bytes->base64-data-uri (u/string-to-bytes pk-key))}]
|
||||
:value (mt/bytes->base64-data-uri (util-be/string-to-bytes pk-key))}]
|
||||
(testing "private key authentication via uploaded keys or local key with path stored in a secret"
|
||||
(spit pk-path pk-key)
|
||||
(is (can-connect? (-> (:details (mt/db))
|
||||
@@ -770,10 +771,10 @@
|
||||
{:private-key-value pk-key
|
||||
:private-key-options "uploaded"}
|
||||
;; uploaded byte array
|
||||
{:private-key-value (mt/bytes->base64-data-uri (u/string-to-bytes pk-key))
|
||||
{:private-key-value (mt/bytes->base64-data-uri (util-be/string-to-bytes pk-key))
|
||||
:private-key-options "uploaded"}
|
||||
;; uploaded byte array without private-key-options
|
||||
{:private-key-value (mt/bytes->base64-data-uri (u/string-to-bytes pk-key))}
|
||||
{:private-key-value (mt/bytes->base64-data-uri (util-be/string-to-bytes pk-key))}
|
||||
;; saved local path
|
||||
{:private-key-id path-secret-id}
|
||||
;; saved uploaded bytes
|
||||
@@ -855,9 +856,9 @@
|
||||
(let [source (case (:private-key-options details-to-succeed "local")
|
||||
"local" :file-path
|
||||
"uploaded" :uploaded)]
|
||||
(is (=? {:value (u/string-to-bytes (if (= :file-path source)
|
||||
(:private-key-path details-to-succeed pk-path)
|
||||
pk-key))
|
||||
(is (=? {:value (util-be/string-to-bytes (if (= :file-path source)
|
||||
(:private-key-path details-to-succeed pk-path)
|
||||
pk-key))
|
||||
:source source}
|
||||
(secret/latest-for-id secret-id))))))))))))))))))
|
||||
|
||||
@@ -881,7 +882,7 @@
|
||||
:advanced-options false
|
||||
:schema-filters-type "all"
|
||||
:account account
|
||||
:private-key-value (mt/bytes->base64-data-uri (u/string-to-bytes private-key-value))
|
||||
:private-key-value (mt/bytes->base64-data-uri (util-be/string-to-bytes private-key-value))
|
||||
:tunnel-enabled false
|
||||
:user user}}]
|
||||
;; TODO: We should make those message returned when role is incorrect more descriptive!
|
||||
@@ -940,7 +941,7 @@
|
||||
:advanced-options false
|
||||
:schema-filters-type "all"
|
||||
:account account
|
||||
:private-key-value (mt/bytes->base64-data-uri (u/string-to-bytes private-key-value))
|
||||
:private-key-value (mt/bytes->base64-data-uri (util-be/string-to-bytes private-key-value))
|
||||
:tunnel-enabled false
|
||||
:user user}}]
|
||||
(testing "Database can be created using _default_ `nil` role"
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
[metabase.query-processor.error-type :as qp.error-type]
|
||||
[metabase.query-processor.middleware.permissions :as qp.perms]
|
||||
[metabase.util :as u]
|
||||
[metabase.util-be.core :as util-be]
|
||||
[metabase.util.i18n :refer [tru]]
|
||||
[metabase.util.log :as log]
|
||||
[metabase.util.malli :as mu]
|
||||
@@ -47,7 +48,7 @@
|
||||
(binding [qp.perms/*card-id* model-id]
|
||||
(qp/execute-write-query! query)))
|
||||
(catch Throwable e
|
||||
(if (= (:type (u/all-ex-data e)) qp.error-type/missing-required-permissions)
|
||||
(if (= (:type (util-be/all-ex-data e)) qp.error-type/missing-required-permissions)
|
||||
(api/throw-403 e)
|
||||
(throw (ex-info (format "Error executing Action: %s" (ex-message e))
|
||||
{:action action
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
[metabase.lib.schema.id :as lib.schema.id]
|
||||
[metabase.parameters.schema :as parameters.schema]
|
||||
[metabase.queries.schema :as queries.schema]
|
||||
[metabase.util.i18n :refer [deferred-tru]]
|
||||
[metabase.util.i18n-be.core :refer [deferred-tru]]
|
||||
[metabase.util.malli :as mu]
|
||||
[metabase.util.malli.registry :as mr]
|
||||
[metabase.util.malli.schema :as ms]))
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
(ns metabase.actions.settings
|
||||
(:require
|
||||
[metabase.settings.core :as setting]
|
||||
[metabase.util.i18n :as i18n]
|
||||
[metabase.util.i18n-be.core :as i18n-be]
|
||||
[metabase.warehouses.models.database :as database]
|
||||
[toucan2.core :as t2]))
|
||||
|
||||
(setting/defsetting database-enable-actions
|
||||
(i18n/deferred-tru "Whether to enable Actions for a specific Database.")
|
||||
(i18n-be/deferred-tru "Whether to enable Actions for a specific Database.")
|
||||
:default false
|
||||
:driver-feature :actions
|
||||
:type :boolean
|
||||
@@ -18,28 +18,28 @@
|
||||
(def ^:private db-routing-reason
|
||||
{:key :setting/database-routing
|
||||
:type :error
|
||||
:message (i18n/deferred-tru "Table editing is not supported with database routing.")})
|
||||
:message (i18n-be/deferred-tru "Table editing is not supported with database routing.")})
|
||||
|
||||
(def ^:private no-writable-tables-reason
|
||||
{:key :permissions/no-writable-table
|
||||
:type :error
|
||||
:message (i18n/deferred-tru "Table editing requires at least one table with INSERT, UPDATE, and DELETE support.")})
|
||||
:message (i18n-be/deferred-tru "Table editing requires at least one table with INSERT, UPDATE, and DELETE support.")})
|
||||
|
||||
(def ^:private busy-sync-reason
|
||||
{:key :database-metadata/sync-in-progress
|
||||
:type :warning
|
||||
:message (i18n/deferred-tru "Unable to determine whether the database connection is readonly, as it is still syncing.")})
|
||||
:message (i18n-be/deferred-tru "Unable to determine whether the database connection is readonly, as it is still syncing.")})
|
||||
|
||||
(def ^:private missing-permissions-reason
|
||||
{:key :database-metadata/not-populated
|
||||
:type :warning
|
||||
:message (i18n/deferred-tru "Unable to determine whether the database connection is readonly, as we are missing metadata from sync.")})
|
||||
:message (i18n-be/deferred-tru "Unable to determine whether the database connection is readonly, as we are missing metadata from sync.")})
|
||||
|
||||
;; Marking reasons as warnings allow the user to proactively set the configuration, but it will only come into
|
||||
;; effect once the warning is resolved.
|
||||
|
||||
(setting/defsetting database-enable-table-editing
|
||||
(i18n/deferred-tru "Whether the Database has table data editing enabled.")
|
||||
(i18n-be/deferred-tru "Whether the Database has table data editing enabled.")
|
||||
:default false
|
||||
:feature :table-data-editing
|
||||
:driver-feature :actions/data-editing
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
[metabase.request.core :as request]
|
||||
[metabase.server.streaming-response :as streaming-response]
|
||||
[metabase.util :as u]
|
||||
[metabase.util-be.core :as util-be]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.log :as log]
|
||||
[metabase.util.malli.registry :as mr]
|
||||
@@ -271,7 +272,7 @@
|
||||
_query-params
|
||||
{:keys [prompt] :as body} :- ::construct-query-request]
|
||||
(let [query (evaluate-external-query-for-execution body)]
|
||||
(cond-> {:query (-> query json/encode u/encode-base64)}
|
||||
(cond-> {:query (-> query json/encode util-be/encode-base64)}
|
||||
prompt (assoc :prompt prompt))))
|
||||
|
||||
;;; ------------------------------------------------- Combined Query -------------------------------------------------
|
||||
@@ -283,7 +284,7 @@
|
||||
(-> {:query query-map
|
||||
:pagination {:limit total-limit :page (inc page)}}
|
||||
json/encode
|
||||
u/encode-base64))
|
||||
util-be/encode-base64))
|
||||
|
||||
(defn- decode-continuation-token
|
||||
"Decode a base64-encoded continuation token into {:query ... :pagination ...}.
|
||||
@@ -292,7 +293,7 @@
|
||||
the embedded query happens in [[check-token-query-permissions!]] — a token
|
||||
doesn't grant access the bearer wouldn't otherwise have."
|
||||
[token]
|
||||
(let [decoded (-> token u/decode-base64 json/decode+kw)
|
||||
(let [decoded (-> token util-be/decode-base64 json/decode+kw)
|
||||
{:keys [limit page]} (:pagination decoded)]
|
||||
(api/check (and (int? limit) (pos? limit))
|
||||
[400 "Invalid continuation token: limit must be a positive integer"])
|
||||
@@ -490,7 +491,7 @@
|
||||
_query-params
|
||||
{encoded-query :query} :- ::execute-query-request]
|
||||
(let [query (-> encoded-query
|
||||
u/decode-base64
|
||||
util-be/decode-base64
|
||||
json/decode+kw)]
|
||||
;; `/v1/execute` is gated by the `agent:query:execute` scope and is intended for MBQL.
|
||||
;; The opaque base64 payload could carry `:type :native`, but `execute_sql` is gated by
|
||||
@@ -636,7 +637,7 @@
|
||||
{:keys [query display description collection_id visualization_settings]
|
||||
question-name :name}
|
||||
:- ::create-question-request]
|
||||
(let [dataset-query (-> query u/decode-base64 json/decode+kw)]
|
||||
(let [dataset-query (-> query util-be/decode-base64 json/decode+kw)]
|
||||
;; Mirror REST `POST /api/card/` pre-checks before calling `queries/create-card!`.
|
||||
;; `create-card!` itself does NOT run permissions checks; without these mirroring the
|
||||
;; REST endpoint, an LLM caller could (a) save a card whose query references data the
|
||||
@@ -733,7 +734,7 @@
|
||||
;; canonical MBQL shape regardless of whether the LLM
|
||||
;; sent legacy or MBQL 5.
|
||||
(-> (:query body)
|
||||
u/decode-base64
|
||||
util-be/decode-base64
|
||||
json/decode+kw
|
||||
lib-be/normalize-query)))
|
||||
;; Set :archived_directly to mirror :archived (mark as Trash if explicitly archived).
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
(:require
|
||||
[metabase.llm.settings :as llm.settings]
|
||||
[metabase.settings.core :as setting :refer [defsetting]]
|
||||
[metabase.util.i18n :refer [deferred-tru]]))
|
||||
[metabase.util.i18n-be.core :refer [deferred-tru]]))
|
||||
|
||||
(defsetting agent-api-enabled?
|
||||
(deferred-tru "Whether the Agent API is enabled.")
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
[metabase.config.core :as config]
|
||||
[metabase.settings.core :as setting :refer [defsetting]]
|
||||
[metabase.util.date-2 :as u.date]
|
||||
[metabase.util.i18n :refer [deferred-tru]]
|
||||
[metabase.util.i18n-be.core :refer [deferred-tru]]
|
||||
[toucan2.core :as t2]))
|
||||
|
||||
(defsetting analytics-uuid
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
[metabase.analyze.fingerprint.fingerprinters :as fingerprinters]
|
||||
[metabase.analyze.fingerprint.insights :as insights]
|
||||
[metabase.query-processor.schema :as query-processor.schema]
|
||||
[metabase.util.i18n :as i18n]
|
||||
[metabase.util.i18n-be.core :as i18n-be]
|
||||
[metabase.util.log :as log]
|
||||
[metabase.util.malli :as mu]
|
||||
[metabase.util.malli.registry :as mr]
|
||||
@@ -21,7 +21,7 @@
|
||||
(mr/def ::ResultsMetadata
|
||||
(mu/with-api-error-message
|
||||
[:maybe [:sequential ResultColumnMetadata]]
|
||||
(i18n/deferred-tru "value must be an array of valid results column metadata maps.")))
|
||||
(i18n-be/deferred-tru "value must be an array of valid results column metadata maps.")))
|
||||
|
||||
(def ResultsMetadata
|
||||
"Schema for valid values of the `result_metadata` column."
|
||||
|
||||
@@ -85,7 +85,8 @@
|
||||
[metabase.events.core :as events]
|
||||
[metabase.models.interface :as mi]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.i18n :as i18n :refer [deferred-tru tru]]
|
||||
[metabase.util.i18n :refer [tru]]
|
||||
[metabase.util.i18n-be.core :as i18n-be :refer [deferred-tru]]
|
||||
[metabase.util.log :as log]
|
||||
[metabase.util.malli :as mu]
|
||||
[metabase.util.malli.schema :as ms]
|
||||
@@ -142,7 +143,7 @@
|
||||
(defn- check-one [condition code message]
|
||||
(when-not condition
|
||||
(let [[message info] (if (and (map? message)
|
||||
(not (i18n/localized-string? message)))
|
||||
(not (i18n-be/localized-string? message)))
|
||||
[(:message message) message]
|
||||
[message])]
|
||||
(throw (ex-info (str message) (assoc info :status-code code)))))
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
[metabase.api.open-api :as open-api]
|
||||
[metabase.api.response :as api.response]
|
||||
[metabase.api.settings :as api.settings]
|
||||
[metabase.util.i18n :refer [deferred-trs deferred-tru]]
|
||||
[metabase.util.i18n-be.core :refer [deferred-trs deferred-tru]]
|
||||
[metabase.util.log :as log]
|
||||
[metabase.util.malli :as mu]))
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
[metabase.permissions.core :as perms]
|
||||
[metabase.users.models.user :as user]
|
||||
[metabase.util :as u]
|
||||
[metabase.util-be.core :as util-be]
|
||||
[metabase.util.i18n :refer [tru]]
|
||||
[metabase.util.malli :as mu]
|
||||
[metabase.util.malli.registry :as mr]
|
||||
@@ -192,14 +193,14 @@
|
||||
(mu/defn key-with-unique-prefix :- ::api-keys.schema/key.secret
|
||||
"Generate an unique API key with a unique prefix."
|
||||
[]
|
||||
(u/auto-retry 5
|
||||
(let [api-key (generate-key)
|
||||
prefix (prefix (u.secret/expose api-key))]
|
||||
;; we could make this more efficient by generating 5 API keys up front and doing one select to remove any
|
||||
;; duplicates. But a duplicate should be rare enough to just do multiple queries for now.
|
||||
(if-not (t2/exists? :model/ApiKey :key_prefix prefix)
|
||||
api-key
|
||||
(throw (ex-info (tru "could not generate key with unique prefix") {}))))))
|
||||
(util-be/auto-retry 5
|
||||
(let [api-key (generate-key)
|
||||
prefix (prefix (u.secret/expose api-key))]
|
||||
;; we could make this more efficient by generating 5 API keys up front and doing one select to remove any
|
||||
;; duplicates. But a duplicate should be rare enough to just do multiple queries for now.
|
||||
(if-not (t2/exists? :model/ApiKey :key_prefix prefix)
|
||||
api-key
|
||||
(throw (ex-info (tru "could not generate key with unique prefix") {}))))))
|
||||
|
||||
(mu/defn create-api-key-with-new-user!
|
||||
"Create a new API key and a new user for that key at the same time."
|
||||
|
||||
@@ -67,7 +67,7 @@
|
||||
[metabase.upload.api]
|
||||
[metabase.user-key-value.api]
|
||||
[metabase.users-rest.api]
|
||||
[metabase.util.i18n :refer [deferred-tru]]
|
||||
[metabase.util.i18n-be.core :refer [deferred-tru]]
|
||||
[metabase.warehouse-schema-rest.api]
|
||||
[metabase.warehouses-rest.api]
|
||||
[metabase.xrays.api]))
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
[metabase.classloader.core :as classloader]
|
||||
[metabase.config.core :as config]
|
||||
[metabase.util :as u]
|
||||
[metabase.util-be.core :as util-be]
|
||||
[metabase.util.i18n :refer [trs]]
|
||||
[metabase.util.log :as log]
|
||||
[metabase.util.malli :as mu]
|
||||
@@ -74,7 +75,7 @@
|
||||
"Check if a table exists."
|
||||
[table-name ^Connection conn]
|
||||
(-> (.getMetaData conn)
|
||||
(.getTables nil nil table-name (u/varargs String ["TABLE"]))
|
||||
(.getTables nil nil table-name (util-be/varargs String ["TABLE"]))
|
||||
jdbc/metadata-query
|
||||
seq
|
||||
boolean))
|
||||
@@ -234,16 +235,16 @@
|
||||
chance the lock will end up clearing up so we can run migrations normally."
|
||||
[^LockService lock-service]
|
||||
(let [retry-counter (volatile! 0)]
|
||||
(u/auto-retry 5
|
||||
(when-not (.acquireLock lock-service)
|
||||
(Thread/sleep 2000)
|
||||
(vswap! retry-counter inc)
|
||||
(throw
|
||||
(LockException.
|
||||
(str
|
||||
(trs "Database has migration lock; cannot run migrations.")
|
||||
" "
|
||||
(trs "You can force-release these locks by running `java --add-opens java.base/java.nio=ALL-UNNAMED -jar metabase.jar migrate release-locks`."))))))
|
||||
(util-be/auto-retry 5
|
||||
(when-not (.acquireLock lock-service)
|
||||
(Thread/sleep 2000)
|
||||
(vswap! retry-counter inc)
|
||||
(throw
|
||||
(LockException.
|
||||
(str
|
||||
(trs "Database has migration lock; cannot run migrations.")
|
||||
" "
|
||||
(trs "You can force-release these locks by running `java --add-opens java.base/java.nio=ALL-UNNAMED -jar metabase.jar migrate release-locks`."))))))
|
||||
(if (pos? @retry-counter)
|
||||
(log/warnf "Migration lock was acquired after %d retries." @retry-counter)
|
||||
(do (log/info "No migration lock found.")
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
[metabase.app-db.liquibase :as liquibase]
|
||||
[metabase.config.core :as config]
|
||||
[metabase.util :as u]
|
||||
[metabase.util-be.core :as util-be]
|
||||
[metabase.util.encryption :as encryption]
|
||||
[metabase.util.honey-sql-2]
|
||||
[metabase.util.i18n :refer [trs]]
|
||||
@@ -258,15 +259,15 @@
|
||||
data-source :- (ms/InstanceOfClass javax.sql.DataSource)
|
||||
auto-migrate? :- :boolean
|
||||
create-sample-content? :- :boolean]
|
||||
(u/profile (trs "Database setup")
|
||||
(u/with-us-locale
|
||||
(binding [mdb.connection/*application-db* (mdb.connection/application-db db-type data-source :create-pool? false) ; should already be a pool
|
||||
config/*disable-setting-cache* true
|
||||
custom-migrations/*create-sample-content* create-sample-content?]
|
||||
(verify-db-connection db-type data-source)
|
||||
(error-if-downgrade-required! data-source)
|
||||
(run-schema-migrations! data-source auto-migrate?)
|
||||
(check-encryption))))
|
||||
(util-be/profile (trs "Database setup")
|
||||
(util-be/with-us-locale
|
||||
(binding [mdb.connection/*application-db* (mdb.connection/application-db db-type data-source :create-pool? false) ; should already be a pool
|
||||
config/*disable-setting-cache* true
|
||||
custom-migrations/*create-sample-content* create-sample-content?]
|
||||
(verify-db-connection db-type data-source)
|
||||
(error-if-downgrade-required! data-source)
|
||||
(run-schema-migrations! data-source auto-migrate?)
|
||||
(check-encryption))))
|
||||
:done)
|
||||
|
||||
(defn release-migration-locks!
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
[metabase.settings.core :as setting :refer [defsetting]]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.fonts :as u.fonts]
|
||||
[metabase.util.i18n :refer [deferred-tru tru]]
|
||||
[metabase.util.i18n :refer [tru]]
|
||||
[metabase.util.i18n-be.core :refer [deferred-tru]]
|
||||
[toucan2.core :as t2]))
|
||||
|
||||
(set! *warn-on-reflection* true)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
(ns metabase.audit-app.settings
|
||||
(:require
|
||||
[metabase.settings.core :as setting :refer [defsetting]]
|
||||
[metabase.util.i18n :refer [deferred-tru]]
|
||||
[metabase.util.i18n-be.core :refer [deferred-tru]]
|
||||
[metabase.util.log :as log]))
|
||||
|
||||
(defsetting last-analytics-checksum
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
[metabase.notification.core :as notification]
|
||||
[metabase.premium-features.core :refer [defenterprise]]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.i18n :refer [deferred-tru]]
|
||||
[metabase.util.i18n-be.core :refer [deferred-tru]]
|
||||
[metabase.util.malli :as mu]
|
||||
[metabase.util.malli.schema :as ms]
|
||||
[methodical.core :as methodical]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
(ns metabase.batch-processing.settings
|
||||
(:require
|
||||
[metabase.settings.core :refer [defsetting]]
|
||||
[metabase.util.i18n :refer [deferred-tru]]))
|
||||
[metabase.util.i18n-be.core :refer [deferred-tru]]))
|
||||
|
||||
(defsetting synchronous-batch-updates
|
||||
(deferred-tru "Process batches updates synchronously. If true, all `submit!` calls will be processed immediately. Default is false.")
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
(ns metabase.bug-reporting.settings
|
||||
(:require
|
||||
[metabase.settings.core :refer [defsetting]]
|
||||
[metabase.util.i18n :refer [deferred-tru]]))
|
||||
[metabase.util.i18n-be.core :refer [deferred-tru]]))
|
||||
|
||||
(defsetting bug-reporting-enabled
|
||||
(deferred-tru "Enable bug report submissions.")
|
||||
|
||||
3
src/metabase/cache/settings.clj
vendored
3
src/metabase/cache/settings.clj
vendored
@@ -2,7 +2,8 @@
|
||||
(:require
|
||||
[metabase.settings.core :as setting :refer [defsetting]]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.i18n :refer [deferred-tru tru]]
|
||||
[metabase.util.i18n :refer [tru]]
|
||||
[metabase.util.i18n-be.core :refer [deferred-tru]]
|
||||
[toucan2.core :as t2]))
|
||||
|
||||
(defsetting enable-query-caching
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
[metabase.models.interface :as mi]
|
||||
[metabase.permissions.core :as perms]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.i18n :refer [deferred-tru]]
|
||||
[metabase.util.i18n-be.core :refer [deferred-tru]]
|
||||
[metabase.util.malli :as mu]
|
||||
[metabase.util.malli.schema :as ms]
|
||||
[toucan2.core :as t2]))
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
[metabase.premium-features.core :as premium-features]
|
||||
[metabase.settings.core :as setting]
|
||||
[metabase.util :as u]
|
||||
[metabase.util-be.core :as util-be]
|
||||
[metabase.util.i18n :refer [tru]]
|
||||
[metabase.util.log :as log]
|
||||
[metabase.util.malli :as mu]
|
||||
@@ -307,7 +308,7 @@
|
||||
(smtp->mb-setting :port mb-to-smtp-map) "Wrong host or port"}}
|
||||
creds-error {:errors {(smtp->mb-setting :user mb-to-smtp-map) "Wrong username or password"
|
||||
(smtp->mb-setting :pass mb-to-smtp-map) "Wrong username or password"}}
|
||||
exceptions (u/full-exception-chain error)
|
||||
exceptions (util-be/full-exception-chain error)
|
||||
message (str/join ": " (map ex-message exceptions))
|
||||
match-error (fn match-error [regex-or-exception-class [message exceptions]]
|
||||
(cond (instance? java.util.regex.Pattern regex-or-exception-class)
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
[metabase.util.date-2 :as u.date]
|
||||
[metabase.util.encryption :as encryption]
|
||||
[metabase.util.i18n :as i18n :refer [trs tru]]
|
||||
[metabase.util.i18n-be.core :as i18n-be]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.log :as log]
|
||||
[metabase.util.malli :as mu]
|
||||
@@ -175,7 +176,7 @@
|
||||
(let [user-info (or (t2/select-one [:model/User :last_name :first_name :email :locale] :id user-id)
|
||||
(throw (ex-info (tru "User {0} does not exist" user-id)
|
||||
{:user-id user-id, :status-code 404})))
|
||||
user-locale (or (:locale user-info) (i18n/site-locale))
|
||||
user-locale (or (:locale user-info) (i18n-be/site-locale))
|
||||
timestamp (u.date/format-human-readable timestamp user-locale)
|
||||
username (or (:first_name user-info) (:last_name user-info) (:email user-info))
|
||||
context (merge (common-context)
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
[metabase.channel.settings :as channel.settings]
|
||||
[metabase.channel.shared :as channel.shared]
|
||||
[metabase.channel.urls :as urls]
|
||||
[metabase.util :as u]
|
||||
[metabase.util-be.core :as util-be]
|
||||
[metabase.util.i18n :refer [tru]]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.malli :as mu]
|
||||
@@ -39,7 +39,7 @@
|
||||
(mu/defmethod channel/send! :channel/http
|
||||
[{{:keys [url method auth-method auth-info]} :details} :- HTTPChannel
|
||||
request]
|
||||
(when-not (u/valid-host? (channel.settings/http-channel-host-strategy) url)
|
||||
(when-not (util-be/valid-host? (channel.settings/http-channel-host-strategy) url)
|
||||
(throw (ex-info (tru "URLs referring to hosts that supply internal hosting metadata are prohibited.")
|
||||
{:status-code 400})))
|
||||
(let [req (merge
|
||||
|
||||
@@ -19,7 +19,8 @@
|
||||
[metabase.timeline.core :as timeline]
|
||||
[metabase.types.core :as types]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.i18n :refer [deferred-trs trs tru]]
|
||||
[metabase.util.i18n :refer [trs tru]]
|
||||
[metabase.util.i18n-be.core :refer [deferred-trs]]
|
||||
[metabase.util.malli :as mu]
|
||||
[metabase.util.malli.registry :as mr]
|
||||
[metabase.util.malli.schema :as ms])
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
[clojure.string :as str]
|
||||
[java-time.api :as t]
|
||||
[metabase.settings.core :as setting :refer [defsetting]]
|
||||
[metabase.util.i18n :refer [deferred-tru tru]]
|
||||
[metabase.util.i18n :refer [tru]]
|
||||
[metabase.util.i18n-be.core :refer [deferred-tru]]
|
||||
[metabase.util.malli.registry :as mr]
|
||||
[metabase.util.malli.schema :as ms]
|
||||
[metabase.util.string :as u.str]))
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
[metabase.channel.settings :as channel.settings]
|
||||
[metabase.events.core :as events]
|
||||
[metabase.util :as u]
|
||||
[metabase.util-be.core :as util-be]
|
||||
[metabase.util.date-2 :as u.date]
|
||||
[metabase.util.i18n :refer [tru]]
|
||||
[metabase.util.json :as json]
|
||||
@@ -273,12 +274,12 @@
|
||||
(throw (ex-info (ex-message e) (assoc (ex-data e) :filename filename)))))
|
||||
uploaded? (fn [complete-response] (seq (get-in complete-response [:files 0 :filetype])))
|
||||
_ (when-not (or (uploaded? complete-response)
|
||||
(u/poll {:thunk complete!
|
||||
:done? uploaded?
|
||||
;; Cal 2024-04-30: this typically takes 1-2 seconds to succeed.
|
||||
;; If it takes more than 20 seconds, something else is wrong and we should abort.
|
||||
:timeout-ms 20000
|
||||
:interval-ms 500}))
|
||||
(util-be/poll {:thunk complete!
|
||||
:done? uploaded?
|
||||
;; Cal 2024-04-30: this typically takes 1-2 seconds to succeed.
|
||||
;; If it takes more than 20 seconds, something else is wrong and we should abort.
|
||||
:timeout-ms 20000
|
||||
:interval-ms 500}))
|
||||
(throw (ex-info "Timed out waiting to confirm the file was uploaded to Slack."
|
||||
{:filename filename})))]
|
||||
(get-in complete-response [:files 0 :url_private])))
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
[metabase.task.bootstrap :as task.bootstrap]
|
||||
[metabase.task.core :as task]
|
||||
[metabase.util :as u]
|
||||
[metabase.util-be.core :as util-be]
|
||||
[metabase.util.i18n :refer [tru]]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.log :as log]
|
||||
@@ -145,12 +146,12 @@
|
||||
(defn- put-file
|
||||
"Put file, whole or from start to end, on url, reporting on-progress. Retries up to 3 times."
|
||||
[url ^File file on-progress & {:keys [headers start end]}]
|
||||
(u/auto-retry 3
|
||||
(with-open [file-stream (progress-file-input-stream file on-progress)]
|
||||
(let [[stream length] (if (and start end)
|
||||
[(sub-stream file-stream start end) (- end start)]
|
||||
[file-stream (.length file)])]
|
||||
(http/put url {:headers headers :length length :body stream})))))
|
||||
(util-be/auto-retry 3
|
||||
(with-open [file-stream (progress-file-input-stream file on-progress)]
|
||||
(let [[stream length] (if (and start end)
|
||||
[(sub-stream file-stream start end) (- end start)]
|
||||
[file-stream (.length file)])]
|
||||
(http/put url {:headers headers :length length :body stream})))))
|
||||
|
||||
;; ~100mb
|
||||
(def ^:private part-size 100e6)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
[clojure.string :as str]
|
||||
[metabase.config.core :as config]
|
||||
[metabase.settings.core :refer [defsetting]]
|
||||
[metabase.util.i18n :refer [deferred-tru]]))
|
||||
[metabase.util.i18n-be.core :refer [deferred-tru]]))
|
||||
|
||||
(defsetting store-use-staging
|
||||
(deferred-tru "If staging store should be used instead of prod. True on dev.")
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
[metabase.app-db.core :as mdb]
|
||||
[metabase.auth-identity.core :as auth-identity]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.i18n :refer [deferred-trs trs]]
|
||||
[metabase.util.i18n :refer [trs]]
|
||||
[metabase.util.i18n-be.core :refer [deferred-trs]]
|
||||
[toucan2.core :as t2]))
|
||||
|
||||
(set! *warn-on-reflection* true)
|
||||
|
||||
@@ -22,7 +22,8 @@
|
||||
[metabase.search.spec :as search.spec]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.honey-sql-2 :as h2x]
|
||||
[metabase.util.i18n :refer [trs tru deferred-tru]]
|
||||
[metabase.util.i18n :refer [trs tru]]
|
||||
[metabase.util.i18n-be.core :refer [deferred-tru]]
|
||||
[metabase.util.log :as log]
|
||||
[metabase.util.malli :as mu]
|
||||
[metabase.util.malli.schema :as ms]
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
(ns metabase.collections-rest.settings
|
||||
(:require
|
||||
[metabase.settings.core :refer [defsetting]]
|
||||
[metabase.util.i18n :as i18n]))
|
||||
[metabase.util.i18n-be.core :as i18n-be]))
|
||||
|
||||
(defsetting can-run-adhoc-query-check-threshold
|
||||
(i18n/deferred-tru (str "Maximum number of cards to compute can_run_adhoc_query for. When the number of cards exceeds "
|
||||
"this threshold, can_run_adhoc_query will return true for all cards without computing actual "
|
||||
"permissions. Set to 0 to always compute permissions. This only affects how cards are displayed"
|
||||
" in the query builder and does not affect actual permission enforcement."))
|
||||
(i18n-be/deferred-tru (str "Maximum number of cards to compute can_run_adhoc_query for. When the number of cards exceeds "
|
||||
"this threshold, can_run_adhoc_query will return true for all cards without computing actual "
|
||||
"permissions. Set to 0 to always compute permissions. This only affects how cards are displayed"
|
||||
" in the query builder and does not affect actual permission enforcement."))
|
||||
:type :integer
|
||||
:export? false
|
||||
:default 250
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
[metabase.users.core :as users]
|
||||
[metabase.users.models.user :as user]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.i18n :refer [deferred-tru]]
|
||||
[metabase.util.i18n-be.core :refer [deferred-tru]]
|
||||
[metabase.util.malli :as mu]
|
||||
[metabase.util.malli.schema :as ms]
|
||||
[toucan2.core :as t2]))
|
||||
|
||||
@@ -26,7 +26,8 @@
|
||||
[metabase.util :as u]
|
||||
[metabase.util.embed :refer [maybe-populate-initially-published-at]]
|
||||
[metabase.util.honey-sql-2 :as h2x]
|
||||
[metabase.util.i18n :as i18n :refer [tru]]
|
||||
[metabase.util.i18n :refer [tru]]
|
||||
[metabase.util.i18n-be.core :as i18n-be]
|
||||
[metabase.util.log :as log]
|
||||
[metabase.util.malli :as mu]
|
||||
[metabase.util.malli.schema :as ms]
|
||||
@@ -336,7 +337,7 @@
|
||||
(t2/with-transaction [_conn]
|
||||
(let [{dashcards :dashcards
|
||||
tabs :tabs
|
||||
:keys [description] :as dashboard} (i18n/localized-strings->strings dashboard)
|
||||
:keys [description] :as dashboard} (i18n-be/localized-strings->strings dashboard)
|
||||
dashboard (first (t2/insert-returning-instances!
|
||||
:model/Dashboard
|
||||
(-> dashboard
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
(ns metabase.dashboards.settings
|
||||
(:require
|
||||
[metabase.settings.core :refer [defsetting]]
|
||||
[metabase.util.i18n :refer [deferred-tru]]))
|
||||
[metabase.util.i18n-be.core :refer [deferred-tru]]))
|
||||
|
||||
(defsetting dashboards-save-last-used-parameters
|
||||
(deferred-tru "Whether dashboards should default to a user''s last used parameters on load.")
|
||||
|
||||
@@ -46,7 +46,8 @@
|
||||
[metabase.revisions.core :as revisions]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.honey-sql-2 :as h2x]
|
||||
[metabase.util.i18n :refer [deferred-tru tru]]
|
||||
[metabase.util.i18n :refer [tru]]
|
||||
[metabase.util.i18n-be.core :refer [deferred-tru]]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.log :as log]
|
||||
[metabase.util.malli :as mu]
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
[metabase.public-sharing.core :as public-sharing]
|
||||
[metabase.search.spec :as search.spec]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.i18n :refer [deferred-tru]]
|
||||
[metabase.util.i18n-be.core :refer [deferred-tru]]
|
||||
[metabase.util.log :as log]
|
||||
[metabase.util.malli :as mu]
|
||||
[methodical.core :as methodical]
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
[metabase.driver.connection :as driver.conn]
|
||||
[metabase.premium-features.core :as premium-features]
|
||||
[metabase.settings.core :as setting]
|
||||
[metabase.util.i18n :refer [deferred-tru]]
|
||||
[metabase.util.i18n-be.core :refer [deferred-tru]]
|
||||
[metabase.util.log :as log]
|
||||
[metabase.util.malli :as mu]
|
||||
[metabase.warehouses.core :as warehouses]))
|
||||
|
||||
@@ -27,7 +27,8 @@
|
||||
[metabase.lib.schema.metadata :as lib.schema.metadata]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.honey-sql-2 :as h2x]
|
||||
[metabase.util.i18n :refer [deferred-tru tru]]
|
||||
[metabase.util.i18n :refer [tru]]
|
||||
[metabase.util.i18n-be.core :refer [deferred-tru]]
|
||||
[metabase.util.log :as log]
|
||||
[metabase.util.malli :as mu]
|
||||
[metabase.util.performance :as perf :refer [every? some]])
|
||||
|
||||
@@ -7,7 +7,9 @@
|
||||
[metabase.driver.sql-jdbc.actions :as sql-jdbc.actions]
|
||||
[metabase.driver.sql-jdbc.connection :as sql-jdbc.conn]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.i18n :refer [deferred-trun tru]]
|
||||
[metabase.util-be.core :as util-be]
|
||||
[metabase.util.i18n :refer [tru]]
|
||||
[metabase.util.i18n-be.core :refer [deferred-trun]]
|
||||
[metabase.util.log :as log]))
|
||||
|
||||
(defmethod sql-jdbc.actions/base-type->sql-type-map :h2
|
||||
@@ -77,7 +79,7 @@
|
||||
(re-find #"Unique index or primary key violation: \"[^.]+.(.+?) ON [^.]+.\"\"(.+?)\"\"" error-message)]
|
||||
(let [columns (constraint->column-names database table constraint-name)]
|
||||
{:type error-type
|
||||
:message (tru "{0} already {1}." (u/build-sentence (map str/capitalize columns) :stop? false) (deferred-trun "exists" "exist" (count columns)))
|
||||
:message (tru "{0} already {1}." (util-be/build-sentence (map str/capitalize columns) :stop? false) (deferred-trun "exists" "exist" (count columns)))
|
||||
:errors (reduce (fn [acc col]
|
||||
(assoc acc col (tru "This {0} value already exists." (str/capitalize col))))
|
||||
{}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user