From c29951e0fa551968ef006d838f616964f26b87e1 Mon Sep 17 00:00:00 2001 From: adam-james <21064735+adam-james-v@users.noreply.github.com> Date: Thu, 24 Mar 2022 13:08:31 -0700 Subject: [PATCH] Hydrate Collections on Timelines for card/collection endpoints (#21227) * Hydrate Collections on Timelines for card/collection endpoints * Add tests to check that collection is hydrated * Add missing docstring --- src/metabase/api/timeline.clj | 16 ++-------------- src/metabase/models/timeline.clj | 20 ++++++++++++++++++-- test/metabase/api/card_test.clj | 5 +++++ test/metabase/api/collection_test.clj | 5 +++++ 4 files changed, 30 insertions(+), 16 deletions(-) diff --git a/src/metabase/api/timeline.clj b/src/metabase/api/timeline.clj index 591a3ac3298..e98d88fb530 100644 --- a/src/metabase/api/timeline.clj +++ b/src/metabase/api/timeline.clj @@ -32,25 +32,13 @@ {:icon timeline/DefaultIcon}))] (db/insert! Timeline tl))) -;; todo: should this fn move into `metabase.model.collection`? -;; a nearly identical fn exists in `metabase.api.collection` -(defn- root-collection - [] - (-> (collection/root-collection-with-ui-details nil) - collection/personal-collection-with-ui-details - (hydrate :parent_id :effective_location [:effective_ancestors :can_write] :can_write))) - (api/defendpoint GET "/" "Fetch a list of [[Timelines]]. Can include `archived=true` to return archived timelines." [include archived] {include (s/maybe Include) archived (s/maybe su/BooleanString)} (let [archived? (Boolean/parseBoolean archived) - hydrate-root-collection (fn [tl] - (if (nil? (:collection_id tl)) - (assoc tl :collection (root-collection)) - tl)) - timelines (map hydrate-root-collection (db/select Timeline [:where [:= :archived archived?]]))] + timelines (map timeline/hydrate-root-collection (db/select Timeline [:where [:= :archived archived?]]))] (cond->> (hydrate timelines :creator :collection) (= include "events") (map #(timeline-event/include-events-singular % {:events/all? archived?}))))) @@ -69,7 +57,7 @@ ;; `collection_id` `nil` means we need to assoc 'root' collection ;; because hydrate `:collection` needs a proper `:id` to work. (nil? (:collection_id timeline)) - (assoc :collection (root-collection)) + timeline/hydrate-root-collection (= include "events") (timeline-event/include-events-singular {:events/all? archived? diff --git a/src/metabase/models/timeline.clj b/src/metabase/models/timeline.clj index 9b86314c669..57c5a5a41c6 100644 --- a/src/metabase/models/timeline.clj +++ b/src/metabase/models/timeline.clj @@ -1,5 +1,6 @@ (ns metabase.models.timeline - (:require [metabase.models.interface :as i] + (:require [metabase.models.collection :as collection] + [metabase.models.interface :as i] [metabase.models.permissions :as perms] [metabase.models.timeline-event :as timeline-event] [metabase.util :as u] @@ -22,6 +23,19 @@ ;;;; functions +(defn- root-collection + [] + (-> (collection/root-collection-with-ui-details nil) + collection/personal-collection-with-ui-details + (hydrate :parent_id :effective_location [:effective_ancestors :can_write] :can_write))) + +(defn hydrate-root-collection + "Hydrate `:collection` on [[Timelines]] when the id is `nil`." + [{:keys [collection_id] :as timeline}] + (if (nil? collection_id) + (assoc timeline :collection (root-collection)) + timeline)) + (defn timelines-for-collection "Load timelines based on `collection-id` passed in (nil means the root collection). Hydrates the events on each timeline at `:events` on the timeline." @@ -29,7 +43,9 @@ (cond-> (hydrate (db/select Timeline :collection_id collection-id :archived (boolean archived?)) - :creator) + :creator + :collection) + (nil? collection-id) (->> (map hydrate-root-collection)) events? (timeline-event/include-events options))) (u/strict-extend (class Timeline) diff --git a/test/metabase/api/card_test.clj b/test/metabase/api/card_test.clj index 57be4235ad6..03347ec4e4a 100644 --- a/test/metabase/api/card_test.clj +++ b/test/metabase/api/card_test.clj @@ -1280,6 +1280,11 @@ (testing "Timelines in the collection of the card are returned" (is (= #{"Timeline A"} (timeline-names (timelines-request card-a false))))) + (testing "Timelines in the collection have a hydrated `:collection` key" + (is (= #{(u/the-id coll-a)} + (->> (timelines-request card-a false) + (map #(get-in % [:collection :id])) + set)))) (testing "Only un-archived timelines in the collection of the card are returned" (is (= #{"Timeline B"} (timeline-names (timelines-request card-b false))))) diff --git a/test/metabase/api/collection_test.clj b/test/metabase/api/collection_test.clj index 24c4654b52e..a7e570572f1 100644 --- a/test/metabase/api/collection_test.clj +++ b/test/metabase/api/collection_test.clj @@ -1481,6 +1481,11 @@ (testing "Timelines in the collection of the card are returned" (is (= #{"Timeline A"} (timeline-names (timelines-request coll-a false))))) + (testing "Timelines in the collection have a hydrated `:collection` key" + (is (= #{(u/the-id coll-a)} + (->> (timelines-request coll-a false) + (map #(get-in % [:collection :id])) + set)))) (testing "Only un-archived timelines in the collection of the card are returned" (is (= #{"Timeline B"} (timeline-names (timelines-request coll-b false))))) -- GitLab