(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)))