(ns metabase.task.creator-sentiment-emails (:require [clojurewerkz.quartzite.jobs :as jobs] [clojurewerkz.quartzite.schedule.cron :as cron] [clojurewerkz.quartzite.triggers :as triggers] [java-time.api :as t] [metabase.analytics.core :as analytics] [metabase.channel.email :as email] [metabase.channel.email.messages :as messages] [metabase.config :as config] [metabase.db :as mdb] [metabase.driver.sql.query-processor :as sql.qp] [metabase.premium-features.core :as premium-features] [metabase.public-settings :as public-settings] [metabase.task :as task] [metabase.util.log :as log] [toucan2.core :as t2]) (:import (java.time.temporal WeekFields) (java.util Locale))) | |
(set! *warn-on-reflection* true) | |
Fetch the creators who are eligible for a creator sentiment email. Which are users who, in the past 2 months: - Created at least 10 questions total - Created at least 2 SQL questions - Created at least 1 dashboard - Only admins if whitelabeling is enabled | (defn- fetch-creators [has-whitelabelling?] (t2/query {:select [[:u.email :email] [:u.date_joined :created_at] [:u.first_name :first_name] [[:count [:distinct [:case [:= :d.archived false] :d.id]]] :num_dashboards] [[:count [:distinct [:case [:and [:= :rc.type "question"] [:= :rc.archived false]] :rc.id]]] :num_questions] [[:count [:distinct [:case [:and [:= :rc.type "model"] [:= :rc.archived false]] :rc.id]]] :num_models]] :from [[:core_user :u]] :join [[:report_card :rc] [:= :rc.creator_id :u.id] [:report_dashboard :d] [:= :d.creator_id :u.id]] :where [:and [:>= :rc.created_at (sql.qp/add-interval-honeysql-form (mdb/db-type) :%now -2 :month)] [:>= :d.created_at (sql.qp/add-interval-honeysql-form (mdb/db-type) :%now -2 :month)] [:= :u.is_active true] [:= :u.type "personal"] (when has-whitelabelling? [:= :u.is_superuser true])] :group-by [:u.id] :having [:and [:>= [:count [:distinct :rc.id]] 10] [:>= [:count [:distinct [:case [:= :rc.query_type "native"] :rc.id]]] 2] [:>= [:count [:distinct :d.id]] 1]]})) |
Figure out what plan this Metabase instance is on. | (defn fetch-plan-info [] (cond (and config/ee-available? (premium-features/is-hosted?)) (if (premium-features/has-any-features?) "pro-cloud/enterprise-cloud" "starter") config/ee-available? "pro-self-hosted/enterprise-self-hosted" :else "unknown")) |
(defn- fetch-instance-data [] {:created_at (analytics/instance-creation) :plan (fetch-plan-info) :version (config/mb-version-info :tag) :num_users (t2/count :model/User :is_active true, :type "personal") :num_dashboards (t2/count :model/Dashboard :archived false) :num_databases (t2/count :model/Database :is_audit false) :num_questions (t2/count :model/Card :archived false :type "question") :num_models (t2/count :model/Card :archived false :type "model")}) | |
Create a blob of instance/user data to be sent to the creator sentiment survey. | (defn- user-instance-info [instance-data {:keys [created_at num_dashboards num_questions num_models]}] {:instance instance-data :user {:created_at created_at :num_dashboards num_dashboards :num_questions num_questions :num_models num_models}}) |
Send an email to the instance admin following up on their experience with Metabase thus far. | (defn- send-creator-sentiment-emails! [current-week] ;; we need access to email AND the instance must have surveys enabled. (when (and (email/email-configured?) (email/surveys-enabled)) (let [instance-data (fetch-instance-data) all-creators (fetch-creators (premium-features/enable-whitelabeling?)) this-week? (fn [c] (= current-week (-> c :email hash (mod 52)))) recipients (filter this-week? all-creators) blob (if (public-settings/anon-tracking-enabled) (fn [creator] (user-instance-info instance-data creator)) (constantly nil))] (log/infof "Sending surveys to %d creators of a total %d" (count all-creators) (count recipients)) (doseq [creator recipients] (try (messages/send-creator-sentiment-email! creator (blob creator)) (catch Throwable e (log/error e "Problem sending creator sentiment email:"))))))) |
Sends out a monthly survey to a portion of the creators. | (jobs/defjob CreatorSentimentEmail [_] (let [current-week (.get (t/local-date) (.weekOfWeekBasedYear (WeekFields/of (Locale/getDefault))))] (send-creator-sentiment-emails! current-week))) |
(def ^:private creator-sentiment-emails-job-key "metabase.task.creator-sentiment-emails.job") (def ^:private creator-sentiment-emails-trigger-key "metabase.task.creator-sentiment-emails.trigger") | |
(defmethod task/init! ::SendCreatorSentimentEmails [_] (let [job (jobs/build (jobs/of-type CreatorSentimentEmail) (jobs/with-identity (jobs/key creator-sentiment-emails-job-key))) trigger (triggers/build (triggers/with-identity (triggers/key creator-sentiment-emails-trigger-key)) (triggers/start-now) (triggers/with-schedule ;; Fire at 2am every saturday (cron/cron-schedule "0 0 2 ? * 7")))] (task/schedule-task! job trigger))) | |