From 145ecc6cbb98ed63f6e3a84f65d44ffeede2845d Mon Sep 17 00:00:00 2001
From: Noah Moss <32746338+noahmoss@users.noreply.github.com>
Date: Fri, 29 Oct 2021 14:33:58 -0400
Subject: [PATCH] Skip sending dashboard subscription if dashboard is archived
 (#18712)

---
 src/metabase/models/pulse.clj                 | 11 +++++--
 src/metabase/pulse.clj                        | 31 ++++++++++---------
 test/metabase/api/pulse_test.clj              |  7 ++++-
 test/metabase/dashboard_subscription_test.clj | 26 ++++++++++++----
 4 files changed, 50 insertions(+), 25 deletions(-)

diff --git a/src/metabase/models/pulse.clj b/src/metabase/models/pulse.clj
index 1381ca9d3f8..bd424fe7303 100644
--- a/src/metabase/models/pulse.clj
+++ b/src/metabase/models/pulse.clj
@@ -309,12 +309,17 @@
   (let [query {:select    [:p.* [:%lower.p.name :lower-name]]
                :modifiers [:distinct]
                :from      [[Pulse :p]]
-               :left-join (when user-id
-                            [[PulseChannel :pchan] [:= :p.id :pchan.pulse_id]
-                             [PulseChannelRecipient :pcr] [:= :pchan.id :pcr.pulse_channel_id]])
+               :left-join (concat
+                           [[:report_dashboard :d] [:= :p.dashboard_id :d.id]]
+                           (when user-id
+                             [[PulseChannel :pchan] [:= :p.id :pchan.pulse_id]
+                              [PulseChannelRecipient :pcr] [:= :pchan.id :pcr.pulse_channel_id]]))
                :where     [:and
                            [:= :p.alert_condition nil]
                            [:= :p.archived archived?]
+                           [:or
+                            [:= :p.dashboard_id nil]
+                            [:= :d.archived false]]
                            (when dashboard-id
                              [:= :p.dashboard_id dashboard-id])
                            (when user-id
diff --git a/src/metabase/pulse.clj b/src/metabase/pulse.clj
index bf8c095f1bc..852779630ef 100644
--- a/src/metabase/pulse.clj
+++ b/src/metabase/pulse.clj
@@ -96,11 +96,10 @@
     (compare (:row dashcard-1) (:row dashcard-2))
     (compare (:col dashcard-1) (:col dashcard-2))))
 
-(defn execute-dashboard
+(defn- execute-dashboard
   "Fetch all the dashcards in a dashboard for a Pulse, and execute non-text cards"
-  [{pulse-creator-id :creator_id, :as pulse} dashboard-or-id & {:as options}]
-  (let [dashboard-id      (u/the-id dashboard-or-id)
-        dashboard         (Dashboard :id dashboard-id)
+  [{pulse-creator-id :creator_id, :as pulse} dashboard & {:as options}]
+  (let [dashboard-id      (u/the-id dashboard)
         dashcards         (db/select DashboardCard :dashboard_id dashboard-id)
         ordered-dashcards (sort dashcard-comparator dashcards)]
     (for [dashcard ordered-dashcards]
@@ -367,11 +366,11 @@
 
 (defn- pulse->notifications
   "Execute the underlying queries for a sequence of Pulses and return the results as 'notification' maps."
-  [{:keys [cards dashboard_id], pulse-id :id, :as pulse}]
+  [{:keys [cards], pulse-id :id, :as pulse} dashboard]
   (results->notifications pulse
-                          (if dashboard_id
+                          (if dashboard
                             ;; send the dashboard
-                            (execute-dashboard pulse dashboard_id)
+                            (execute-dashboard pulse dashboard)
                             ;; send the cards instead
                             (for [card  cards
                                   ;; Pulse ID may be `nil` if the Pulse isn't saved yet
@@ -423,12 +422,14 @@
    Example:
        (send-pulse! pulse)                       Send to all Channels
        (send-pulse! pulse :channel-ids [312])    Send only to Channel with :id = 312"
-  [{:keys [cards], :as pulse} & {:keys [channel-ids]}]
+  [{:keys [cards dashboard_id], :as pulse} & {:keys [channel-ids]}]
   {:pre [(map? pulse) (integer? (:creator_id pulse))]}
-  (let [pulse (-> pulse
-                  pulse/map->PulseInstance
-                  ;; This is usually already done by this step, in the `send-pulses` task which uses `retrieve-pulse`
-                  ;; to fetch the Pulse.
-                  pulse/hydrate-notification
-                  (merge (when channel-ids {:channel-ids channel-ids})))]
-    (send-notifications! (pulse->notifications pulse))))
+  (let [dashboard (Dashboard :id dashboard_id)
+        pulse     (-> pulse
+                      pulse/map->PulseInstance
+                      ;; This is usually already done by this step, in the `send-pulses` task which uses `retrieve-pulse`
+                      ;; to fetch the Pulse.
+                      pulse/hydrate-notification
+                      (merge (when channel-ids {:channel-ids channel-ids})))]
+    (when (not (:archived dashboard))
+      (send-notifications! (pulse->notifications pulse dashboard)))))
diff --git a/test/metabase/api/pulse_test.clj b/test/metabase/api/pulse_test.clj
index 8c29130c785..ce595f4bab8 100644
--- a/test/metabase/api/pulse_test.clj
+++ b/test/metabase/api/pulse_test.clj
@@ -791,7 +791,12 @@
         (is (= #{"LuckyRecipient" "Other"}
                (set (map :name (mt/user-http-request :rasta :get 200 (str "pulse?user_id=" (mt/user->id :rasta)))))))
         (is (= #{}
-               (set (map :name (mt/user-http-request :rasta :get 200 (str "pulse?user_id=" (mt/user->id :trashbird)))))))))))
+               (set (map :name (mt/user-http-request :rasta :get 200 (str "pulse?user_id=" (mt/user->id :trashbird)))))))))
+
+    (testing "excludes dashboard subscriptions associated with archived dashboards"
+      (mt/with-temp* [Dashboard [{dashboard-id :id} {:archived true}]
+                      Pulse     [_ {:dashboard_id dashboard-id}]]
+        (is (= [] (mt/user-http-request :rasta :get 200 "pulse")))))))
 
 
 ;;; +----------------------------------------------------------------------------------------------------------------+
diff --git a/test/metabase/dashboard_subscription_test.clj b/test/metabase/dashboard_subscription_test.clj
index e3e475a0036..d63d0e2c039 100644
--- a/test/metabase/dashboard_subscription_test.clj
+++ b/test/metabase/dashboard_subscription_test.clj
@@ -133,11 +133,11 @@
   (testing "it runs for each non-virtual card"
     (mt/with-temp* [Card          [{card-id-1 :id}]
                     Card          [{card-id-2 :id}]
-                    Dashboard     [{dashboard-id :id} {:name "Birdfeed Usage"}]
+                    Dashboard     [{dashboard-id :id, :as dashboard} {:name "Birdfeed Usage"}]
                     DashboardCard [dashcard-1 {:dashboard_id dashboard-id :card_id card-id-1}]
                     DashboardCard [dashcard-2 {:dashboard_id dashboard-id :card_id card-id-2}]
                     User [{user-id :id}]]
-      (let [result (pulse/execute-dashboard {:creator_id user-id} dashboard-id)]
+      (let [result (@#'pulse/execute-dashboard {:creator_id user-id} dashboard)]
         (is (= (count result) 2))
         (is (schema= [{:card     (s/pred map?)
                        :dashcard (s/pred map?)
@@ -147,22 +147,22 @@
     (mt/with-temp* [Card          [{card-id-1 :id}]
                     Card          [{card-id-2 :id}]
                     Card          [{card-id-3 :id}]
-                    Dashboard     [{dashboard-id :id} {:name "Birdfeed Usage"}]
+                    Dashboard     [{dashboard-id :id, :as dashboard} {:name "Birdfeed Usage"}]
                     DashboardCard [dashcard-1 {:dashboard_id dashboard-id :card_id card-id-1 :row 1 :col 0}]
                     DashboardCard [dashcard-2 {:dashboard_id dashboard-id :card_id card-id-2 :row 0 :col 1}]
                     DashboardCard [dashcard-3 {:dashboard_id dashboard-id :card_id card-id-3 :row 0 :col 0}]
                     User [{user-id :id}]]
-      (let [result (pulse/execute-dashboard {:creator_id user-id} dashboard-id)]
+      (let [result (@#'pulse/execute-dashboard {:creator_id user-id} dashboard)]
         (is (= [card-id-3 card-id-2 card-id-1]
                (map #(-> % :card :id) result))))))
   (testing "virtual (text) cards are returned as a viz settings map"
     (mt/with-temp* [Card          [{card-id-1 :id}]
                     Card          [{card-id-2 :id}]
-                    Dashboard     [{dashboard-id :id} {:name "Birdfeed Usage"}]
+                    Dashboard     [{dashboard-id :id, :as dashboard} {:name "Birdfeed Usage"}]
                     DashboardCard [dashcard-1 {:dashboard_id dashboard-id
                                                :visualization_settings {:virtual_card {}, :text "test"}}]
                     User [{user-id :id}]]
-      (is (= [{:virtual_card {}, :text "test"}] (pulse/execute-dashboard {:creator_id user-id} dashboard-id))))))
+      (is (= [{:virtual_card {}, :text "test"}] (@#'pulse/execute-dashboard {:creator_id user-id} dashboard))))))
 
 (deftest basic-table-test
   (tests {:pulse {:skip_if_empty false}}
@@ -337,3 +337,17 @@
       (fn [{:keys [card-id]} [pulse-results]]
         (is (= {:blocks [{:type "section" :text {:type "mrkdwn" :text "abcdefghi…"}}]}
                (nth (:attachments (thunk->boolean pulse-results)) 2))))}}))
+
+(deftest archived-dashboard-test
+  (tests {:dashboard {:archived true}}
+    "Dashboard subscriptions are not sent if dashboard is archived"
+    {:card (checkins-query-card {})
+
+     :assert
+     {:slack
+      (fn [_ [pulse-results]]
+        (is (= {:attachments []} (thunk->boolean pulse-results))))
+
+      :email
+      (fn [_ _]
+        (is (= {} (mt/summarize-multipart-email))))}}))
-- 
GitLab