Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
M
Metabase
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Iterations
Wiki
Requirements
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Locked files
Build
Pipelines
Jobs
Pipeline schedules
Test cases
Artifacts
Deploy
Releases
Package registry
Container registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Code review analytics
Issue analytics
Insights
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Terms and privacy
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Engineering Digital Service
Metabase
Commits
a8ae6415
Commit
a8ae6415
authored
9 years ago
by
Allen Gilliland
Browse files
Options
Downloads
Patches
Plain Diff
split follow-up emails into 2 distinct paths.
parent
fc55f139
Branches
Branches containing commit
Tags
Tags containing commit
No related merge requests found
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
src/metabase/email/messages.clj
+3
-3
3 additions, 3 deletions
src/metabase/email/messages.clj
src/metabase/models/user.clj
+5
-0
5 additions, 0 deletions
src/metabase/models/user.clj
src/metabase/task/follow_up_emails.clj
+74
-32
74 additions, 32 deletions
src/metabase/task/follow_up_emails.clj
with
82 additions
and
35 deletions
src/metabase/email/messages.clj
+
3
−
3
View file @
a8ae6415
...
...
@@ -93,8 +93,8 @@
[
email
msg-type
]
{
:pre
[(
string?
email
)
(
u/is-email?
email
)
(
contains?
#
{
"a
ctive"
"inactive
"
}
msg-type
)]}
(
let
[
subject
(
if
(
=
"
inactive
"
msg-type
)
(
contains?
#
{
"a
bandon"
"follow-up
"
}
msg-type
)]}
(
let
[
subject
(
if
(
=
"
abandon
"
msg-type
)
"[Metabase] Help make Metabase better."
"[Metabase] Tell us how things are going."
)
data-quote
(
quotation/random-quote
)
...
...
@@ -102,7 +102,7 @@
:logoHeader
true
:quotation
(
:quote
data-quote
)
:quotationAuthor
(
:author
data-quote
)}
(
if
(
=
"
inactive
"
msg-type
)
(
if
(
=
"
abandon
"
msg-type
)
{
:heading
"We’d love your feedback."
:callToAction
"It looks like Metabase wasn’t quite a match for you. Would you mind taking a fast 5 question survey to help the Metabase team understand why and make things better in the future?"
:link
"http://www.metabase.com/feedback/this-thing-sucks"
}
...
...
This diff is collapsed.
Click to expand it.
src/metabase/models/user.clj
+
5
−
0
View file @
a8ae6415
...
...
@@ -118,3 +118,8 @@
[
reset-token
]
{
:pre
[(
string?
reset-token
)]}
(
str
(
setting/get
:-site-url
)
"/auth/reset_password/"
reset-token
))
(
defn
instance-created-at
"The date the instance was created. We use the :date_joined of the first user to determine this."
[]
(
db/sel
:one
:field
[
User
:date_joined
]
(
k/order
:date_joined
:ASC
)
(
k/limit
1
)))
This diff is collapsed.
Click to expand it.
src/metabase/task/follow_up_emails.clj
+
74
−
32
View file @
a8ae6415
...
...
@@ -17,45 +17,61 @@
[
metabase.task
:as
task
]))
(
declare
send-follow-up-email!
)
(
declare
send-follow-up-email!
send-abandonment-email!
)
(
def
^
:private
^
:const
follow-up-emails-job-key
"metabase.task.follow-up-emails.job"
)
(
def
^
:private
^
:const
follow-up-emails-trigger-key
"metabase.task.follow-up-emails.trigger"
)
(
defonce
^
:private
follow-up-emails-job
(
atom
nil
))
(
defonce
^
:private
follow-up-emails-trigger
(
atom
nil
))
(
setting/defsetting
follow-up-email-sent
"have we sent a follow up email to the instance admin?"
false
:internal
true
)
;; triggers the sending of all pulses which are scheduled to run in the current hour
(
def
^
:private
^
:const
abandonment-emails-job-key
"metabase.task.abandonment-emails.job"
)
(
def
^
:private
^
:const
abandonment-emails-trigger-key
"metabase.task.abandonment-emails.trigger"
)
(
defonce
^
:private
abandonment-emails-job
(
atom
nil
))
(
defonce
^
:private
abandonment-emails-trigger
(
atom
nil
))
(
setting/defsetting
abandonment-email-sent
"have we sent an abandonment email to the instance admin?"
false
:internal
true
)
;; 2 weeks of inactivity after 30 days of total install
;;
;; this sends out a general 2 week email follow up email
(
jobs/defjob
FollowUpEmail
[
ctx
]
;;
1.
if we've already sent the follow-up email then we are done
;; if we've already sent the follow-up email then we are done
(
when-not
(
=
"true"
(
follow-up-email-sent
))
;; figure out when we consider the instance created (join date of oldest user)
(
when-let
[
instance-created
(
->
(
k/select
user/User
(
k/fields
:date_joined
)
(
k/order
:date_joined
:ASC
)
(
k/limit
1
))
first
:date_joined
)]
;; 2. we need to be 2+ weeks (14 days) from creation to send the follow up
;; figure out when we consider the instance created
(
when-let
[
instance-created
(
user/instance-created-at
)]
;; we need to be 2+ weeks (14 days) from creation to send the follow up
(
when
(
<
(
*
14
24
60
60
1000
)
(
-
(
System/currentTimeMillis
)
(
.getTime
^
java.sql.Timestamp
instance-created
)))
;; 3. we need access to email AND the instance must be opted into anonymous tracking
(
send-follow-up-email!
)))))
;; this sends out an email any time after 30 days if the instance has stopped being used for 14 days
(
jobs/defjob
AbandonmentEmail
[
ctx
]
;; if we've already sent the abandonment email then we are done
(
when-not
(
=
"true"
(
abandonment-email-sent
))
;; figure out when we consider the instance created
(
when-let
[
instance-created
(
user/instance-created-at
)]
;; we need to be 4+ weeks (30 days) from creation to send the follow up
(
when
(
<
(
*
30
24
60
60
1000
)
(
-
(
System/currentTimeMillis
)
(
.getTime
^
java.sql.Timestamp
instance-created
)))
;; we need access to email AND the instance must be opted into anonymous tracking
(
when
(
and
(
email/email-configured?
)
(
let
[
tracking?
(
setting/get
:anon-tracking-enabled
)]
(
or
(
nil?
tracking?
)
(
=
"true"
tracking?
))))
(
send-
follow-up
-email!
))))))
(
send-
abandonment
-email!
))))))
(
defn
task-init
"Automatically called during startup; start the job for sending
pulse
s."
"Automatically called during startup; start the job for sending
follow up email
s."
[]
;;
build our job
;;
FollowUpEmail job + trigger
(
reset!
follow-up-emails-job
(
jobs/build
(
jobs/of-type
FollowUpEmail
)
(
jobs/with-identity
(
jobs/key
follow-up-emails-job-key
))))
;; build our trigger
(
reset!
follow-up-emails-trigger
(
triggers/build
(
triggers/with-identity
(
triggers/key
follow-up-emails-trigger-key
))
(
triggers/start-now
)
...
...
@@ -63,28 +79,54 @@
;; run once a day
(
cron/cron-schedule
"0 0 12 * * ? *"
))))
;; submit ourselves to the scheduler
(
task/schedule-task!
@
follow-up-emails-job
@
follow-up-emails-trigger
))
(
task/schedule-task!
@
follow-up-emails-job
@
follow-up-emails-trigger
)
;; AbandonmentEmail job + trigger
(
reset!
abandonment-emails-job
(
jobs/build
(
jobs/of-type
AbandonmentEmail
)
(
jobs/with-identity
(
jobs/key
abandonment-emails-job-key
))))
(
reset!
abandonment-emails-trigger
(
triggers/build
(
triggers/with-identity
(
triggers/key
abandonment-emails-trigger-key
))
(
triggers/start-now
)
(
triggers/with-schedule
;; run once a day
(
cron/cron-schedule
"0 0 12 * * ? *"
))))
;; submit ourselves to the scheduler
(
task/schedule-task!
@
abandonment-emails-job
@
abandonment-emails-trigger
))
(
defn-
send-follow-up-email!
"Send an email to the instance admin following up on their experience with Metabase thus far."
[]
(
try
;; grab the oldest admins email address, that's who we'll send to
(
when-let
[
admin
(
db/sel
:one
user/User
:is_superuser
true
(
k/order
:date_joined
))]
;; check for activity and use that to determine which email we'll send
;; inactive = no users created, no activity created, no dash/card views (past 7 days)
(
let
[
last-user
(
c/from-sql-time
(
db/sel
:one
:field
[
user/User
:date_joined
]
(
k/order
:date_joined
:DESC
)
(
k/limit
1
)))
last-activity
(
c/from-sql-time
(
db/sel
:one
:field
[
activity/Activity
:timestamp
]
(
k/order
:timestamp
:DESC
)
(
k/limit
1
)))
last-view
(
c/from-sql-time
(
db/sel
:one
:field
[
view-log/ViewLog
:timestamp
]
(
k/order
:timestamp
:DESC
)
(
k/limit
1
)))
seven-days-ago
(
t/minus
(
t/now
)
(
t/days
7
))
message-type
(
if
(
and
(
t/before?
last-user
seven-days-ago
)
(
t/before?
last-activity
seven-days-ago
)
(
t/before?
last-view
seven-days-ago
))
"inactive"
"active"
)]
(
messages/send-follow-up-email
(
:email
admin
)
message-type
)))
;; we need access to email AND the instance must be opted into anonymous tracking
(
when
(
and
(
email/email-configured?
)
(
let
[
tracking?
(
setting/get
:anon-tracking-enabled
)]
(
or
(
nil?
tracking?
)
(
=
"true"
tracking?
))))
;; grab the oldest admins email address, that's who we'll send to
(
when-let
[
admin
(
db/sel
:one
user/User
:is_superuser
true
(
k/order
:date_joined
))]
(
messages/send-follow-up-email
(
:email
admin
)
"follow-up"
)))
(
catch
Throwable
t
(
log/error
"Problem sending follow-up email"
t
))
(
finally
(
setting/set
:follow-up-email-sent
"true"
))))
(
defn-
send-abandonment-email!
"Send an email to the instance admin about why Metabase usage has died down."
[]
;; grab the oldest admins email address, that's who we'll send to
(
when-let
[
admin
(
db/sel
:one
user/User
:is_superuser
true
(
k/order
:date_joined
))]
;; inactive = no users created, no activity created, no dash/card views (past 7 days)
(
let
[
last-user
(
c/from-sql-time
(
db/sel
:one
:field
[
user/User
:date_joined
]
(
k/order
:date_joined
:DESC
)
(
k/limit
1
)))
last-activity
(
c/from-sql-time
(
db/sel
:one
:field
[
activity/Activity
:timestamp
]
(
k/order
:timestamp
:DESC
)
(
k/limit
1
)))
last-view
(
c/from-sql-time
(
db/sel
:one
:field
[
view-log/ViewLog
:timestamp
]
(
k/order
:timestamp
:DESC
)
(
k/limit
1
)))
two-weeks-ago
(
t/minus
(
t/now
)
(
t/days
14
))]
(
when
(
and
(
t/before?
last-user
two-weeks-ago
)
(
t/before?
last-activity
two-weeks-ago
)
(
t/before?
last-view
two-weeks-ago
))
(
try
(
messages/send-follow-up-email
(
:email
admin
)
"abandon"
)
(
catch
Throwable
t
(
log/error
"Problem sending abandonment email"
t
))
(
finally
(
setting/set
:abandonment-email-sent
"true"
)))))))
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment