From 3a60888f79ac05ab556012a8eda4518ffc04d7dc Mon Sep 17 00:00:00 2001 From: Allen Gilliland <agilliland@gmail.com> Date: Mon, 21 Mar 2016 14:54:59 -0700 Subject: [PATCH] update slack api settings endpoint to handle `metabot-enabled` setting and add a new metabot-lifecycle event handler which can listen for the appropriate events (:settings-update) and trigger startup/shutdown of metabot as needed. --- src/metabase/api/slack.clj | 14 ++++--- src/metabase/events/metabot_lifecycle.clj | 47 +++++++++++++++++++++++ src/metabase/integrations/slack.clj | 8 +--- src/metabase/models/setting.clj | 3 +- 4 files changed, 58 insertions(+), 14 deletions(-) create mode 100644 src/metabase/events/metabot_lifecycle.clj diff --git a/src/metabase/api/slack.clj b/src/metabase/api/slack.clj index 006e971b294..810b635a94f 100644 --- a/src/metabase/api/slack.clj +++ b/src/metabase/api/slack.clj @@ -3,18 +3,20 @@ (:require [compojure.core :refer [PUT]] [metabase.api.common :refer :all] [metabase.config :as config] - [metabase.integrations.slack :as slack])) + [metabase.integrations.slack :as slack] + [metabase.models.setting :as setting])) (defendpoint PUT "/settings" - "Update the `slack-token`. You must be a superuser to do this." - [:as {{slack-token :slack-token} :body}] - {slack-token [Required NonEmptyString]} + "Update Slack related settings. You must be a superuser to do this." + [:as {{slack-token :slack-token, metabot-enabled :metabot-enabled, :as slack-settings} :body}] + {slack-token [Required NonEmptyString] + metabot-enabled [Required]} (check-superuser) (try - ;; just check that channels.list doesn't throw an exception (that the connection works) + ;; just check that channels.list doesn't throw an exception (a.k.a. that the token works) (when-not config/is-test? (slack/GET :channels.list, :exclude_archived 1, :token slack-token)) - (slack/slack-token slack-token) + (setting/set-all slack-settings) {:ok true} (catch clojure.lang.ExceptionInfo info {:status 400, :body (ex-data info)}))) diff --git a/src/metabase/events/metabot_lifecycle.clj b/src/metabase/events/metabot_lifecycle.clj new file mode 100644 index 00000000000..bc6406c0149 --- /dev/null +++ b/src/metabase/events/metabot_lifecycle.clj @@ -0,0 +1,47 @@ +(ns metabase.events.metabot-lifecycle + (:require [clojure.core.async :as async] + [clojure.tools.logging :as log] + [metabase.db :as db] + [metabase.driver :as driver] + [metabase.events :as events] + [metabase.metabot :as metabot] + [metabase.models.database :refer [Database]])) + + +(def ^:const ^:private metabot-lifecycle-topics + "The `Set` of event topics which are subscribed to for use in metabot lifecycle." + #{:settings-update}) + +(def ^:private metabot-lifecycle-channel + "Channel for receiving event notifications we want to subscribe to for metabot lifecycle events." + (async/chan)) + + +;;; ## ---------------------------------------- EVENT PROCESSING ---------------------------------------- + + +(defn process-metabot-lifecycle-event + "Handle processing for a single event notification received on the metabot-lifecycle-channel" + [metabot-lifecycle-event] + ;; try/catch here to prevent individual topic processing exceptions from bubbling up. better to handle them here. + (when-let [{topic :topic object :item} metabot-lifecycle-event] + (try + ;; if someone updated our slack-token, or metabot was enabled/disabled then react accordingly + (let [{:keys [slack-token metabot-enabled]} object] + (cond + (and (contains? object :metabot-enabled) + (not (= "true" metabot-enabled))) (metabot/stop-metabot!) + (and (contains? object :slack-token) + (seq slack-token)) (metabot/start-metabot!))) + (catch Throwable e + (log/warn (format "Failed to process driver notifications event. %s" topic) e))))) + + + +;;; ## ---------------------------------------- LIFECYLE ---------------------------------------- + + +(defn events-init + "Automatically called during startup; start event listener for metabot lifecycle events." + [] + (events/start-event-listener metabot-lifecycle-topics metabot-lifecycle-channel process-metabot-lifecycle-event)) diff --git a/src/metabase/integrations/slack.clj b/src/metabase/integrations/slack.clj index b72d3218185..a27bb56a57a 100644 --- a/src/metabase/integrations/slack.clj +++ b/src/metabase/integrations/slack.clj @@ -7,13 +7,7 @@ ;; Define a setting which captures our Slack api token -(defsetting slack-token "Slack API bearer token obtained from https://api.slack.com/web#authentication" nil - :setter (fn [new-value] - (setting/set* :slack-token new-value) - (require 'metabase.metabot) - ((ns-resolve 'metabase.metabot (if (seq new-value) - 'start-metabot! - 'stop-metabot!))))) +(defsetting slack-token "Slack API bearer token obtained from https://api.slack.com/web#authentication" nil) (def ^:private ^:const ^String slack-api-base-url "https://slack.com/api") (def ^:private ^:const ^String files-channel-name "metabase_files") diff --git a/src/metabase/models/setting.clj b/src/metabase/models/setting.clj index 689c2b8b9bb..aa696d5ea94 100644 --- a/src/metabase/models/setting.clj +++ b/src/metabase/models/setting.clj @@ -5,6 +5,7 @@ [korma.core :as k] [metabase.config :as config] [metabase.db :refer [exists? sel del]] + [metabase.events :as events] [metabase.models [common :as common] [interface :as i]] [metabase.setup :as setup] @@ -128,7 +129,7 @@ (if-let [v (clojure.core/get settings k)] (set k v) (delete k))) - settings) + (events/publish-event :settings-update settings)) (defn set* "Set the value of a `Setting`, deleting it if VALUE is `nil` or an empty string." -- GitLab