From b09db3b450047b4b94e6d595ecb1b3763b3ceb78 Mon Sep 17 00:00:00 2001
From: bryan <bryan.maass@gmail.com>
Date: Thu, 29 Feb 2024 15:43:36 -0800
Subject: [PATCH] Tech Debt: teamzero (#39417)

* [AS+BCM] fix first 3 todos

* [AS+BCM] add issues

* add jdbc proxy issue

* driver/driver-features -> driver/features

* killing more todos and remove `supports?`

* add more issues

* dont let people who dont have snippet perms access snippets

* adding more issues

* replace calls to support? in mongo driver

* fix namespace sorting

* whitespace
---
 .clj-kondo/config.edn                         |  2 +-
 .../sso/integrations/jwt.clj                  |  4 +-
 .../sso/integrations/saml.clj                 |  4 +-
 .../sandbox/api/gtap_test.clj                 |  4 +-
 .../athena/test/metabase/test/data/athena.clj |  2 +-
 .../metabase/driver/bigquery_cloud_sdk.clj    |  2 +
 .../mongo/src/metabase/driver/mongo.clj       | 12 +-----
 .../mongo/test/metabase/test/data/mongo.clj   |  5 ---
 src/metabase/api/database.clj                 |  6 ++-
 src/metabase/api/session.clj                  | 30 +++++++-------
 src/metabase/api/user.clj                     |  4 +-
 src/metabase/driver.clj                       | 39 +++++--------------
 src/metabase/driver/util.clj                  |  2 +-
 src/metabase/lib/join.cljc                    |  2 +-
 src/metabase/lib/js.cljs                      |  2 +-
 src/metabase/lib/schema/metadata.cljc         |  2 +-
 src/metabase/models/collection.clj            |  5 +--
 src/metabase/models/dashboard.clj             |  2 +
 src/metabase/models/humanization.clj          |  1 +
 src/metabase/models/login_history.clj         |  6 +--
 src/metabase/models/session.clj               |  4 +-
 src/metabase/plugins/jdbc_proxy.clj           |  1 +
 src/metabase/server/middleware/auth.clj       |  8 ++--
 .../server/middleware/browser_cookie.clj      |  4 +-
 src/metabase/server/middleware/log.clj        |  4 +-
 src/metabase/server/middleware/misc.clj       |  4 +-
 src/metabase/server/middleware/security.clj   | 18 ++-------
 src/metabase/server/middleware/session.clj    | 10 ++---
 src/metabase/server/middleware/ssl.clj        |  4 +-
 src/metabase/server/middleware/util.clj       |  5 ---
 src/metabase/server/request/util.clj          |  9 +++++
 test/metabase/api/alert_test.clj              |  6 +--
 test/metabase/api/card_test.clj               |  6 +--
 test/metabase/api/dashboard_test.clj          |  4 +-
 test/metabase/api/metric_test.clj             |  6 +--
 test/metabase/api/notify_test.clj             |  4 +-
 test/metabase/api/pulse_test.clj              |  6 +--
 test/metabase/api/segment_test.clj            |  6 +--
 test/metabase/api/table_test.clj              |  6 +--
 test/metabase/api/timeline_event_test.clj     |  6 +--
 test/metabase/api/timeline_test.clj           |  6 +--
 test/metabase/api/user_test.clj               |  6 +--
 test/metabase/models/login_history_test.clj   |  4 +-
 test/metabase/query_processor/test_util.clj   |  4 +-
 test/metabase/server/middleware/auth_test.clj | 12 +++---
 test/metabase/server/request/util_test.clj    | 18 ++++-----
 46 files changed, 137 insertions(+), 170 deletions(-)
 delete mode 100644 src/metabase/server/middleware/util.clj

diff --git a/.clj-kondo/config.edn b/.clj-kondo/config.edn
index 32c53cecb9a..059b7e9a8ee 100644
--- a/.clj-kondo/config.edn
+++ b/.clj-kondo/config.edn
@@ -340,7 +340,7 @@
     metabase.server.middleware.security                             mw.security
     metabase.server.middleware.session                              mw.session
     metabase.server.middleware.ssl                                  mw.ssl
-    metabase.server.middleware.util                                 mw.util
+    metabase.server.request.util                                    req.util
     metabase.server.protocols                                       server.protocols
     metabase.shared.util                                            shared.u
     metabase.shared.util.currency                                   currency
diff --git a/enterprise/backend/src/metabase_enterprise/sso/integrations/jwt.clj b/enterprise/backend/src/metabase_enterprise/sso/integrations/jwt.clj
index 0fd300419a1..678a6730685 100644
--- a/enterprise/backend/src/metabase_enterprise/sso/integrations/jwt.clj
+++ b/enterprise/backend/src/metabase_enterprise/sso/integrations/jwt.clj
@@ -12,7 +12,7 @@
    [metabase.integrations.common :as integrations.common]
    [metabase.public-settings.premium-features :as premium-features]
    [metabase.server.middleware.session :as mw.session]
-   [metabase.server.request.util :as request.u]
+   [metabase.server.request.util :as req.util]
    [metabase.util.i18n :refer [tru]]
    [ring.util.response :as response])
   (:import
@@ -91,7 +91,7 @@
           first-name   (get jwt-data (jwt-attribute-firstname))
           last-name    (get jwt-data (jwt-attribute-lastname))
           user         (fetch-or-create-user! first-name last-name email login-attrs)
-          session      (api.session/create-session! :sso user (request.u/device-info request))]
+          session      (api.session/create-session! :sso user (req.util/device-info request))]
       (sync-groups! user jwt-data)
       (mw.session/set-session-cookies request (response/redirect redirect-url) session (t/zoned-date-time (t/zone-id "GMT"))))))
 
diff --git a/enterprise/backend/src/metabase_enterprise/sso/integrations/saml.clj b/enterprise/backend/src/metabase_enterprise/sso/integrations/saml.clj
index 5c0c9fa5b34..d28f7db153c 100644
--- a/enterprise/backend/src/metabase_enterprise/sso/integrations/saml.clj
+++ b/enterprise/backend/src/metabase_enterprise/sso/integrations/saml.clj
@@ -44,7 +44,7 @@
    [metabase.public-settings :as public-settings]
    [metabase.public-settings.premium-features :as premium-features]
    [metabase.server.middleware.session :as mw.session]
-   [metabase.server.request.util :as request.u]
+   [metabase.server.request.util :as req.util]
    [metabase.util :as u]
    [metabase.util.i18n :refer [trs tru]]
    [metabase.util.log :as log]
@@ -230,7 +230,7 @@
                            :email           email
                            :group-names     groups
                            :user-attributes attrs
-                           :device-info     (request.u/device-info request)})
+                           :device-info     (req.util/device-info request)})
           response      (response/redirect (or continue-url (public-settings/site-url)))]
       (mw.session/set-session-cookies request response session (t/zoned-date-time (t/zone-id "GMT"))))))
 
diff --git a/enterprise/backend/test/metabase_enterprise/sandbox/api/gtap_test.clj b/enterprise/backend/test/metabase_enterprise/sandbox/api/gtap_test.clj
index 9b83a658979..c63a58f913c 100644
--- a/enterprise/backend/test/metabase_enterprise/sandbox/api/gtap_test.clj
+++ b/enterprise/backend/test/metabase_enterprise/sandbox/api/gtap_test.clj
@@ -6,7 +6,7 @@
    [metabase.models :refer [Card Field PermissionsGroup Table]]
    [metabase.models.permissions :as perms]
    [metabase.public-settings.premium-features :as premium-features]
-   [metabase.server.middleware.util :as mw.util]
+   [metabase.server.request.util :as req.util]
    [metabase.test :as mt]
    [toucan2.core :as t2]
    [toucan2.tools.with-temp :as t2.with-temp]))
@@ -14,7 +14,7 @@
 (deftest require-auth-test
   (testing "Must be authenticated to query for GTAPs"
     (mt/with-premium-features #{:sandboxes}
-      (is (= (get mw.util/response-unauthentic :body)
+      (is (= (get req.util/response-unauthentic :body)
              (client/client :get 401 "mt/gtap")))
 
       (is (= "You don't have permissions to do that."
diff --git a/modules/drivers/athena/test/metabase/test/data/athena.clj b/modules/drivers/athena/test/metabase/test/data/athena.clj
index 28659189281..93b126b114b 100644
--- a/modules/drivers/athena/test/metabase/test/data/athena.clj
+++ b/modules/drivers/athena/test/metabase/test/data/athena.clj
@@ -184,7 +184,7 @@
                               :type/Time           "TIMESTAMP"}]
   (defmethod sql.tx/field-base-type->sql-type [:athena base-type] [_ _] sql-type))
 
-;; I'm not sure why `driver/supports?` above doesn't rectify this, but make `add-fk-sql a noop
+;; TODO: Maybe make `add-fk-sql a noop
 (defmethod sql.tx/add-fk-sql :athena [& _] nil)
 
 ;; Athena can only execute one statement at a time
diff --git a/modules/drivers/bigquery-cloud-sdk/src/metabase/driver/bigquery_cloud_sdk.clj b/modules/drivers/bigquery-cloud-sdk/src/metabase/driver/bigquery_cloud_sdk.clj
index ae9538a92ca..978cc425ca1 100644
--- a/modules/drivers/bigquery-cloud-sdk/src/metabase/driver/bigquery_cloud_sdk.clj
+++ b/modules/drivers/bigquery-cloud-sdk/src/metabase/driver/bigquery_cloud_sdk.clj
@@ -512,6 +512,8 @@
       (t2/update! Database db-id {:details (:details updated-db)})
       updated-db)))
 
+;; TODO: THIS METHOD SHOULD NOT BE UPDATING THE APP-DB (which it does in [convert-dataset-id-to-filters!])
+;; Issue: https://github.com/metabase/metabase/issues/39392
 (defmethod driver/normalize-db-details :bigquery-cloud-sdk
   [_driver {:keys [details] :as database}]
   (when-not (empty? (filter some? ((juxt :auth-code :client-id :client-secret) details)))
diff --git a/modules/drivers/mongo/src/metabase/driver/mongo.clj b/modules/drivers/mongo/src/metabase/driver/mongo.clj
index 30ba5305964..22ef38d019f 100644
--- a/modules/drivers/mongo/src/metabase/driver/mongo.clj
+++ b/modules/drivers/mongo/src/metabase/driver/mongo.clj
@@ -23,8 +23,8 @@
    [metabase.util.log :as log]
    [taoensso.nippy :as nippy])
   (:import
-   (org.bson.types ObjectId)
-   (com.mongodb.client MongoClient MongoDatabase)))
+   (com.mongodb.client MongoClient MongoDatabase)
+   (org.bson.types ObjectId)))
 
 (set! *warn-on-reflection* true)
 
@@ -271,14 +271,6 @@
                               :index-info                      true}]
   (defmethod driver/database-supports? [:mongo feature] [_driver _feature _db] supported?))
 
-;; We say Mongo supports foreign keys so that the front end can use implicit
-;; joins. In reality, Mongo doesn't support foreign keys.
-;; Only define an implementation for `:foreign-keys` if none exists already.
-;; In test extensions we define an alternate implementation, and we don't want
-;; to stomp over that if it was loaded already.
-(when-not (get (methods driver/supports?) [:mongo :foreign-keys])
-  (defmethod driver/supports? [:mongo :foreign-keys] [_ _] true))
-
 (defmethod driver/database-supports? [:mongo :schemas] [_driver _feat _db] false)
 
 (defmethod driver/database-supports? [:mongo :expressions]
diff --git a/modules/drivers/mongo/test/metabase/test/data/mongo.clj b/modules/drivers/mongo/test/metabase/test/data/mongo.clj
index b09c1858766..fb5129698cc 100644
--- a/modules/drivers/mongo/test/metabase/test/data/mongo.clj
+++ b/modules/drivers/mongo/test/metabase/test/data/mongo.clj
@@ -6,8 +6,6 @@
    [clojure.test :refer :all]
    [flatland.ordered.map :as ordered-map]
    [medley.core :as m]
-   [metabase.config :as config]
-   [metabase.driver :as driver]
    [metabase.driver.ddl.interface :as ddl.i]
    [metabase.driver.mongo.connection :as mongo.connection]
    [metabase.driver.mongo.util :as mongo.util]
@@ -23,9 +21,6 @@
 (defmethod tx/supports-time-type? :mongo [_driver] false)
 (defmethod tx/supports-timestamptz-type? :mongo [_driver] false)
 
-;; during unit tests don't treat Mongo as having FK support
-(defmethod driver/supports? [:mongo :foreign-keys] [_ _] (not config/is-test?))
-
 (defn ssl-required?
   "Returns if the mongo server requires an SSL connection."
   []
diff --git a/src/metabase/api/database.clj b/src/metabase/api/database.clj
index 156afd71400..59b3d313c38 100644
--- a/src/metabase/api/database.clj
+++ b/src/metabase/api/database.clj
@@ -448,7 +448,11 @@
   (let [db (-> (if include-editable-data-model?
                  (api/check-404 (t2/select-one Database :id id))
                  (api/read-check Database id))
-               (t2/hydrate [:tables [:fields [:target :has_field_values] :has_field_values] :segments :metrics]))
+               (t2/hydrate [:tables [:fields
+                                     :has_field_values
+                                     [:target :has_field_values]]
+                            :segments
+                            :metrics]))
         db (if include-editable-data-model?
              ;; We need to check data model perms after hydrating tables, since this will also filter out tables for
              ;; which the *current-user* does not have data model perms
diff --git a/src/metabase/api/session.clj b/src/metabase/api/session.clj
index 53bf8434246..455f78918e2 100644
--- a/src/metabase/api/session.clj
+++ b/src/metabase/api/session.clj
@@ -19,7 +19,7 @@
    [metabase.models.user :as user :refer [User]]
    [metabase.public-settings :as public-settings]
    [metabase.server.middleware.session :as mw.session]
-   [metabase.server.request.util :as request.u]
+   [metabase.server.request.util :as req.util]
    [metabase.util :as u]
    [metabase.util.i18n :refer [deferred-tru trs tru]]
    [metabase.util.log :as log]
@@ -37,7 +37,7 @@
 (mu/defn ^:private record-login-history!
   [session-id  :- (ms/InstanceOfClass UUID)
    user-id     :- ms/PositiveInt
-   device-info :- request.u/DeviceInfo]
+   device-info :- req.util/DeviceInfo]
   (t2/insert! LoginHistory (merge {:user_id    user-id
                                    :session_id (str session-id)}
                                   device-info)))
@@ -62,7 +62,7 @@
     [:type [:enum :normal :full-app-embed]]]])
 
 (mu/defmethod create-session! :sso :- SessionSchema
-  [_ user :- CreateSessionUserInfo device-info :- request.u/DeviceInfo]
+  [_ user :- CreateSessionUserInfo device-info :- req.util/DeviceInfo]
   (let [session-uuid (random-uuid)
         session      (first (t2/insert-returning-instances! Session
                                                             :id      (str session-uuid)
@@ -80,7 +80,7 @@
 (mu/defmethod create-session! :password :- SessionSchema
   [session-type
    user         :- CreateSessionUserInfo
-   device-info  :- request.u/DeviceInfo]
+   device-info  :- req.util/DeviceInfo]
   ;; this is actually the same as `create-session!` for `:sso` but we check whether password login is enabled.
   (when-not (public-settings/enable-password-login)
     (throw (ex-info (str (tru "Password login is disabled for this instance.")) {:status-code 400})))
@@ -107,7 +107,7 @@
 (mu/defn ^:private ldap-login :- [:maybe [:map [:id (ms/InstanceOfClass UUID)]]]
   "If LDAP is enabled and a matching user exists return a new Session for them, or `nil` if they couldn't be
   authenticated."
-  [username password device-info :- request.u/DeviceInfo]
+  [username password device-info :- req.util/DeviceInfo]
   (when (api.ldap/ldap-enabled)
     (try
       (when-let [user-info (ldap/find-user username)]
@@ -131,7 +131,7 @@
   "Find a matching `User` if one exists and return a new Session for them, or `nil` if they couldn't be authenticated."
   [username    :- ms/NonBlankString
    password    :- [:maybe ms/NonBlankString]
-   device-info :- request.u/DeviceInfo]
+   device-info :- req.util/DeviceInfo]
   (if-let [user (t2/select-one [User :id :password_salt :password :last_login :is_active], :%lower.email (u/lower-case-en username))]
     (when (u.password/verify-password password (:password_salt user) (:password user))
       (if (:is_active user)
@@ -157,7 +157,7 @@
   throwing an Exception if login could not be completed."
   [username    :- ms/NonBlankString
    password    :- ms/NonBlankString
-   device-info :- request.u/DeviceInfo]
+   device-info :- req.util/DeviceInfo]
   ;; Primitive "strategy implementation", should be reworked for modular providers in #3210
   (or (ldap-login username password device-info)  ; First try LDAP if it's enabled
       (email-login username password device-info) ; Then try local authentication
@@ -185,10 +185,10 @@
   [:as {{:keys [username password]} :body, :as request}]
   {username ms/NonBlankString
    password ms/NonBlankString}
-  (let [ip-address   (request.u/ip-address request)
+  (let [ip-address   (req.util/ip-address request)
         request-time (t/zoned-date-time (t/zone-id "GMT"))
         do-login     (fn []
-                       (let [{session-uuid :id, :as session} (login username password (request.u/device-info request))
+                       (let [{session-uuid :id, :as session} (login username password (req.util/device-info request))
                              response                        {:id (str session-uuid)}]
                          (mw.session/set-session-cookies request response session request-time)))]
     (if throttling-disabled?
@@ -240,7 +240,7 @@
   [:as {{:keys [email]} :body, :as request}]
   {email ms/Email}
   ;; Don't leak whether the account doesn't exist, just pretend everything is ok
-  (let [request-source (request.u/ip-address request)]
+  (let [request-source (req.util/ip-address request)]
     (throttle-check (forgot-password-throttlers :ip-address) request-source))
   (throttle-check (forgot-password-throttlers :email) email)
   (forgot-password-impl email)
@@ -289,7 +289,7 @@
             ;; Send all the active admins an email :D
             (messages/send-user-joined-admin-notification-email! (t2/select-one User :id user-id)))
           ;; after a successful password update go ahead and offer the client a new session that they can use
-          (let [{session-uuid :id, :as session} (create-session! :password user (request.u/device-info request))
+          (let [{session-uuid :id, :as session} (create-session! :password user (req.util/device-info request))
                 response                        {:success    true
                                                  :session_id (str session-uuid)}]
             (mw.session/set-session-cookies request response session (t/zoned-date-time (t/zone-id "GMT"))))))
@@ -317,9 +317,9 @@
   (if throttling-disabled?
     (google/do-google-auth request)
     (http-401-on-error
-     (throttle/with-throttling [(login-throttlers :ip-address) (request.u/ip-address request)]
+     (throttle/with-throttling [(login-throttlers :ip-address) (req.util/ip-address request)]
        (let [user (google/do-google-auth request)
-             {session-uuid :id, :as session} (create-session! :sso user (request.u/device-info request))
+             {session-uuid :id, :as session} (create-session! :sso user (req.util/device-info request))
              response {:id (str session-uuid)}
              user (t2/select-one [User :id :is_active], :email (:email user))]
          (if (and user (:is_active user))
@@ -356,7 +356,7 @@
   {pulse-id ms/PositiveInt
    email    :string
    hash     :string}
-  (check-hash pulse-id email hash (request.u/ip-address request))
+  (check-hash pulse-id email hash (req.util/ip-address request))
   (t2/with-transaction [_conn]
     (api/let-404 [pulse-channel (t2/select-one PulseChannel :pulse_id pulse-id :channel_type "email")]
       (let [emails (get-in pulse-channel [:details :emails])]
@@ -374,7 +374,7 @@
   {pulse-id ms/PositiveInt
    email    :string
    hash     :string}
-  (check-hash pulse-id email hash (request.u/ip-address request))
+  (check-hash pulse-id email hash (req.util/ip-address request))
   (t2/with-transaction [_conn]
     (api/let-404 [pulse-channel (t2/select-one PulseChannel :pulse_id pulse-id :channel_type "email")]
       (let [emails (get-in pulse-channel [:details :emails])]
diff --git a/src/metabase/api/user.clj b/src/metabase/api/user.clj
index 775d8489aac..42b7c42ae28 100644
--- a/src/metabase/api/user.clj
+++ b/src/metabase/api/user.clj
@@ -25,7 +25,7 @@
    [metabase.public-settings.premium-features :as premium-features]
    [metabase.server.middleware.offset-paging :as mw.offset-paging]
    [metabase.server.middleware.session :as mw.session]
-   [metabase.server.request.util :as request.u]
+   [metabase.server.request.util :as req.util]
    [metabase.util :as u]
    [metabase.util.i18n :refer [deferred-tru tru]]
    [metabase.util.malli.schema :as ms]
@@ -519,7 +519,7 @@
     (user/set-password! id password)
     ;; after a successful password update go ahead and offer the client a new session that they can use
     (when (= id api/*current-user-id*)
-      (let [{session-uuid :id, :as session} (api.session/create-session! :password user (request.u/device-info request))
+      (let [{session-uuid :id, :as session} (api.session/create-session! :password user (req.util/device-info request))
             response                        {:success    true
                                              :session_id (str session-uuid)}]
         (mw.session/set-session-cookies request response session (t/zoned-date-time (t/zone-id "GMT")))))))
diff --git a/src/metabase/driver.clj b/src/metabase/driver.clj
index be0bb80b48b..a702340c9f1 100644
--- a/src/metabase/driver.clj
+++ b/src/metabase/driver.clj
@@ -425,8 +425,7 @@
   dispatch-on-initialized-driver
   :hierarchy #'hierarchy)
 
-;; TODO -- I think we should rename this to `features` since `driver/driver-features` is a bit redundant.
-(def driver-features
+(def features
   "Set of all features a driver can support."
   #{
     ;; Does this database support foreign key relationships?
@@ -550,25 +549,6 @@
     ;; Does the driver support column(s) support storing index info
     :index-info})
 
-
-(defmulti supports?
-  "Does this driver support a certain `feature`? (A feature is a keyword, and can be any of the ones listed above in
-  [[driver-features]].)
-
-    (supports? :postgres :set-timezone) ; -> true
-
-  DEPRECATED — [[database-supports?]] should be used instead. This function will be removed in Metabase version 0.50.0."
-  {:added "0.32.0", :arglists '([driver feature]), :deprecated "0.47.0"}
-  (fn [driver feature]
-    (when-not (driver-features feature)
-      (throw (Exception. (tru "Invalid driver feature: {0}" feature))))
-    [(dispatch-on-initialized-driver driver) feature])
-  :hierarchy #'hierarchy)
-
-(defmethod supports? :default [_ _] false)
-
-(defmethod supports? [::driver :schemas] [_ _] true)
-
 (defmulti database-supports?
   "Does this driver and specific instance of a database support a certain `feature`?
   (A feature is a keyword, and can be any of the ones listed above in `driver-features`.
@@ -587,18 +567,20 @@
     (database-supports? :mongo :set-timezone mongo-db) ; -> true"
   {:arglists '([driver feature database]), :added "0.41.0"}
   (fn [driver feature _database]
-    (when-not (driver-features feature)
+    (when-not (features feature)
       (throw (Exception. (tru "Invalid driver feature: {0}" feature))))
     [(dispatch-on-initialized-driver driver) feature])
   :hierarchy #'hierarchy)
 
-(defmethod database-supports? :default [driver feature _] (supports? driver feature))
+(defmethod database-supports?
+  :default [_driver _feature _] false)
 
-(doseq [[feature supported?] {:basic-aggregations                     true
+(doseq [[feature supported?] {:convert-timezone                       false
+                              :basic-aggregations                     true
                               :case-sensitivity-string-filter-options true
                               :date-arithmetics                       true
                               :temporal-extract                       true
-                              :convert-timezone                       false
+                              :schemas                                true
                               :test/jvm-timezone-setting              true}]
   (defmethod database-supports? [::driver feature] [_driver _feature _db] supported?))
 
@@ -712,10 +694,8 @@
   [_ query]
   query)
 
-;; TODO - we should just have some sort of `core.async` channel to handle DB update notifications instead
-;;
 ;; TODO -- shouldn't this be called `notify-database-updated!`, since the expectation is that it is done for side
-;; effects?
+;; effects? issue: https://github.com/metabase/metabase/issues/39367
 (defmulti notify-database-updated
   "Notify the driver that the attributes of a `database` have changed, or that `database was deleted. This is
   specifically relevant in the event that the driver was doing some caching or connection pooling; the driver should
@@ -804,6 +784,7 @@
 (defmethod default-field-order ::driver [_] :database)
 
 ;; TODO -- this can vary based on session variables or connection options
+;; Issue: https://github.com/metabase/metabase/pull/39386
 (defmulti db-start-of-week
   "Return the day that is considered to be the start of week by `driver`. Should return a keyword such as `:sunday`."
   {:added "0.37.0" :arglists '([driver])}
@@ -826,8 +807,8 @@
 ;;;
 ;;; 1. We definitely should not be asking drivers to "update the value for `:details`". Drivers shouldn't touch the
 ;;;    application database.
-;;;
 ;;; 2. Something that is done for side effects like updating the application DB NEEDS TO END IN AN EXCLAMATION MARK!
+;;; Issue: https://github.com/metabase/metabase/issues/39392
 (defmulti normalize-db-details
   "Normalizes db-details for the given driver. This is to handle migrations that are too difficult to perform via
   regular Liquibase queries. This multimethod will be called from a `:post-select` handler within the database model.
diff --git a/src/metabase/driver/util.clj b/src/metabase/driver/util.clj
index 91ce5b7fbe8..77a2e0d2795 100644
--- a/src/metabase/driver/util.clj
+++ b/src/metabase/driver/util.clj
@@ -211,7 +211,7 @@
 (defn features
   "Return a set of all features supported by `driver` with respect to `database`."
   [driver database]
-  (set (for [feature driver/driver-features
+  (set (for [feature driver/features
              :when (driver/database-supports? driver feature database)]
          feature)))
 
diff --git a/src/metabase/lib/join.cljc b/src/metabase/lib/join.cljc
index 03531e78c40..7d5f36f79cb 100644
--- a/src/metabase/lib/join.cljc
+++ b/src/metabase/lib/join.cljc
@@ -568,7 +568,7 @@
 
 (mu/defn available-join-strategies :- [:sequential ::lib.schema.join/strategy.option]
   "Get available join strategies for the current Database (based on the Database's
-  supported [[metabase.driver/driver-features]]) as raw keywords like `:left-join`."
+  supported [[metabase.driver/features]]) as raw keywords like `:left-join`."
   ([query]
    (available-join-strategies query -1))
 
diff --git a/src/metabase/lib/js.cljs b/src/metabase/lib/js.cljs
index 814a7c4633f..d901c1c9f36 100644
--- a/src/metabase/lib/js.cljs
+++ b/src/metabase/lib/js.cljs
@@ -739,7 +739,7 @@
 
 (defn ^:export available-join-strategies
   "Get available join strategies for the current Database (based on the Database's
-  supported [[metabase.driver/driver-features]]) as opaque JoinStrategy objects."
+  supported [[metabase.driver/features]]) as opaque JoinStrategy objects."
   [a-query stage-number]
   (to-array (lib.core/available-join-strategies a-query stage-number)))
 
diff --git a/src/metabase/lib/schema/metadata.cljc b/src/metabase/lib/schema/metadata.cljc
index 1016ca49dc5..181088a00c1 100644
--- a/src/metabase/lib/schema/metadata.cljc
+++ b/src/metabase/lib/schema/metadata.cljc
@@ -280,7 +280,7 @@
    {:error/message "Valid Database metadata"}
    [:lib/type [:= :metadata/database]]
    [:id ::lib.schema.id/database]
-   ;; TODO -- this should validate against the driver features list in [[metabase.driver/driver-features]] if we're in
+   ;; TODO -- this should validate against the driver features list in [[metabase.driver/features]] if we're in
    ;; Clj mode
    [:dbms-version {:optional true} [:maybe :map]]
    [:details      {:optional true} :map]
diff --git a/src/metabase/models/collection.clj b/src/metabase/models/collection.clj
index 9082b4f9d1b..5a565b696e2 100644
--- a/src/metabase/models/collection.clj
+++ b/src/metabase/models/collection.clj
@@ -928,11 +928,8 @@
   (let [collection (if (integer? collection-or-id)
                      (t2/select-one [Collection :id :namespace] :id (collection-or-id))
                      collection-or-id)]
-    ;; HACK Collections in the "snippets" namespace have no-op permissions unless EE enhancements are enabled
-    ;;
-    ;; TODO -- Pretty sure snippet perms should be feature flagged by `advanced-permissions` instead
     (if (and (= (u/qualified-name (:namespace collection)) "snippets")
-             (not (premium-features/enable-enhancements?)))
+             (not (premium-features/enable-snippet-collections?)))
       #{}
       ;; This is not entirely accurate as you need to be a superuser to modifiy a collection itself (e.g., changing its
       ;; name) but if you have write perms you can add/remove cards
diff --git a/src/metabase/models/dashboard.clj b/src/metabase/models/dashboard.clj
index 9dc82ef5249..1aa64c58d2a 100644
--- a/src/metabase/models/dashboard.clj
+++ b/src/metabase/models/dashboard.clj
@@ -448,7 +448,9 @@
     (let [new-param-field-ids (params/dashcards->param-field-ids (t2/hydrate new-dashcards :card))]
       (update-field-values-for-on-demand-dbs! (params/dashcards->param-field-ids old-dashcards) new-param-field-ids))))
 
+
 ;; TODO - we need to actually make this async, but then we'd need to make `save-card!` async, and so forth
+;; Issue: https://github.com/metabase/metabase/issues/39413
 (defn- result-metadata-for-query
   "Fetch the results metadata for a `query` by running the query and seeing what the `qp` gives us in return."
   [query]
diff --git a/src/metabase/models/humanization.clj b/src/metabase/models/humanization.clj
index 37db41a62f8..1c459ec2e3c 100644
--- a/src/metabase/models/humanization.clj
+++ b/src/metabase/models/humanization.clj
@@ -70,6 +70,7 @@
       (setting/set-value-of-type! :keyword :humanization-strategy new-value)
       ;; now rehumanize all the Tables and Fields using the new strategy.
       ;; TODO: Should we do this in a background thread because it is potentially slow?
+      ;; https://github.com/metabase/metabase/issues/39406
       (log/info (trs "Changing Table & Field names humanization strategy from ''{0}'' to ''{1}''"
                      (name old-strategy) (name new-strategy)))
       (re-humanize-table-and-field-names! old-strategy))))
diff --git a/src/metabase/models/login_history.clj b/src/metabase/models/login_history.clj
index 8e43d0a61b2..4fc88985d92 100644
--- a/src/metabase/models/login_history.clj
+++ b/src/metabase/models/login_history.clj
@@ -3,7 +3,7 @@
    [java-time.api :as t]
    [metabase.email.messages :as messages]
    [metabase.models.setting :refer [defsetting]]
-   [metabase.server.request.util :as request.u]
+   [metabase.server.request.util :as req.util]
    [metabase.util.date-2 :as u.date]
    [metabase.util.i18n :as i18n :refer [trs tru]]
    [metabase.util.log :as log]
@@ -28,7 +28,7 @@
   or another -- keep that in mind when using this."
   [history-items]
   (let [ip-addresses (map :ip_address history-items)
-        ip->info     (request.u/geocode-ip-addresses ip-addresses)]
+        ip->info     (req.util/geocode-ip-addresses ip-addresses)]
     (for [history-item history-items
           :let         [{location-description :description, timezone :timezone} (get ip->info (:ip_address history-item))]]
       (-> history-item
@@ -38,7 +38,7 @@
                                (if (and timestamp timezone)
                                  (t/zoned-date-time (u.date/with-time-zone-same-instant timestamp timezone) timezone)
                                  timestamp)))
-          (update :device_description request.u/describe-user-agent)))))
+          (update :device_description req.util/describe-user-agent)))))
 
 (defsetting send-email-on-first-login-from-new-device
   ;; no need to i18n -- this isn't user-facing
diff --git a/src/metabase/models/session.clj b/src/metabase/models/session.clj
index 80d0ec10aaf..230210a1e1b 100644
--- a/src/metabase/models/session.clj
+++ b/src/metabase/models/session.clj
@@ -3,7 +3,7 @@
    [buddy.core.codecs :as codecs]
    [buddy.core.nonce :as nonce]
    [metabase.server.middleware.misc :as mw.misc]
-   [metabase.server.request.util :as request.u]
+   [metabase.server.request.util :as req.util]
    [methodical.core :as methodical]
    [schema.core :as s]
    [toucan2.core :as t2]))
@@ -29,7 +29,7 @@
 (t2/define-before-insert :model/Session
   [session]
   (cond-> session
-    (some-> mw.misc/*request* request.u/embedded?) (assoc :anti_csrf_token (random-anti-csrf-token))))
+    (some-> mw.misc/*request* req.util/embedded?) (assoc :anti_csrf_token (random-anti-csrf-token))))
 
 (t2/define-after-insert :model/Session
   [{anti-csrf-token :anti_csrf_token, :as session}]
diff --git a/src/metabase/plugins/jdbc_proxy.clj b/src/metabase/plugins/jdbc_proxy.clj
index c4bc5a90d5f..194844d77d7 100644
--- a/src/metabase/plugins/jdbc_proxy.clj
+++ b/src/metabase/plugins/jdbc_proxy.clj
@@ -16,6 +16,7 @@
 ;;; -------------------------------------------------- Proxy Driver --------------------------------------------------
 
 ;; TODO -- why not use `java.sql.Wrapper` here instead of defining a new protocol that basically does the same thing?
+;; issue: https://github.com/metabase/metabase/issues/39357
 (p.types/defprotocol+ ^:private ProxyDriver
   (wrapped-driver [this]
     "Get the JDBC driver wrapped by a Metabase JDBC proxy driver."))
diff --git a/src/metabase/server/middleware/auth.clj b/src/metabase/server/middleware/auth.clj
index 5e3e60df492..a56fcf16f0b 100644
--- a/src/metabase/server/middleware/auth.clj
+++ b/src/metabase/server/middleware/auth.clj
@@ -4,7 +4,7 @@
   (:require
    [clojure.string :as str]
    [metabase.models.setting :refer [defsetting]]
-   [metabase.server.middleware.util :as mw.util]
+   [metabase.server.request.util :as req.util]
    [metabase.util.i18n :refer [deferred-trs]]))
 
 (def ^:private ^:const ^String static-metabase-api-key-header "x-metabase-apikey")
@@ -15,7 +15,7 @@
   (fn [{:keys [metabase-user-id] :as request} respond raise]
     (if metabase-user-id
       (handler request respond raise)
-      (respond mw.util/response-unauthentic))))
+      (respond req.util/response-unauthentic))))
 
 (defn- wrap-static-api-key* [{:keys [headers], :as request}]
   (if-let [api-key (headers static-metabase-api-key-header)]
@@ -64,10 +64,10 @@
           (respond key-not-set-response)
 
           (not static-metabase-api-key)
-          (respond mw.util/response-forbidden)
+          (respond req.util/response-forbidden)
 
           (= (static-api-key) static-metabase-api-key)
           (handler request respond raise)
 
           :else
-          (respond mw.util/response-forbidden))))
+          (respond req.util/response-forbidden))))
diff --git a/src/metabase/server/middleware/browser_cookie.clj b/src/metabase/server/middleware/browser_cookie.clj
index bbec17e21c0..4e61a263f77 100644
--- a/src/metabase/server/middleware/browser_cookie.clj
+++ b/src/metabase/server/middleware/browser_cookie.clj
@@ -5,7 +5,7 @@
   they log in."
   (:require
    [java-time.api :as t]
-   [metabase.server.request.util :as request.u]
+   [metabase.server.request.util :as req.util]
    [metabase.util.malli :as mu]
    [metabase.util.malli.schema :as ms]
    [ring.util.response :as response]))
@@ -25,7 +25,7 @@
           :path      "/"
           ;; Set the cookie to expire 20 years from now. That should be sufficient
           :expires   (t/format :rfc-1123-date-time (t/plus (t/zoned-date-time) (t/years 20)))}
-         (if (request.u/https? request)
+         (if (req.util/https? request)
            {:same-site :none, :secure true}
            {:same-site :lax})))
 
diff --git a/src/metabase/server/middleware/log.clj b/src/metabase/server/middleware/log.clj
index 14782e30383..0761cbc0206 100644
--- a/src/metabase/server/middleware/log.clj
+++ b/src/metabase/server/middleware/log.clj
@@ -10,7 +10,7 @@
    [metabase.driver.sql-jdbc.execute.diagnostic
     :as sql-jdbc.execute.diagnostic]
    [metabase.server :as server]
-   [metabase.server.request.util :as request.u]
+   [metabase.server.request.util :as req.util]
    [metabase.util :as u]
    [metabase.util.i18n :refer [trs]]
    [metabase.util.log :as log]
@@ -193,7 +193,7 @@
 (defn- should-log-request? [{:keys [uri], :as request}]
   ;; don't log calls to /health or /util/logs because they clutter up the logs (especially the window in admin) with
   ;; useless lines
-  (and (request.u/api-call? request)
+  (and (req.util/api-call? request)
        (not (#{"/api/util/logs"} uri))))
 
 (defn log-api-call
diff --git a/src/metabase/server/middleware/misc.clj b/src/metabase/server/middleware/misc.clj
index aba0b9bac56..0bd79f890e3 100644
--- a/src/metabase/server/middleware/misc.clj
+++ b/src/metabase/server/middleware/misc.clj
@@ -5,7 +5,7 @@
    [metabase.async.streaming-response]
    [metabase.db :as mdb]
    [metabase.public-settings :as public-settings]
-   [metabase.server.request.util :as request.u]
+   [metabase.server.request.util :as req.util]
    [metabase.util.i18n :refer [trs]]
    [metabase.util.log :as log])
   (:import
@@ -27,7 +27,7 @@
   [handler]
   (fn [request respond raise]
     (handler request
-             (if-not (request.u/api-call? request)
+             (if-not (req.util/api-call? request)
                respond
                (comp respond add-content-type*))
              raise)))
diff --git a/src/metabase/server/middleware/security.clj b/src/metabase/server/middleware/security.clj
index 9bad6121dfe..fefb48c1fa4 100644
--- a/src/metabase/server/middleware/security.clj
+++ b/src/metabase/server/middleware/security.clj
@@ -7,10 +7,8 @@
    [metabase.analytics.snowplow :as snowplow]
    [metabase.config :as config]
    [metabase.embed.settings :as embed.settings]
-   [metabase.models.setting :refer [defsetting]]
    [metabase.public-settings :as public-settings]
-   [metabase.server.request.util :as request.u]
-   [metabase.util.i18n :refer [deferred-tru]]
+   [metabase.server.request.util :as req.util]
    [ring.util.codec :refer [base64-encode]])
   (:import
    (java.security MessageDigest SecureRandom)))
@@ -82,7 +80,6 @@
                                  (when-not config/is-dev?
                                    (map (partial format "'sha256-%s'") inline-js-hashes)))
                   :child-src    ["'self'"
-                                 ;; TODO - double check that we actually need this for Google Auth
                                  "https://accounts.google.com"]
                   :style-src    ["'self'"
                                  ;; See [[generate-nonce]]
@@ -129,15 +126,6 @@
           "Content-Security-Policy"
           #(format "%s frame-ancestors %s;" % (if allow-iframes? "*" (or (embedding-app-origin) "'none'")))))
 
-(defsetting ssl-certificate-public-key
-  (deferred-tru
-    (str "Base-64 encoded public key for this site''s SSL certificate. "
-         "Specify this to enable HTTP Public Key Pinning. "
-         "See {0} for more information.")
-    "http://mzl.la/1EnfqBf")
-  :audit :getter)
-;; TODO - it would be nice if we could make this a proper link in the UI; consider enabling markdown parsing
-
 (defn- first-embedding-app-origin
   "Return only the first embedding app origin."
   []
@@ -171,8 +159,8 @@
   ;; merge is other way around so that handler can override headers
   (update response :headers #(merge %2 %1) (security-headers
                                             :nonce          (:nonce request)
-                                            :allow-iframes? ((some-fn request.u/public? request.u/embed?) request)
-                                            :allow-cache?   (request.u/cacheable? request))))
+                                            :allow-iframes? ((some-fn req.util/public? req.util/embed?) request)
+                                            :allow-cache?   (req.util/cacheable? request))))
 
 (defn add-security-headers
   "Middleware that adds HTTP security and cache-busting headers."
diff --git a/src/metabase/server/middleware/session.clj b/src/metabase/server/middleware/session.clj
index 71519f449e1..ad25d172009 100644
--- a/src/metabase/server/middleware/session.clj
+++ b/src/metabase/server/middleware/session.clj
@@ -34,7 +34,7 @@
    [metabase.models.user :as user :refer [User]]
    [metabase.public-settings :as public-settings]
    [metabase.public-settings.premium-features :as premium-features]
-   [metabase.server.request.util :as request.u]
+   [metabase.server.request.util :as req.util]
    [metabase.util :as u]
    [metabase.util.i18n :as i18n :refer [deferred-trs deferred-tru trs tru]]
    [metabase.util.log :as log]
@@ -121,18 +121,18 @@
   (merge
    {:same-site (session-cookie-samesite)
     ;; TODO - we should set `site-path` as well. Don't want to enable this yet so we don't end
-    ;; up breaking things
+    ;; up breaking things issue: https://github.com/metabase/metabase/issues/39346
     :path      "/" #_(site-path)}
    ;; If the authentication request request was made over HTTPS (hopefully always except for
    ;; local dev instances) add `Secure` attribute so the cookie is only sent over HTTPS.
-   (when (request.u/https? request)
+   (when (req.util/https? request)
      {:secure true})))
 
 (defmethod default-session-cookie-attributes :full-app-embed
   [_ request]
   (merge
    {:path "/"}
-   (when (request.u/https? request)
+   (when (req.util/https? request)
      ;; SameSite=None is required for cross-domain full-app embedding. This is safe because
      ;; security is provided via anti-CSRF token. Note that most browsers will only accept
      ;; SameSite=None with secure cookies, thus we are setting it only over HTTPS to prevent
@@ -194,7 +194,7 @@
                         ;; max-session age-is in minutes; Max-Age= directive should be in seconds
                         (when (use-permanent-cookies? request)
                           {:max-age (* 60 (config/config-int :max-session-age))}))]
-    (when (and (= (session-cookie-samesite) :none) (not (request.u/https? request)))
+    (when (and (= (session-cookie-samesite) :none) (not (req.util/https? request)))
       (log/warn
        (str (deferred-trs "Session cookie's SameSite is configured to \"None\", but site is served over an insecure connection. Some browsers will reject cookies under these conditions.")
             " "
diff --git a/src/metabase/server/middleware/ssl.clj b/src/metabase/server/middleware/ssl.clj
index 8918a32e71d..5dc942f2888 100644
--- a/src/metabase/server/middleware/ssl.clj
+++ b/src/metabase/server/middleware/ssl.clj
@@ -3,7 +3,7 @@
   (:require
    [clojure.string :as str]
    [metabase.public-settings :as public-settings]
-   [metabase.server.request.util :as request.u]
+   [metabase.server.request.util :as req.util]
    [ring.util.request :as req]
    [ring.util.response :as response]))
 
@@ -45,7 +45,7 @@
 
       (and
        (public-settings/redirect-all-requests-to-https)
-       (not (request.u/https? request)))
+       (not (req.util/https? request)))
       (respond (ssl-redirect-response request))
 
       :else (handler request respond raise))))
diff --git a/src/metabase/server/middleware/util.clj b/src/metabase/server/middleware/util.clj
deleted file mode 100644
index 803864683a6..00000000000
--- a/src/metabase/server/middleware/util.clj
+++ /dev/null
@@ -1,5 +0,0 @@
-(ns metabase.server.middleware.util
-  "Ring middleware utility functions. TODO -- consider renaming this to `metabase.server.request.util`.")
-
-(def response-unauthentic "Generic `401 (Unauthenticated)` Ring response map." {:status 401, :body "Unauthenticated"})
-(def response-forbidden   "Generic `403 (Forbidden)` Ring response map."       {:status 403, :body "Forbidden"})
diff --git a/src/metabase/server/request/util.clj b/src/metabase/server/request/util.clj
index f091da5eaa0..4b718bde906 100644
--- a/src/metabase/server/request/util.clj
+++ b/src/metabase/server/request/util.clj
@@ -149,6 +149,7 @@
     [:timezone    [:maybe (ms/InstanceOfClass ZoneId)]]]])
 
 ;; TODO -- replace with something better, like built-in database once we find one that's GPL compatible
+;; issue: https://github.com/metabase/metabase/issues/39352
 (mu/defn geocode-ip-addresses :- [:maybe IPAddress->Info]
   "Geocode multiple IP addresses, returning a map of IP address -> info, with each info map containing human-friendly
   `:description` of the location and a `java.time.ZoneId` `:timezone`, if that information is available."
@@ -169,3 +170,11 @@
          (catch Throwable e
            (log/error e (trs "Error geocoding IP addresses") {:url url})
            nil))))))
+
+(def response-unauthentic
+  "Generic `401 (Unauthenticated)` Ring response map."
+  {:status 401, :body "Unauthenticated"})
+
+(def response-forbidden
+  "Generic `403 (Forbidden)` Ring response map."
+  {:status 403, :body "Forbidden"})
diff --git a/test/metabase/api/alert_test.clj b/test/metabase/api/alert_test.clj
index 4451acfda79..1a7e3443ce6 100644
--- a/test/metabase/api/alert_test.clj
+++ b/test/metabase/api/alert_test.clj
@@ -12,7 +12,7 @@
    [metabase.models.permissions-group :as perms-group]
    [metabase.models.pulse :as pulse]
    [metabase.models.pulse-test :as pulse-test]
-   [metabase.server.middleware.util :as mw.util]
+   [metabase.server.request.util :as req.util]
    [metabase.test :as mt]
    [metabase.test.mock.util :refer [pulse-channel-defaults]]
    [metabase.util :as u]
@@ -134,10 +134,10 @@
 ;; authentication test on every single individual endpoint
 
 (deftest auth-tests
-  (is (= (get mw.util/response-unauthentic :body)
+  (is (= (get req.util/response-unauthentic :body)
          (client/client :get 401 "alert")))
 
-  (is (= (get mw.util/response-unauthentic :body)
+  (is (= (get req.util/response-unauthentic :body)
          (client/client :put 401 "alert/13"))))
 
 ;;; +----------------------------------------------------------------------------------------------------------------+
diff --git a/test/metabase/api/card_test.clj b/test/metabase/api/card_test.clj
index 8e36c213698..3f86d38c369 100644
--- a/test/metabase/api/card_test.clj
+++ b/test/metabase/api/card_test.clj
@@ -40,7 +40,7 @@
    [metabase.query-processor.card :as qp.card]
    [metabase.query-processor.compile :as qp.compile]
    [metabase.query-processor.middleware.constraints :as qp.constraints]
-   [metabase.server.middleware.util :as mw.util]
+   [metabase.server.request.util :as req.util]
    [metabase.task :as task]
    [metabase.task.persist-refresh :as task.persist-refresh]
    [metabase.task.sync-databases :as task.sync-databases]
@@ -212,8 +212,8 @@
              (card-returned? :database db      card-2))))))
 
 (deftest ^:parallel authentication-test
-  (is (= (get mw.util/response-unauthentic :body) (client/client :get 401 "card")))
-  (is (= (get mw.util/response-unauthentic :body) (client/client :put 401 "card/13"))))
+  (is (= (get req.util/response-unauthentic :body) (client/client :get 401 "card")))
+  (is (= (get req.util/response-unauthentic :body) (client/client :put 401 "card/13"))))
 
 (deftest ^:parallel model-id-requied-when-f-is-database-test
   (is (= {:errors {:model_id "model_id is a required parameter when filter mode is 'database'"}}
diff --git a/test/metabase/api/dashboard_test.clj b/test/metabase/api/dashboard_test.clj
index 89614c2b9d3..ffe115bb780 100644
--- a/test/metabase/api/dashboard_test.clj
+++ b/test/metabase/api/dashboard_test.clj
@@ -46,7 +46,7 @@
    [metabase.query-processor :as qp]
    [metabase.query-processor.middleware.permissions :as qp.perms]
    [metabase.query-processor.streaming.test-util :as streaming.test-util]
-   [metabase.server.middleware.util :as mw.util]
+   [metabase.server.request.util :as req.util]
    [metabase.test :as mt]
    [metabase.test.fixtures :as fixtures]
    [metabase.util :as u]
@@ -173,7 +173,7 @@
 ;; authentication test on every single individual endpoint
 
 (deftest auth-test
-  (is (= (get mw.util/response-unauthentic :body)
+  (is (= (get req.util/response-unauthentic :body)
          (client/client :get 401 "dashboard")
          (client/client :put 401 "dashboard/13"))))
 
diff --git a/test/metabase/api/metric_test.clj b/test/metabase/api/metric_test.clj
index 3357a9773c8..6d507db5dd7 100644
--- a/test/metabase/api/metric_test.clj
+++ b/test/metabase/api/metric_test.clj
@@ -7,7 +7,7 @@
    [metabase.models.metric :as metric :refer [Metric]]
    [metabase.models.permissions :as perms]
    [metabase.models.permissions-group :as perms-group]
-   [metabase.server.middleware.util :as mw.util]
+   [metabase.server.request.util :as req.util]
    [metabase.test :as mt]
    [metabase.util :as u]
    [toucan2.core :as t2]
@@ -44,10 +44,10 @@
   (testing "AUTHENTICATION"
     ;; We assume that all endpoints for a given context are enforced by the same middleware, so we don't run the same
     ;; authentication test on every single individual endpoint
-    (is (= (get mw.util/response-unauthentic :body)
+    (is (= (get req.util/response-unauthentic :body)
            (client/client :get 401 "metric")))
 
-    (is (= (get mw.util/response-unauthentic :body)
+    (is (= (get req.util/response-unauthentic :body)
            (client/client :put 401 "metric/13")))))
 
 (deftest create-test
diff --git a/test/metabase/api/notify_test.clj b/test/metabase/api/notify_test.clj
index 478ef4f2cd3..ec8ba7c6f04 100644
--- a/test/metabase/api/notify_test.clj
+++ b/test/metabase/api/notify_test.clj
@@ -8,7 +8,7 @@
    [metabase.http-client :as client]
    [metabase.models.database :as database :refer [Database]]
    [metabase.server.middleware.auth :as mw.auth]
-   [metabase.server.middleware.util :as mw.util]
+   [metabase.server.request.util :as req.util]
    [metabase.sync :as sync]
    [metabase.sync.sync-metadata]
    [metabase.test :as mt]
@@ -26,7 +26,7 @@
                (client/client :post 403 "notify/db/100")))))
     (testing "endpoint requires authentication"
       (mt/with-temporary-setting-values [api-key "test-api-key"] ;; set in :test but not in :dev
-        (is (= (get mw.util/response-forbidden :body)
+        (is (= (get req.util/response-forbidden :body)
                (client/client :post 403 "notify/db/100")))))))
 
 (def ^:private api-headers {:headers {"x-metabase-apikey" "test-api-key"
diff --git a/test/metabase/api/pulse_test.clj b/test/metabase/api/pulse_test.clj
index 7bf73342abf..ecf49c0af9f 100644
--- a/test/metabase/api/pulse_test.clj
+++ b/test/metabase/api/pulse_test.clj
@@ -21,7 +21,7 @@
    [metabase.models.pulse-channel :as pulse-channel]
    [metabase.models.pulse-test :as pulse-test]
    [metabase.pulse.render.style :as style]
-   [metabase.server.middleware.util :as mw.util]
+   [metabase.server.request.util :as req.util]
    [metabase.test :as mt]
    [metabase.test.mock.util :refer [pulse-channel-defaults]]
    [metabase.util :as u]
@@ -99,8 +99,8 @@
 ;; authentication test on every single individual endpoint
 
 (deftest authentication-test
-  (is (= (:body mw.util/response-unauthentic) (client/client :get 401 "pulse")))
-  (is (= (:body mw.util/response-unauthentic) (client/client :put 401 "pulse/13"))))
+  (is (= (:body req.util/response-unauthentic) (client/client :get 401 "pulse")))
+  (is (= (:body req.util/response-unauthentic) (client/client :put 401 "pulse/13"))))
 
 
 ;;; +----------------------------------------------------------------------------------------------------------------+
diff --git a/test/metabase/api/segment_test.clj b/test/metabase/api/segment_test.clj
index 746d968d426..847d1cbe6ba 100644
--- a/test/metabase/api/segment_test.clj
+++ b/test/metabase/api/segment_test.clj
@@ -7,7 +7,7 @@
    [metabase.models.permissions :as perms]
    [metabase.models.permissions-group :as perms-group]
    [metabase.models.segment :as segment :refer [Segment]]
-   [metabase.server.middleware.util :as mw.util]
+   [metabase.server.request.util :as req.util]
    [metabase.test :as mt]
    [metabase.util :as u]
    [toucan2.core :as t2]
@@ -33,10 +33,10 @@
 ;; authentication test on every single individual endpoint
 
 (deftest authentication-test
-  (is (= (get mw.util/response-unauthentic :body)
+  (is (= (get req.util/response-unauthentic :body)
          (client/client :get 401 "segment")))
 
-  (is (= (get mw.util/response-unauthentic :body)
+  (is (= (get req.util/response-unauthentic :body)
          (client/client :put 401 "segment/13"))))
 
 ;; ## POST /api/segment
diff --git a/test/metabase/api/table_test.clj b/test/metabase/api/table_test.clj
index 1daa635f4fe..119e83ecbe3 100644
--- a/test/metabase/api/table_test.clj
+++ b/test/metabase/api/table_test.clj
@@ -12,7 +12,7 @@
    [metabase.models.permissions :as perms]
    [metabase.models.permissions-group :as perms-group]
    [metabase.models.table :as table]
-   [metabase.server.middleware.util :as mw.util]
+   [metabase.server.request.util :as req.util]
    [metabase.test :as mt]
    [metabase.timeseries-query-processor-test.util :as tqpt]
    [metabase.upload-test :as upload-test]
@@ -27,9 +27,9 @@
 ;; authentication test on every single individual endpoint
 
 (deftest unauthenticated-test
-  (is (= (get mw.util/response-unauthentic :body)
+  (is (= (get req.util/response-unauthentic :body)
          (client/client :get 401 "table")))
-  (is (= (get mw.util/response-unauthentic :body)
+  (is (= (get req.util/response-unauthentic :body)
          (client/client :get 401 (format "table/%d" (mt/id :users))))))
 
 (defn- db-details []
diff --git a/test/metabase/api/timeline_event_test.clj b/test/metabase/api/timeline_event_test.clj
index d7c72d6f784..dbc3e8480ad 100644
--- a/test/metabase/api/timeline_event_test.clj
+++ b/test/metabase/api/timeline_event_test.clj
@@ -6,7 +6,7 @@
    [metabase.models.collection :refer [Collection]]
    [metabase.models.timeline :refer [Timeline]]
    [metabase.models.timeline-event :refer [TimelineEvent]]
-   [metabase.server.middleware.util :as mw.util]
+   [metabase.server.request.util :as req.util]
    [metabase.test :as mt]
    [metabase.util :as u]
    [toucan2.core :as t2]))
@@ -15,9 +15,9 @@
 
 (deftest auth-tests
   (testing "Authentication"
-    (is (= (get mw.util/response-unauthentic :body)
+    (is (= (get req.util/response-unauthentic :body)
            (client/client :get 401 "/timeline-event")))
-    (is (= (get mw.util/response-unauthentic :body)
+    (is (= (get req.util/response-unauthentic :body)
            (client/client :get 401 "/timeline-event/1")))))
 
 (deftest get-timeline-event-test
diff --git a/test/metabase/api/timeline_test.clj b/test/metabase/api/timeline_test.clj
index 1ca06466d4f..87c43757bba 100644
--- a/test/metabase/api/timeline_test.clj
+++ b/test/metabase/api/timeline_test.clj
@@ -9,7 +9,7 @@
    [metabase.models.permissions-group :as perms-group]
    [metabase.models.timeline :refer [Timeline]]
    [metabase.models.timeline-event :refer [TimelineEvent]]
-   [metabase.server.middleware.util :as mw.util]
+   [metabase.server.request.util :as req.util]
    [metabase.test :as mt]
    [metabase.util :as u]
    [toucan2.core :as t2]
@@ -17,9 +17,9 @@
 
 (deftest auth-tests
   (testing "Authentication"
-    (is (= (get mw.util/response-unauthentic :body)
+    (is (= (get req.util/response-unauthentic :body)
            (client/client :get 401 "/timeline")))
-    (is (= (get mw.util/response-unauthentic :body)
+    (is (= (get req.util/response-unauthentic :body)
            (client/client :get 401 "/timeline/1")))))
 
 (deftest list-timelines-test
diff --git a/test/metabase/api/user_test.clj b/test/metabase/api/user_test.clj
index 7ff49347b20..0cb481397f1 100644
--- a/test/metabase/api/user_test.clj
+++ b/test/metabase/api/user_test.clj
@@ -14,7 +14,7 @@
    [metabase.models.user :as user]
    [metabase.models.user-test :as user-test]
    [metabase.public-settings.premium-features :as premium-features]
-   [metabase.server.middleware.util :as mw.util]
+   [metabase.server.request.util :as req.util]
    [metabase.test :as mt]
    [metabase.test.fixtures :as fixtures]
    [metabase.util :as u]
@@ -54,10 +54,10 @@
 (deftest user-list-authentication-test
   (testing "authentication"
     (testing "GET /api/user"
-      (is (= (get mw.util/response-unauthentic :body)
+      (is (= (get req.util/response-unauthentic :body)
              (client/client :get 401 "user"))))
     (testing "GET /api/user/current"
-      (is (= (get mw.util/response-unauthentic :body)
+      (is (= (get req.util/response-unauthentic :body)
              (client/client :get 401 "user/current"))))))
 
 (deftest user-list-test
diff --git a/test/metabase/models/login_history_test.clj b/test/metabase/models/login_history_test.clj
index 7468833ce85..16acbc1d973 100644
--- a/test/metabase/models/login_history_test.clj
+++ b/test/metabase/models/login_history_test.clj
@@ -6,7 +6,7 @@
    [metabase.models :refer [LoginHistory User]]
    [metabase.models.login-history :as login-history]
    [metabase.public-settings :as public-settings]
-   [metabase.server.request.util :as request.u]
+   [metabase.server.request.util :as req.util]
    [metabase.test :as mt]
    [metabase.util :as u]
    [metabase.util.date-2 :as u.date]
@@ -48,7 +48,7 @@
             (mt/with-fake-inbox
               ;; mock out the IP address geocoding function so we can make sure it handles timezones like PST correctly
               ;; (#15603)
-              (with-redefs [request.u/geocode-ip-addresses (fn [ip-addresses]
+              (with-redefs [req.util/geocode-ip-addresses (fn [ip-addresses]
                                                              (into {} (for [ip-address ip-addresses]
                                                                         [ip-address
                                                                          {:description "San Francisco, California, United States"
diff --git a/test/metabase/query_processor/test_util.clj b/test/metabase/query_processor/test_util.clj
index cd169b2527a..5d8c9818072 100644
--- a/test/metabase/query_processor/test_util.clj
+++ b/test/metabase/query_processor/test_util.clj
@@ -63,7 +63,7 @@
                           (every? #(driver/database-supports? driver % db) features)))]
            driver))))
 
-(alter-meta! #'normal-drivers-with-feature assoc :arglists (list (into ['&] (sort driver/driver-features))))
+(alter-meta! #'normal-drivers-with-feature assoc :arglists (list (into ['&] (sort driver/features))))
 
 (defn normal-drivers-without-feature
   "Return a set of all non-timeseries engines (e.g., everything except Druid and Google Analytics) that DO NOT support
@@ -71,7 +71,7 @@
   [feature]
   (set/difference (normal-drivers) (normal-drivers-with-feature feature)))
 
-(alter-meta! #'normal-drivers-without-feature assoc :arglists (list (into ['&] (sort driver/driver-features))))
+(alter-meta! #'normal-drivers-without-feature assoc :arglists (list (into ['&] (sort driver/features))))
 
 (defn normal-drivers-except
   "Return the set of all drivers except Druid, Google Analytics, and those in `excluded-drivers`."
diff --git a/test/metabase/server/middleware/auth_test.clj b/test/metabase/server/middleware/auth_test.clj
index a5caaae147e..42709fcd786 100644
--- a/test/metabase/server/middleware/auth_test.clj
+++ b/test/metabase/server/middleware/auth_test.clj
@@ -5,7 +5,7 @@
    [metabase.models.session :refer [Session]]
    [metabase.server.middleware.auth :as mw.auth]
    [metabase.server.middleware.session :as mw.session]
-   [metabase.server.middleware.util :as mw.util]
+   [metabase.server.request.util :as req.util]
    [metabase.test :as mt]
    [metabase.test.data.users :as test.users]
    [metabase.test.fixtures :as fixtures]
@@ -49,7 +49,7 @@
 
   (testing "Invalid requests should return unauthed response"
     (testing "when no session ID is sent with request"
-      (is (= mw.util/response-unauthentic
+      (is (= req.util/response-unauthentic
              (auth-enforced-handler
               (ring.mock/request :get "/anyurl")))))
 
@@ -62,7 +62,7 @@
                                :user_id (test.users/user->id :rasta)})
           (t2/update! (t2/table-name Session) {:id session-id}
             {:created_at (t/instant 1000)})
-          (is (= mw.util/response-unauthentic
+          (is (= req.util/response-unauthentic
                  (auth-enforced-handler (request-with-session-id session-id))))
           (finally (t2/delete! Session :id session-id)))))
 
@@ -74,7 +74,7 @@
         (try
           (t2/insert! Session {:id      session-id
                                :user_id (test.users/user->id :trashbird)})
-          (is (= mw.util/response-unauthentic
+          (is (= req.util/response-unauthentic
                  (auth-enforced-handler
                   (request-with-session-id session-id))))
           (finally (t2/delete! Session :id session-id)))))))
@@ -123,7 +123,7 @@
 (deftest enforce-static-api-key-request
   (mt/with-temporary-setting-values [api-key "test-api-key"]
     (testing "no apikey in the request, expect 403"
-      (is (= mw.util/response-forbidden
+      (is (= req.util/response-forbidden
              (api-key-enforced-handler
               (ring.mock/request :get "/anyurl")))))
 
@@ -133,7 +133,7 @@
               (request-with-api-key "test-api-key")))))
 
     (testing "invalid apikey, expect 403"
-      (is (= mw.util/response-forbidden
+      (is (= req.util/response-forbidden
              (api-key-enforced-handler
               (request-with-api-key "foobar"))))))
 
diff --git a/test/metabase/server/request/util_test.clj b/test/metabase/server/request/util_test.clj
index 1bab8a9e9a4..d17a6aff02b 100644
--- a/test/metabase/server/request/util_test.clj
+++ b/test/metabase/server/request/util_test.clj
@@ -3,7 +3,7 @@
    [clojure.test :refer :all]
    [clojure.tools.reader.edn :as edn]
    [java-time.api :as t]
-   [metabase.server.request.util :as request.u]
+   [metabase.server.request.util :as req.util]
    [metabase.test :as mt]
    [ring.mock.request :as ring.mock]))
 
@@ -22,7 +22,7 @@
                               {"origin" "http://mysite.com"}   false}]
     (testing (pr-str (list 'https? {:headers headers}))
       (is (= expected
-             (request.u/https? {:headers headers}))))))
+             (req.util/https? {:headers headers}))))))
 
 (def ^:private mock-request
   (delay (edn/read-string (slurp "test/metabase/server/request/sample-request.edn"))))
@@ -31,10 +31,10 @@
   (is (= {:device_id          "129d39d1-6758-4d2c-a751-35b860007002"
           :device_description "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.72 Safari/537.36"
           :ip_address         "0:0:0:0:0:0:0:1"}
-         (request.u/device-info @mock-request))))
+         (req.util/device-info @mock-request))))
 
 (deftest ^:parallel describe-user-agent-test
-  (are [user-agent expected] (= expected (request.u/describe-user-agent user-agent))
+  (are [user-agent expected] (= expected (req.util/describe-user-agent user-agent))
     "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML  like Gecko) Chrome/89.0.4389.86 Safari/537.36"
     "Browser (Chrome/Windows)"
 
@@ -57,27 +57,27 @@
   (let [request (ring.mock/request :get "api/session")]
     (testing "request with no forwarding"
       (is (= "127.0.0.1"
-             (request.u/ip-address request))))
+             (req.util/ip-address request))))
     (testing "request with forwarding"
       (let [mock-request (-> (ring.mock/request :get "api/session")
                              (ring.mock/header "X-Forwarded-For" "5.6.7.8"))]
         (is (= "5.6.7.8"
-               (request.u/ip-address mock-request))))
+               (req.util/ip-address mock-request))))
       (testing "multiple IP addresses"
         (let [mock-request (-> (ring.mock/request :get "api/session")
                                (ring.mock/header "X-Forwarded-For" "1.2.3.4, 5.6.7.8"))]
           (is (= "1.2.3.4"
-                 (request.u/ip-address mock-request)))))
+                 (req.util/ip-address mock-request)))))
       (testing "different header than default X-Forwarded-For"
         (mt/with-temporary-setting-values [source-address-header "X-ProxyUser-Ip"]
           (let [mock-request (-> (ring.mock/request :get "api/session")
                                  (ring.mock/header "x-proxyuser-ip" "1.2.3.4"))]
             (is (= "1.2.3.4"
-                   (request.u/ip-address mock-request)))))))))
+                   (req.util/ip-address mock-request)))))))))
 
 (deftest ^:parallel geocode-ip-addresses-test
   (are [ip-addresses expected] (malli= [:maybe expected]
-                                       (request.u/geocode-ip-addresses ip-addresses))
+                                       (req.util/geocode-ip-addresses ip-addresses))
     ;; Google DNS
     ["8.8.8.8"]
     [:map
-- 
GitLab