### Example: Custom Setup with do-with-perm* :before Method Source: https://metabase-dev-docs.github.io/metabase/toc.html/dev.with-perm This example demonstrates how to implement a `:before` method for `do-with-perm*` to execute custom setup logic, such as `(set-up-db!)`, before the main function `f` is invoked. It shows how to access `_model` and `_explicit-attributes` (which can be `nil`) for conditional setup. ```Clojure (m/defmethod do-with-perm* :before :default [_model _explicit-attributes f] (set-up-db!) f) ``` -------------------------------- ### Main Entry Point for Development Server Source: https://metabase-dev-docs.github.io/metabase/toc.html/user Defines the `-main` function, which serves as the primary entry point for starting the Metabase development server. It launches an nREPL server on port 50605, calls the `dev` function to switch to the development namespace, evaluates `(start!)`, and keeps the process alive, typically invoked via CLI aliases like `:dev-start`. ```Clojure (defn -main [& _args] (future (nrepl.cmdline/-main "-p" "50605")) (dev) #_{:clj-kondo/ignore [:discouraged-var]} (eval "(start!)") (deref (promise))) ``` -------------------------------- ### Generate Metabase 'Get Connected' Onboarding Tasks in Clojure Source: https://metabase-dev-docs.github.io/metabase/toc.html/metabase.setup.api This Clojure function `get-connected-tasks` takes the application state (generated by `state-for-checklist`) and returns a list of 'Get connected' onboarding tasks. Each task includes a title, group, description, link, completion status (based on the provided state), and a trigger condition. Tasks cover adding a database, setting up email, setting Slack credentials, setting up embedding, and inviting team members. ```Clojure (defn- get-connected-tasks [{:keys [configured counts exists embedding] :as _info}] [{:title (tru "Add a database") :group (tru "Get connected") :description (tru "Connect to your data so your whole team can start to explore.") :link "/admin/databases/create" :completed (exists :non-sample-db) :triggered :always} {:title (tru "Set up email") :group (tru "Get connected") :description (tru "Add email credentials so you can more easily invite team members and get updates via Pulses.") :link "/admin/settings/email" :completed (configured :email) :triggered :always} {:title (tru "Set Slack credentials") :group (tru "Get connected") :description (tru "Does your team use Slack? If so, you can send automated updates via dashboard subscriptions.") :link "/admin/settings/notifications/slack" :completed (configured :slack) :triggered :always} {:title (tru "Setup embedding") :group (tru "Get connected") :description (tru "Get customizable, flexible, and scalable customer-facing analytics in no time") :link "/admin/settings/embedding-in-other-applications" :completed (or (embedding :done?) (and (configured :sso) (embedding :app-origin)) (exists :embedded-resource)) :triggered (embedding :interested?)} {:title (tru "Invite team members") :group (tru "Get connected") :description (tru "Share answers and data with the rest of your team.") :link "/admin/people/" :completed (> (counts :user) 1) :triggered (or (exists :dashboard) (exists :pulse) (>= (counts :card) 5))}]) ``` -------------------------------- ### Core Metabase Application Initialization (`init!*`) Source: https://metabase-dev-docs.github.io/metabase/toc.html/metabase.core.core This function performs the primary setup for the Metabase application. It handles logging, registers a shutdown hook, loads plugins, validates settings, sets up the database (including migrations and sample content), configures Prometheus metrics, checks for new installations, and starts the scheduler. It tracks progress throughout the initialization process. ```Clojure (defn- init!* [] (log/infof "Starting Metabase version %s ..." config/mb-version-string) (log/infof "System info:\n %s" (u/pprint-to-str (u.system-info/system-info))) (init-status/set-progress! 0.1) ;; First of all, lets register a shutdown hook that will tidy things up for us on app exit (.addShutdownHook (Runtime/getRuntime) (Thread. ^Runnable destroy!)) (init-status/set-progress! 0.2) ;; Ensure the classloader is installed as soon as possible. (classloader/the-classloader) ;; load any plugins as needed (plugins/load-plugins!) (init-status/set-progress! 0.3) (setting/validate-settings-formatting!) ;; startup database. validates connection & runs any necessary migrations (log/info "Setting up and migrating Metabase DB. Please sit tight, this may take a minute...") ;; Cal 2024-04-03: ;; we have to skip creating sample content if we're running tests, because it causes some tests to timeout ;; and the test suite can take 2x longer. this is really unfortunate because it could lead to some false ;; negatives, but for now there's not much we can do (mdb/setup-db! :create-sample-content? (not config/is-test?)) ;; Disable read-only mode if its on during startup. ;; This can happen if a cloud migration process dies during h2 dump. (when (cloud-migration/read-only-mode) (cloud-migration/read-only-mode! false)) (init-status/set-progress! 0.4) ;; Set up Prometheus (log/info "Setting up prometheus metrics") (analytics/setup!) (init-status/set-progress! 0.5) (premium-features/airgap-check-user-count) (init-status/set-progress! 0.55) ;; run a very quick check to see if we are doing a first time installation ;; the test we are using is if there is at least 1 User in the database (let [new-install? (not (setup/has-user-setup))] ;; initialize Metabase from an `config.yml` file if present (Enterprise Edition™ only) (config-from-file/init-from-file-if-code-available!) (init-status/set-progress! 0.6) (when new-install? (log/info "Looks like this is a new installation ... preparing setup wizard") ;; create setup token (create-setup-token-and-log-setup-url!) ;; publish install event (events/publish-event! :event/install {})) (init-status/set-progress! 0.7) ;; deal with our sample database as needed (when (config/load-sample-content?) (if new-install? ;; add the sample database DB for fresh installs (sample-data/extract-and-sync-sample-database!) ;; otherwise update if appropriate (sample-data/update-sample-database-if-needed!)))) (ensure-audit-db-installed!) (notification/seed-notification!) (init-status/set-progress! 0.9) (embed.settings/check-and-sync-settings-on-startup! env/env) (init-status/set-progress! 0.95) (setting/migrate-encrypted-settings!) (task/start-scheduler!) ;; In case we could not do this earlier (e.g. for DBs added via config file), because the scheduler was not up yet: (database/check-health-and-schedule-tasks!) (init-status/set-complete!) (let [start-time (.getStartTime (ManagementFactory/getRuntimeMXBean)) duration (- (System/currentTimeMillis) start-time)] (log/infof "Metabase Initialization COMPLETE in %s" (u/format-milliseconds duration)))) ``` -------------------------------- ### Create Setup Token and Log Setup URL Source: https://metabase-dev-docs.github.io/metabase/toc.html/metabase.core.core This private function is responsible for creating an initial setup token and then logging the setup URL. It ensures that a token exists before the setup URL is displayed to the user, facilitating the first-time setup process. ```Clojure (defn- create-setup-token-and-log-setup-url! [] (setup/create-token!) ; we need this here to create the initial token (print-setup-url)) ``` -------------------------------- ### Public API: Initialize Prometheus System (Clojure) Source: https://metabase-dev-docs.github.io/metabase/toc.html/metabase.analytics.prometheus This public API function, `setup!`, serves as the primary entry point for initializing the entire Prometheus metrics system. It ensures that the system is only initialized once and can optionally start a web server if a port is configured. This function should be called early in the application lifecycle. ```Clojure (defn setup! [] (when-not system (let [port (prometheus-server-port)] (when-not port (log/info "Running prometheus metrics without a webserver")) (locking #'system (when-not system (let [sys (make-prometheus-system port "metabase-registry")] (alter-var-root #'system (constantly sys)))))))) ``` -------------------------------- ### Safely Install Humane Are Source: https://metabase-dev-docs.github.io/metabase/toc.html/user Wraps the loading and installation of `humane-are.core` with `u/ignore-exceptions`. This allows the application to function even if `humane-are` is not available, preventing crashes during startup for environments where this dependency is optional or not needed. ```Clojure (u/ignore-exceptions (classloader/require 'humane-are.core) ((resolve 'humane-are.core/install!))) ``` -------------------------------- ### Metabase API: POST / (Initial Setup Endpoint) Source: https://metabase-dev-docs.github.io/metabase/toc.html/metabase.setup.api Defines the Metabase API endpoint for initial setup. This endpoint creates the first user, logs them in, and returns a session ID. It can also be used to add a database, create and invite a second admin, or set specific settings from the setup flow. The endpoint handles user creation, session management, and event publishing upon successful setup. ```Clojure (api.macros/defendpoint :post "/" "Special endpoint for creating the first user during setup. This endpoint both creates the user AND logs them in and returns a session ID. This endpoint can also be used to add a database, create and invite a second admin, and/or set specific settings from the setup flow." [_route-params _query-params {{first-name :first_name, last-name :last_name, :keys [email password]} :user {invited-first-name :first_name invited-last-name :last_name invited-email :email} :invite {site-name :site_name site-locale :site_locale} :prefs} :- [:map [:token SetupToken] [:user [:map [:email ms/Email] [:password ms/ValidPassword] [:first_name {:optional true} [:maybe ms/NonBlankString]] [:last_name {:optional true} [:maybe ms/NonBlankString]]]] [:invite {:optional true} [:map [:first_name {:optional true} [:maybe ms/NonBlankString]] [:last_name {:optional true} [:maybe ms/NonBlankString]] [:email {:optional true} [:maybe ms/Email]]]] [:prefs [:map [:site_name ms/NonBlankString] [:site_locale {:optional true} [:maybe ms/ValidLocale]]]]] request] (letfn [(create! [] (try (t2/with-transaction [] (let [user-info (setup-create-user! {:email email :first-name first-name :last-name last-name :password password :device-info (request/device-info request)})] (setup-maybe-create-and-invite-user! {:email invited-email :first_name invited-first-name :last_name invited-last-name} {:email email, :first_name first-name}) (setup-set-settings! {:email email :site-name site-name :site-locale site-locale}) user-info)) (catch Throwable e ;; if the transaction fails, restore the Settings cache from the DB again so any changes made in this ;; endpoint (such as clearing the setup token) are reverted. We can't use `dosync` here to accomplish ;; this because there is `io!` in this block (setting.cache/restore-cache!) (throw e))))] (let [{:keys [user-id session-id session]} (create!) superuser (t2/select-one :model/User :id user-id)] (events/publish-event! :event/user-login {:user-id user-id}) (when-not (:last_login superuser) (events/publish-event! :event/user-joined {:user-id user-id})) ;; return response with session ID and set the cookie as well (request/set-session-cookies request {:id session-id} session (t/zoned-date-time (t/zone-id "GMT"))))) ``` -------------------------------- ### Safely Load Hawk Assertions Source: https://metabase-dev-docs.github.io/metabase/toc.html/user Wraps the loading of `mb.hawk.assert-exprs` with `u/ignore-exceptions`. This ensures that if the `hawk` library is not available in the classpath (e.g., during specific CLI commands like migrations), the application can still start without crashing, allowing for partial functionality. ```Clojure (u/ignore-exceptions ;; make sure stuff like `=?` and what not are loaded (classloader/require 'mb.hawk.assert-exprs)) ``` -------------------------------- ### Print Metabase Setup URL Source: https://metabase-dev-docs.github.io/metabase/toc.html/metabase.core.core This private function constructs and logs the Metabase setup URL. It uses configured hostname, port, and the public site URL to generate the complete URL for initial setup, making it easy for users to access the setup wizard. ```Clojure (defn- print-setup-url [] (let [hostname (or (config/config-str :mb-jetty-host) "localhost") port (config/config-int :mb-jetty-port) site-url (or (public-settings/site-url) (str "http://" hostname (when-not (= 80 port) (str ":" port)))) setup-url (str site-url "/setup/")] (log/info (u/format-color 'green (str "Please use the following URL to setup your Metabase installation:" "\n\n" setup-url "\n\n"))))) ``` -------------------------------- ### Clojure: Start Portal debugging tool Source: https://metabase-dev-docs.github.io/metabase/toc.html/dev.debug-qp The `start-portal!` function initializes and starts the Portal debugging tool. It merges provided configuration with default settings, stops any existing Portal instance, starts a new one, adds a tap for `portal.api/submit`, and prints the port it's running on. This function is the primary entry point for activating Portal. ```Clojure (defn start-portal! ([] (start-portal! nil)) ([config] (let [config (merge default-portal-config config)] (stop-portal!) (reset! portal (portal.api/start config)) (add-tap #'portal.api/submit) #_{:clj-kondo/ignore [:discouraged-var]} (printf "Started Portal on port %d.\n" (:port config))))) ``` -------------------------------- ### Clojure: Macro for Query Processor Setup Source: https://metabase-dev-docs.github.io/metabase/toc.html/metabase.query-processor.setup This macro provides a convenient way to wrap a block of code (`body`) with the query processor setup. It expands to a call to `do-with-qp-setup`, passing the query and a function that encapsulates the `body`. This ensures that the QP Store, driver, and database-local settings are correctly resolved and bound for the code within the macro's scope. ```clj (defmacro with-qp-setup [[query-binding query] & body] `(do-with-qp-setup ~query (^:once fn* [~query-binding] ~@body))) ``` -------------------------------- ### Clojure Namespace for Metabase Setup API Source: https://metabase-dev-docs.github.io/metabase/toc.html/metabase.setup.api This code block defines the `metabase.setup.api` namespace, listing all required dependencies and aliases for the Metabase setup API. It serves as the foundational declaration for the API's functionality. ```clj (ns metabase.setup.api (:require [java-time.api :as t] [metabase.analytics.core :as analytics] [metabase.api.common :as api] [metabase.api.common.validation :as validation] [metabase.api.macros :as api.macros] [metabase.channel.email :as email] [metabase.config :as config] [metabase.db :as mdb] [metabase.embed.settings :as embed.settings] [metabase.events :as events] [metabase.integrations.slack :as slack] [metabase.models.interface :as mi] [metabase.models.setting :as setting] [metabase.models.setting.cache :as setting.cache] [metabase.models.user :as user] [metabase.permissions.core :as perms] [metabase.premium-features.core :as premium-features] [metabase.public-settings :as public-settings] [metabase.request.core :as request] [metabase.session.models.session :as session] [metabase.setup.core :as setup] [metabase.util :as u] [metabase.util.i18n :as i18n :refer [tru]] [metabase.util.log :as log] [metabase.util.malli :as mu] [metabase.util.malli.schema :as ms] [toucan2.core :as t2])) ``` -------------------------------- ### Define Metabase Setup Core Namespace Source: https://metabase-dev-docs.github.io/metabase/toc.html/metabase.setup.core This snippet defines the `metabase.setup.core` namespace, importing necessary modules like `environ.core`, `metabase.config`, `metabase.db`, `metabase.models.setting`, `metabase.util.i18n`, and `toucan2.core`. It sets up the core environment for Metabase setup operations. ```Clojure (ns metabase.setup.core (:require [environ.core :as env] [metabase.config :as config] [metabase.db :as mdb] [metabase.models.setting :as setting :refer [defsetting]] [metabase.util.i18n :refer [deferred-tru tru]] [toucan2.core :as t2])) ``` -------------------------------- ### APIDOC: GET /admin_checklist Endpoint Source: https://metabase-dev-docs.github.io/metabase/toc.html/metabase.setup.api This API endpoint returns the various 'admin checklist' steps and their completion status. It requires superuser permissions and performs an application permission check before returning the checklist generated by `admin-checklist`. ```APIDOC GET /admin_checklist Description: Return various "admin checklist" steps and whether they've been completed. You must be a superuser to see this! Permissions: - Superuser - Application permission: :setting Returns: Admin checklist data ``` -------------------------------- ### Clojure: Generate Admin Checklist Items Source: https://metabase-dev-docs.github.io/metabase/toc.html/metabase.setup.api This function generates a list of checklist items, grouping related tasks. It conditionally includes a 'Productionize' section if Metabase is not hosted, and always includes 'Get connected' and 'Curate your data' sections. ```Clojure (mu/defn- checklist-items [info :- ChecklistState] (remove nil? [{:name (tru "Get connected") :tasks (get-connected-tasks info)} (when-not (:hosted? info) {:name (tru "Productionize") :tasks (productionize-tasks info)}) {:name (tru "Curate your data") :tasks (curate-tasks info)}])) ``` -------------------------------- ### Clojure Function to Create Initial Metabase User Source: https://metabase-dev-docs.github.io/metabase/toc.html/metabase.setup.api The `setup-create-user!` function handles the creation of the very first user during Metabase setup. It inserts a new superuser into the database, sets their password, and immediately creates a session for them. A crucial check prevents this route from being used to create additional superusers after the initial setup, unless explicitly allowed for testing. ```clj (defn- setup-create-user! [{:keys [email first-name last-name password device-info]}] (when (and (setup/has-user-setup) (not *allow-api-setup-after-first-user-is-created*)) ;; many tests use /api/setup to setup multiple users, so *allow-api-setup-after-first-user-is-created* is ;; redefined by them (throw (ex-info (tru "The /api/setup route can only be used to create the first user, however a user currently exists.") {:status-code 403}))) (let [new-user (first (t2/insert-returning-instances! :model/User :email email :first_name first-name :last_name last-name :password (str (random-uuid)) :is_superuser true)) user-id (u/the-id new-user)] ;; this results in a second db call, but it avoids redundant password code so figure it's worth it (user/set-password! user-id password) ;; then we create a session right away because we want our new user logged in to continue the setup process (let [session (session/create-session! :password new-user device-info)] ;; return user ID, session ID, and the Session object itself {:session-id (:id session), :user-id user-id, :session session}))) ``` -------------------------------- ### Start Metabase Server (Clojure) Source: https://metabase-dev-docs.github.io/metabase/toc.html/dev This function initiates the Metabase application server. It starts the web server, performs necessary initialization routines, and, in development mode, prunes deleted in-memory databases and starts Malli development tools. ```Clojure (defn start! [] (server/start-web-server! #'handler/app) (init!) (when config/is-dev? (prune-deleted-inmem-databases!) (with-out-str (malli-dev/start!)))) ``` -------------------------------- ### Clojure: Execute with Query Processor Setup Source: https://metabase-dev-docs.github.io/metabase/toc.html/metabase.query-processor.setup This function executes a given function `f` with the query processor environment properly set up. It first checks if the setup has already occurred via `*has-setup*`. If not, it applies the `setup-middleware` functions in sequence, wrapping `f`, and then executes the wrapped function within a scope where `*has-setup*` is true. It also includes a check to prevent QP calls from core.async dispatch threads. ```clj (mu/defn do-with-qp-setup [query :- ::qp.schema/query f :- [:=> [:cat ::qp.schema/query] :any]] ;; TODO -- think about whether we should pre-compile this middleware (when (a.impl.dispatch/in-dispatch-thread?) (throw (ex-info "QP calls are not allowed inside core.async dispatch pool threads." {:type qp.error-type/qp}))) (if *has-setup* (f query) (let [f (reduce (fn [f middleware] (middleware f)) f setup-middleware)] (binding [*has-setup* true] (f query))))) ``` -------------------------------- ### Start Embedded Jetty Web Server (Clojure) Source: https://metabase-dev-docs.github.io/metabase/toc.html/metabase.server.instance Initiates the embedded Jetty web server. This function checks if a server is already running; if not, it creates a new server instance using the provided handler and configuration, then starts it. It returns ':started' if a new server was successfully launched, or 'nil' if a server was already active. ```Clojure (defn start-web-server! [handler] (when-not (instance) ;; NOTE: we always start jetty w/ join=false so we can start the server first then do init in the background (let [config (jetty-config) new-server (create-server handler config)] (log-config config) ;; Only start the server if the newly created server becomes the official new server ;; Don't JOIN yet -- we're doing other init in the background; we can join later (when (compare-and-set! instance* nil new-server) (.start new-server) :started)))) ``` -------------------------------- ### Check Metabase Setup Token Match Source: https://metabase-dev-docs.github.io/metabase/toc.html/metabase.setup.core This Clojure function, `token-match?`, validates if a provided string `token` matches the current `setup-token`. It returns `true` if they are identical, ensuring only authorized attempts to use the setup token are successful, and `false` otherwise. It requires the input `token` to be a string. ```Clojure (defn token-match? [token] {:pre [(string? token)]} (= token (setup-token))) ``` -------------------------------- ### Clojure Schema for Deprecated Setup Token Source: https://metabase-dev-docs.github.io/metabase/toc.html/metabase.setup.api This code defines a private and deprecated schema named `SetupToken` using `malli`. It validates that a string is non-blank and matches the setup token, providing a specific error message if validation fails. This schema is used to ensure the integrity of the setup token during API calls. ```clj (def ^:private ^:deprcated SetupToken (mu/with-api-error-message [:and ms/NonBlankString [:fn {:error/message "setup token"} (every-pred string? #'setup/token-match?)]] (i18n/deferred-tru "Token does not match the setup token."))) ``` -------------------------------- ### Clojure: Query Processor Setup Middleware List Source: https://metabase-dev-docs.github.io/metabase/toc.html/metabase.query-processor.setup This private definition lists the sequence of middleware functions applied during query processor setup. The order is significant, as middleware is applied from bottom to top (last in the list is applied first, then its result is passed to the next, and so on, effectively wrapping the final function). This list includes handlers for cancellation, database settings, driver, metadata, and database ID resolution. ```clj (def ^:private setup-middleware [#'do-with-canceled-chan #'do-with-database-local-settings #'do-with-driver #'do-with-metadata-provider #'do-with-resolved-database]) ``` -------------------------------- ### Clojure: Get PostgreSQL Start of Week Source: https://metabase-dev-docs.github.io/metabase/toc.html/metabase.driver.postgres This method specifies that the start of the week for PostgreSQL databases is Monday. It's a simple definition returning a fixed keyword. ```Clojure (defmethod driver/db-start-of-week :postgres [_] :monday) ``` -------------------------------- ### Perform General Metabase Database Setup Source: https://metabase-dev-docs.github.io/metabase/toc.html/metabase.db Performs general preparation and setup for the Metabase database, including validating connectivity and optionally running pending migrations. This function is thread-safe and will no-op if the database is already set up. Callers must explicitly specify whether to create sample content during migrations via the `create-sample-content?` keyword argument. ```Clojure (defn setup-db! [& {:keys [create-sample-content?]}] {:pre [(some? create-sample-content?)]} (when-not (db-is-set-up?) (locking mdb.connection/*application-db* (when-not (db-is-set-up?) (let [db-type (db-type) data-source (data-source) auto-migrate? (config/config-bool :mb-db-automigrate)] (mdb.setup/setup-db! db-type data-source auto-migrate? create-sample-content?)) (finish-db-setup)))) :done) ``` -------------------------------- ### Get Database Start of Week - Metabase Driver API Source: https://metabase-dev-docs.github.io/metabase/toc.html/metabase.driver Returns the day considered the start of the week by the driver, such as `:sunday`. This setting influences date-related calculations and aggregations within the database. ```Clojure (defmulti db-start-of-week {:added "0.37.0" :arglists '([driver])} dispatch-on-initialized-driver :hierarchy #'hierarchy) ``` -------------------------------- ### Get Combined Qualified Name for Field Source: https://metabase-dev-docs.github.io/metabase/toc.html/metabase.models.field This function generates a combined, dot-separated qualified name for a Metabase field. It leverages `qualified-name-components` to get the path parts and then joins them with dots. An example output is `table_name.parent_field_name.field_name`. ```Clojure (defn qualified-name [field] (str/join \. (qualified-name-components field))) ``` -------------------------------- ### Illustrate Custom Migrations and Honey SQL Dialect Registration Source: https://metabase-dev-docs.github.io/metabase/toc.html/metabase.db.setup This commented code block serves as an example or reminder for developers. It demonstrates how custom migrations are loaded and how the `:h2` dialect is registered with Honey SQL, ensuring proper database interaction. ```Clojure (comment ;; load our custom migrations custom-migrations/keep-me ;; needed so the `:h2` dialect gets registered with Honey SQL metabase.util.honey-sql-2/keep-me) ``` -------------------------------- ### Clojure Usage Examples and Comment Block Source: https://metabase-dev-docs.github.io/metabase/toc.html/dev.toucan2-monitor A comment block demonstrating various ways to interact with the `dev.toucan2-monitor` functions. It includes examples for starting, stopping, querying, resetting, summarizing, and exporting queries to CSV, serving as a quick reference for developers. ```Clojure (comment (start!) (queries) (stop!) (reset-queries!) (summary) (to-csv!) (doseq [q (querles)] #_:clj-kondo/ignore (println q))) ``` -------------------------------- ### API: Get Card Parameter Values Source: https://metabase-dev-docs.github.io/metabase/toc.html/metabase.api.card Fetches possible values for a specific parameter of a card, identified by its ID. This endpoint utilizes the `param-values` utility function to retrieve the values. An example usage is `GET /api/card/1/params/abc/values` to fetch values for parameter 'abc' of card ID 1. ```Clojure (api.macros/defendpoint :get "/:card-id/params/:param-key/values" "Fetch possible values of the parameter whose ID is `:param-key`. ;; fetch values for Card 1 parameter 'abc' that are possible GET /api/card/1/params/abc/values" [{:keys [card-id param-key]} :- [:map [:card-id ms/PositiveInt] [:param-key ms/NonBlankString]]] (param-values (api/read-check :model/Card card-id) param-key)) ``` -------------------------------- ### Execute All Plugin Initialization Steps Source: https://metabase-dev-docs.github.io/metabase/toc.html/metabase.plugins.init-steps This function, `do-init-steps!`, iterates through a list of initialization steps provided in a plugin's manifest. For each step, it calls the `do-init-step!` multimethod, ensuring all required setup for the plugin is performed. ```Clojure (defn do-init-steps! [init-steps] (doseq [step init-steps] (do-init-step! step))) ``` -------------------------------- ### Clojure: Get Configured Start of Week Source: https://metabase-dev-docs.github.io/metabase/toc.html/metabase.util.date-2 This private helper function dynamically retrieves the 'start of week' setting from Metabase's public settings. It uses `requiring-resolve` to access the setting, ensuring that the necessary namespace is loaded only when needed. The result is returned as a keyword, e.g., `:monday`. ```Clojure (defn- start-of-week [] (keyword ((requiring-resolve 'metabase.public-settings/start-of-week)))) ``` -------------------------------- ### Get Current Site Locale Object Source: https://metabase-dev-docs.github.io/metabase/toc.html/metabase.util.i18n Returns the default `java.util.Locale` object for the Metabase installation. This function converts the result of `site-locale-string` into a `Locale` object. ```Clojure (defn site-locale ^Locale [] (locale (site-locale-string))) ``` -------------------------------- ### APIDOC: GET /user_defaults Endpoint Source: https://metabase-dev-docs.github.io/metabase/toc.html/metabase.setup.api This API endpoint returns an object containing default user details for initial setup. It requires a `token` parameter in the request, which must match a configured token. It performs checks for 404 (no config token) and 403 (token mismatch) errors. ```APIDOC GET /user_defaults Description: Returns object containing default user details for initial setup, if configured, and if the provided token value matches the token in the configuration value. Parameters: - token: string (required) - Token value to match against configuration. Returns: Object containing default user details (excluding the token). Error Codes: - 404 Not Found: If configuration token is not found. - 403 Forbidden: If provided token does not match configuration token. ``` -------------------------------- ### Clojure: Setup Portal custom viewers Source: https://metabase-dev-docs.github.io/metabase/toc.html/dev.debug-qp The `portal-setup` private function performs post-startup setup for Portal, specifically loading custom viewers from a ClojureScript file. It reads the file content and evaluates it via `portal.api/eval-str`, allowing for dynamic configuration of Portal's display capabilities. This function can be called manually to reload viewers if needed. ```Clojure (defn- portal-setup [] (portal.api/eval-str (slurp (io/resource "dev/debug_qp/viewers.cljs")))) ``` -------------------------------- ### Clojure API Endpoint: Fetch Timeline by ID (GET /:id) Source: https://metabase-dev-docs.github.io/metabase/toc.html/metabase.timeline.api.timeline Defines a GET endpoint for fetching a specific `Timeline` by its ID. It supports `include`, `archived`, `start`, and `end` query parameters to control event inclusion and filtering, performing permission checks and hydrating related data. ```Clojure (api.macros/defendpoint :get "/:id" :- ::Timeline "Fetch the `Timeline` with `id`. Include `include=events` to unarchived events included on the timeline. Add `archived=true` to return all events on the timeline, both archived and unarchived." [{:keys [id]} :- [:map [:id ms/PositiveInt]] {:keys [include archived start end]} :- [:map [:include {:optional true} ::include] [:archived {:default :false} ms/BooleanValue] [:start {:optional true} ms/TemporalString] [:end {:optional true} ms/TemporalString]]] (let [archived? archived timeline (api/read-check (t2/select-one :model/Timeline :id id))] (cond-> (t2/hydrate timeline :creator [:collection :can_write]) ;; `collection_id` `nil` means we need to assoc 'root' collection ;; because hydrate `:collection` needs a proper `:id` to work. (nil? (:collection_id timeline)) collection.root/hydrate-root-collection (= include :events) (timeline-event/include-events-singular {:events/all? archived? :events/start (when start (u.date/parse start)) :events/end (when end (u.date/parse end))})))) ``` -------------------------------- ### Get Current Site Locale String Source: https://metabase-dev-docs.github.io/metabase/toc.html/metabase.util.i18n Returns the default locale string for the Metabase installation. It prioritizes `*site-locale-override*`, then the value from `i18n.impl/site-locale-from-setting`, defaulting to 'en' if neither is available. ```Clojure (defn site-locale-string [] (or *site-locale-override* (i18n.impl/site-locale-from-setting) "en")) ``` -------------------------------- ### Implement Init Step: Load Namespace Source: https://metabase-dev-docs.github.io/metabase/toc.html/metabase.plugins.init-steps This method implements the `:load-namespace` initialization step. It takes a map containing a `:namespace` key, logs the loading process, and then uses the classloader to dynamically require the specified Clojure namespace. ```Clojure (defmethod do-init-step! :load-namespace [{nmspace :namespace}] (log/debug (u/format-color 'blue "Loading plugin namespace %s..." nmspace)) (classloader/require (symbol nmspace))) ``` -------------------------------- ### Clojure: Initialize Metabase Database Connection and Setup Source: https://metabase-dev-docs.github.io/metabase/toc.html/metabase.db.setup This is the main function for setting up the Metabase database. It establishes a connection, verifies it, checks for downgrades, runs schema migrations, and performs encryption checks. It's designed to be called multiple times safely and is thread-safe. ```Clojure (mu/defn setup-db! [db-type :- :keyword 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)))) :done) ``` -------------------------------- ### Derive Text-Like Types Source: https://metabase-dev-docs.github.io/metabase/toc.html/types.cljc Defines `TextLike` types, which are primarily displayed as text but do not support advanced filtering options like 'starts with' or 'contains'. Specific examples include `MongoBSONID` and `MySQLEnum`. ```Clojure (derive :type/TextLike :type/*) (derive :type/MongoBSONID :type/TextLike) (derive :type/MySQLEnum :type/Text) ``` -------------------------------- ### Define Metabase Setup Token Setting Source: https://metabase-dev-docs.github.io/metabase/toc.html/metabase.setup.core This snippet defines `setup-token` as a Metabase setting. This token is crucial for granting initial user creation permissions upon the first launch of a Metabase instance. It is automatically generated and cleared after its single use. ```Clojure (defsetting setup-token :visibility :public :setter :none :audit :never) ``` -------------------------------- ### Clojure Function to Get Metabase Instance Creation Time Source: https://metabase-dev-docs.github.io/metabase/toc.html/metabase.permissions.api Retrieves the earliest `date_joined` from the `User` model, representing the creation time of the Metabase instance. This function is used internally to determine the age of the Metabase installation. ```Clojure (defn- instance-create-time [] (->> (t2/select-one [:model/User [:%min.date_joined :min]]) :min t/local-date-time)) ``` -------------------------------- ### Clojure: Get Temporal Range Source: https://metabase-dev-docs.github.io/metabase/toc.html/metabase.util.date-2 This function calculates a start and end instant for a specified time unit containing a given temporal value. It supports inclusive/exclusive start/end and different resolutions, providing a flexible way to define time spans. ```Clojure (mu/defn range :- [:map [:start TemporalInstance] [:end TemporalInstance]] "Get a start (by default, inclusive) and end (by default, exclusive) pair of instants for a `unit` span of time containing `t`. e.g. (range (t/zoned-date-time \"2019-11-01T15:29:00Z[UTC]\") :week) -> {:start (t/zoned-date-time \"2019-10-27T00:00Z[UTC]\") :end (t/zoned-date-time \"2019-11-03T00:00Z[UTC]\")}" ([unit] (range (t/zoned-date-time) unit)) ([t unit] (range t unit nil)) ([t :- TemporalInstance unit :- (into [:enum] add-units) {:keys [start end resolution] :or {start :inclusive end :exclusive resolution :millisecond}}] (let [t (truncate t unit)] {:start (case start :inclusive t :exclusive (add t resolution -1)) :end (case end :inclusive (add (add t unit 1) resolution -1) :exclusive (add t unit 1))}))) ``` -------------------------------- ### Mark Metabase Application DB as Setup Source: https://metabase-dev-docs.github.io/metabase/toc.html/metabase.db Marks the current Metabase application database as fully set up and ready. This function updates the status atom of `mdb.connection/*application-db*` to `::setup-finished`, signaling that initial database preparations are complete. ```Clojure (defn finish-db-setup [] (reset! (:status mdb.connection/*application-db*) ::setup-finished)) ``` -------------------------------- ### Generate Metabase 'Productionize' Onboarding Tasks in Clojure Source: https://metabase-dev-docs.github.io/metabase/toc.html/metabase.setup.api This Clojure function `productionize-tasks` takes the application state and returns a list of 'Productionize' onboarding tasks. Currently, it includes a task to switch to a production-ready application database (e.g., PostgreSQL or MySQL) from the default H2. The task's completion and trigger conditions depend on the current database type and whether the instance is hosted. ```Clojure (defn- productionize-tasks [info] [{:title (tru "Switch to a production-ready app database") :group (tru "Productionize") :description (tru "Migrate off of the default H2 application database to PostgreSQL or MySQL") :link "https://www.metabase.com/docs/latest/installation-and-operation/migrating-from-h2" :completed (not= (:db-type info) :h2) :triggered (and (= (:db-type info) :h2) (not (:hosted? info)))}]) ``` -------------------------------- ### Define metabase.db.setup Namespace Source: https://metabase-dev-docs.github.io/metabase/toc.html/metabase.db.setup This code block defines the `metabase.db.setup` namespace, importing necessary modules for database operations, configuration, encryption, logging, and the Toucan2 ORM. It establishes the environment for database setup and migration functions. ```Clojure (ns metabase.db.setup (:require [honey.sql :as sql] [metabase.config :as config] [metabase.db.connection :as mdb.connection] [metabase.db.custom-migrations :as custom-migrations] [metabase.db.encryption :as mdb.encryption] [metabase.db.jdbc-protocols :as mdb.jdbc-protocols] [metabase.db.liquibase :as liquibase] [metabase.plugins.classloader :as classloader] [metabase.util :as u] [metabase.util.encryption :as encryption] [metabase.util.honey-sql-2] [metabase.util.i18n :refer [trs]] [metabase.util.log :as log] [metabase.util.malli :as mu] [metabase.util.malli.schema :as ms] [metabase.util.string :as string] [methodical.core :as methodical] [toucan2.core :as t2] [toucan2.honeysql2 :as t2.honeysql] [toucan2.jdbc.options :as t2.jdbc.options] [toucan2.pipeline :as t2.pipeline]) (:import (liquibase.exception LockException))) ``` -------------------------------- ### Clojure: Hydrate Users with is_installer Flag Source: https://metabase-dev-docs.github.io/metabase/toc.html/metabase.models.user Adds the `is_installer` flag to a collection of `users`. This flag is `true` only for the user who underwent the initial app setup flow (with an ID of 1). It's used to modify the starting page experience for these specific users. ```Clojure (mi/define-batched-hydration-method add-is-installer :is_installer "Adds the `is_installer` flag to a collection of `users`. This should be `true` for only the user who underwent the initial app setup flow (with an ID of 1). This is used to modify the experience of the starting page for users." [users] (when (seq users) (for [user users] (assoc user :is_installer (= (:id user) 1))))) ```