From 5b64eafbea3caa44dc100c86a622c8c5988110e2 Mon Sep 17 00:00:00 2001
From: bryan <bryan.maass@gmail.com>
Date: Tue, 30 May 2023 15:29:34 -0600
Subject: [PATCH] Add type column to collections + hydrate dashboards and cards
 with it (#30994)

* add migration for typed collections

* add hydration of collections to card+dashboard api

- adds it for:
  - GET /api/question/:id
  - GET /api/dashboard/:id

* fix test that checks for collection shape

* get tests working with hydrated collection

* typo fixes

* fix more tests

- PUT requests don't hydrate :collection

* update tests to fix param_values {} vs nil inconsistencies
---
 .../src/metabase_enterprise/audit_db.clj      |  2 +-
 resources/migrations/000_migrations.yaml      | 14 +++++++++++
 src/metabase/api/card.clj                     |  3 ++-
 src/metabase/api/dashboard.clj                | 13 +++++++++--
 src/metabase/models/collection.clj            |  2 +-
 test/metabase/api/collection_test.clj         |  3 ++-
 test/metabase/api/dashboard_test.clj          | 23 +++++++++++++++----
 test/metabase/models/collection_test.clj      |  2 +-
 8 files changed, 51 insertions(+), 11 deletions(-)

diff --git a/enterprise/backend/src/metabase_enterprise/audit_db.clj b/enterprise/backend/src/metabase_enterprise/audit_db.clj
index 9a56c282eb7..2a2a5d6d575 100644
--- a/enterprise/backend/src/metabase_enterprise/audit_db.clj
+++ b/enterprise/backend/src/metabase_enterprise/audit_db.clj
@@ -21,7 +21,7 @@
    (if (t2/select-one Database :id id)
      (install-database! engine (inc id))
      (do
-       ;; guard against someone manually deletihng the audit-db entry, but not removing the audit-db permissions.
+       ;; guard against someone manually deleting the audit-db entry, but not removing the audit-db permissions.
        (t2/delete! :permissions {:where [:like :object (str "%/db/" id "/%")]})
        (t2/insert! Database {:is_audit         true
                              :id               default-audit-db-id
diff --git a/resources/migrations/000_migrations.yaml b/resources/migrations/000_migrations.yaml
index a82d5c413da..28b79cb3e84 100644
--- a/resources/migrations/000_migrations.yaml
+++ b/resources/migrations/000_migrations.yaml
@@ -14798,6 +14798,20 @@ databaseChangeLog:
         - customChange:
             class: "metabase.db.custom_migrations.DowngradeDashboardTab"
 
+  - changeSet:
+      id: v47.00-030
+      author: escherize
+      comment: Added 0.47.0 - Type column for collections for instance-analytics
+      changes:
+        - addColumn:
+            tableName: collection
+            columns:
+              - column:
+                  name: type
+                  type: varchar(256)
+                  defaultValue: null
+                  remarks: 'This is used to differentiate instance-analytics collections from all other collections.'
+
   # >>>>>>>>>> DO NOT ADD NEW MIGRATIONS BELOW THIS LINE! ADD THEM ABOVE <<<<<<<<<<
 
 ########################################################################################################################
diff --git a/src/metabase/api/card.clj b/src/metabase/api/card.clj
index f8e24279052..805a6b4f24b 100644
--- a/src/metabase/api/card.clj
+++ b/src/metabase/api/card.clj
@@ -192,7 +192,8 @@
                           :can_write
                           :average_query_time
                           :last_query_start
-                          :collection [:moderation_reviews :moderator_details])
+                          :collection
+                          [:moderation_reviews :moderator_details])
                  (cond-> ;; card
                    (:dataset raw-card) (hydrate :persisted))
                  api/read-check
diff --git a/src/metabase/api/dashboard.clj b/src/metabase/api/dashboard.clj
index bc5dca62cda..d8a4d7ac974 100644
--- a/src/metabase/api/dashboard.clj
+++ b/src/metabase/api/dashboard.clj
@@ -217,8 +217,17 @@
       ;; i'm a bit worried that this is an n+1 situation here. The cards can be batch hydrated i think because they
       ;; have a hydration key and an id. moderation_reviews currently aren't batch hydrated but i'm worried they
       ;; cannot be in this situation
-      (hydrate [:ordered_cards [:card [:moderation_reviews :moderator_details]] :series :dashcard/action :dashcard/linkcard-info]
-               :ordered_tabs :collection_authority_level :can_write :param_fields :param_values)
+      (hydrate [:ordered_cards
+                [:card [:moderation_reviews :moderator_details]]
+                :series
+                :dashcard/action
+                :dashcard/linkcard-info]
+               :ordered_tabs
+               :collection_authority_level
+               :can_write
+               :param_fields
+               :param_values
+               :collection)
       api/read-check
       api/check-not-archived
       hide-unreadable-cards
diff --git a/src/metabase/models/collection.clj b/src/metabase/models/collection.clj
index ed9f1b0face..c556c48b8ab 100644
--- a/src/metabase/models/collection.clj
+++ b/src/metabase/models/collection.clj
@@ -1181,7 +1181,7 @@
                                :allowed-namespaces   allowed-namespaces
                                :collection-namespace collection-namespace})))))))
 
-(defn annotate-collections
+(defn- annotate-collections
   "Annotate collections with `:below` and `:here` keys to indicate which types are in their subtree and which types are
   in the collection at that level."
   [{:keys [dataset card] :as _coll-type-ids} collections]
diff --git a/test/metabase/api/collection_test.clj b/test/metabase/api/collection_test.clj
index 1aad6e168bc..8e6467cb610 100644
--- a/test/metabase/api/collection_test.clj
+++ b/test/metabase/api/collection_test.clj
@@ -1450,7 +1450,8 @@
                         :location          (s/eq "/")
                         :entity_id         (s/maybe su/NanoIdString)
                         :namespace         (s/eq nil)
-                        :created_at        java.time.temporal.Temporal}
+                        :created_at        java.time.temporal.Temporal
+                        :type              (s/maybe s/Str)}
                        (mt/user-http-request :crowberto :post 200 "collection"
                                              {:name "foo", :color "#f38630", :authority_level "official"})))
           (testing "But they have to be valid types"
diff --git a/test/metabase/api/dashboard_test.clj b/test/metabase/api/dashboard_test.clj
index 712d647e02f..58c7e9324d1 100644
--- a/test/metabase/api/dashboard_test.clj
+++ b/test/metabase/api/dashboard_test.clj
@@ -89,7 +89,8 @@
              :updated_at (boolean updated_at)
              :card       (-> (into {} card)
                              (dissoc :id :database_id :table_id :created_at :updated_at :query_average_duration)
-                             (update :collection_id boolean)))))
+                             (update :collection_id boolean)
+                             (update :collection boolean)))))
 
 (defn- dashboard-response [{:keys [creator ordered_cards created_at updated_at] :as dashboard}]
   ;; todo: should be udpated to use mt/boolean-ids-and-timestamps
@@ -98,7 +99,11 @@
                  (assoc :created_at (boolean created_at)
                         :updated_at (boolean updated_at))
                  (update :entity_id boolean)
-                 (update :collection_id boolean))]
+                 (update :collection_id boolean)
+                 (update :collection boolean)
+                 (cond->
+                   (:param_values dashboard)
+                   (update :param_values not-empty)))]
     (cond-> dash
       (contains? dash :last-edit-info)
       (update :last-edit-info (fn [info]
@@ -155,6 +160,7 @@
    :caveats                 nil
    :collection_id           nil
    :collection_position     nil
+   :collection              true
    :created_at              true ; assuming you call dashboard-response on the results
    :description             nil
    :embedding_params        nil
@@ -185,6 +191,7 @@
                      :updated_at     true
                      :created_at     true
                      :collection_id  true
+                     :collection     false
                      :cache_ttl      1234
                      :last-edit-info {:timestamp true :id true :first_name "Rasta"
                                       :last_name "Toucan" :email "rasta@metabase.com"}})
@@ -302,6 +309,7 @@
                      dashboard-defaults
                      {:name                       "Test Dashboard"
                       :creator_id                 (mt/user->id :rasta)
+                      :collection                 true
                       :collection_id              true
                       :collection_authority_level nil
                       :can_write                  false
@@ -389,7 +397,7 @@
                            :collection_id              true
                            :collection_authority_level nil
                            :can_write                  false
-                           :param_values  nil
+                           :param_values               nil
                            :param_fields               {field-id {:id               field-id
                                                                   :table_id         table-id
                                                                   :display_name     display-name
@@ -416,6 +424,7 @@
                                                                                             {:name                   "Dashboard Test Card"
                                                                                              :creator_id             (mt/user->id :rasta)
                                                                                              :collection_id          true
+                                                                                             :collection             false
                                                                                              :entity_id              (:entity_id card)
                                                                                              :display                "table"
                                                                                              :query_type             nil
@@ -495,6 +504,7 @@
         (testing "GET before update"
           (is (= (merge dashboard-defaults {:name          "Test Dashboard"
                                             :creator_id    (mt/user->id :rasta)
+                                            :collection    false
                                             :collection_id true})
                  (dashboard-response (t2/select-one Dashboard :id dashboard-id)))))
 
@@ -505,6 +515,7 @@
                                             :cache_ttl      1234
                                             :last-edit-info {:timestamp true     :id    true :first_name "Rasta"
                                                              :last_name "Toucan" :email "rasta@metabase.com"}
+                                            :collection     false
                                             :collection_id  true})
                  (dashboard-response
                   (mt/user-http-request :rasta :put 200 (str "dashboard/" dashboard-id)
@@ -519,6 +530,7 @@
                                             :description   "Some awesome description"
                                             :cache_ttl     1234
                                             :creator_id    (mt/user->id :rasta)
+                                            :collection    false
                                             :collection_id true})
                  (dashboard-response (t2/select-one Dashboard :id dashboard-id)))))
 
@@ -556,6 +568,7 @@
         (with-dashboards-in-writeable-collection [dashboard-id]
           (is (= (merge dashboard-defaults {:name                    "Test Dashboard"
                                             :creator_id              (mt/user->id :rasta)
+                                            :collection              false
                                             :collection_id           true
                                             :caveats                 ""
                                             :points_of_interest      ""
@@ -826,6 +839,7 @@
                      {:name          "Test Dashboard"
                       :description   "A description"
                       :creator_id    (mt/user->id :rasta)
+                      :collection    false
                       :collection_id false})
                    (dashboard-response response)))
             (is (some? (:entity_id response)))
@@ -846,7 +860,8 @@
                      {:name          "Test Dashboard - Duplicate"
                       :description   "A new description"
                       :creator_id    (mt/user->id :crowberto)
-                      :collection_id false})
+                      :collection_id false
+                      :collection    false})
                    (dashboard-response response)))
             (is (some? (:entity_id response)))
             (is (not= (:entity_id dashboard) (:entity_id response))
diff --git a/test/metabase/models/collection_test.clj b/test/metabase/models/collection_test.clj
index 82d393fa643..5b749d9257e 100644
--- a/test/metabase/models/collection_test.clj
+++ b/test/metabase/models/collection_test.clj
@@ -1617,7 +1617,7 @@
             {:id 3 :name "c" :location "/1/2/"   :here #{:dataset} :below #{:dataset}}
             {:id 4 :name "d" :location "/1/2/3/" :here #{:dataset}}
             {:id 5 :name "e" :location "/1/"     :here #{:card}}]
-           (collection/annotate-collections {:card #{1 5} :dataset #{3 4}} collections)))
+           (#'collection/annotate-collections {:card #{1 5} :dataset #{3 4}} collections)))
     (is (= [{:id 1 :here #{:card} :below #{:card :dataset}
              :children
              [{:id 2 :below #{:dataset}
-- 
GitLab