Add ahoy + welcome notification tracking (#8758) [deploy]
* Set up ahoy gem, add ahoy-js * Import ahoy.js into base.js.erb * Add trackNotification function to notifications/index.html.erb * Add sanitized_broadcast_id helper * Use sanitized_broadcast_id in broadcast partial * Add specs around tracking welcome notifications * Remove optional fields from Ahoy::Visit migration + table * Fiddle with trait to see if it helps with CI failures * Disable geocode tracking in ahoy * Stub out SiteConfig in notifications page spec
This commit is contained in:
parent
0e765b47de
commit
904f0dac78
18 changed files with 168 additions and 2 deletions
1
Gemfile
1
Gemfile
|
|
@ -16,6 +16,7 @@ gem "acts_as_follower", github: "thepracticaldev/acts_as_follower", branch: "mas
|
|||
gem "addressable", "~> 2.7" # A replacement for the URI implementation that is part of Ruby's standard library
|
||||
gem "administrate", "~> 0.13" # A Rails engine that helps you put together a super-flexible admin dashboard
|
||||
gem "ahoy_email", "~> 1.1" # Email analytics for Rails
|
||||
gem "ahoy_matey", "~> 3.0" # Tracking analytics for Rails
|
||||
gem "ancestry", "~> 3.0" # Ancestry allows the records of a ActiveRecord model to be organized in a tree structure
|
||||
gem "autoprefixer-rails", "~> 9.7" # Parse CSS and add vendor prefixes to CSS rules using values from the Can I Use website
|
||||
gem "aws-sdk-lambda", "~> 1.42" # Official AWS Ruby gem for AWS Lambda
|
||||
|
|
|
|||
|
|
@ -99,6 +99,11 @@ GEM
|
|||
addressable (>= 2.3.2)
|
||||
nokogiri
|
||||
safely_block (>= 0.1.1)
|
||||
ahoy_matey (3.0.4)
|
||||
activesupport (>= 5)
|
||||
device_detector
|
||||
geocoder (>= 1.4.5)
|
||||
safely_block (>= 0.2.1)
|
||||
amazing_print (1.2.0)
|
||||
ancestry (3.0.7)
|
||||
activerecord (>= 3.2.0)
|
||||
|
|
@ -235,6 +240,7 @@ GEM
|
|||
unicode_plot (>= 0.0.4, < 1.0.0)
|
||||
descendants_tracker (0.0.4)
|
||||
thread_safe (~> 0.3, >= 0.3.1)
|
||||
device_detector (1.0.3)
|
||||
devise (4.7.2)
|
||||
bcrypt (~> 3.0)
|
||||
orm_adapter (~> 0.1)
|
||||
|
|
@ -369,6 +375,7 @@ GEM
|
|||
formatador (0.2.5)
|
||||
front_matter_parser (0.2.1)
|
||||
gemoji (4.0.0.rc2)
|
||||
geocoder (1.6.3)
|
||||
get_process_mem (0.2.5)
|
||||
ffi (~> 1.0)
|
||||
gibbon (3.3.4)
|
||||
|
|
@ -876,6 +883,7 @@ DEPENDENCIES
|
|||
addressable (~> 2.7)
|
||||
administrate (~> 0.13)
|
||||
ahoy_email (~> 1.1)
|
||||
ahoy_matey (~> 3.0)
|
||||
amazing_print (~> 1.2)
|
||||
ancestry (~> 3.0)
|
||||
approvals (~> 0.0)
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
//= require initializePage
|
||||
//= require utilities/getImageForLink
|
||||
//= require honeybadger-js/dist/honeybadger.js
|
||||
//= require ahoy.js/dist/ahoy.js
|
||||
//= require serviceworker-companion
|
||||
|
||||
var instantClick
|
||||
|
|
|
|||
|
|
@ -8,4 +8,8 @@ module BroadcastsHelper
|
|||
"crayons-banner crayons-banner--#{broadcast.banner_style}"
|
||||
end
|
||||
end
|
||||
|
||||
def sanitized_broadcast_id(broadcast_title)
|
||||
broadcast_title.downcase.delete(":").tr(" ", "_")
|
||||
end
|
||||
end
|
||||
|
|
|
|||
8
app/models/ahoy/event.rb
Normal file
8
app/models/ahoy/event.rb
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
class Ahoy::Event < ApplicationRecord
|
||||
include Ahoy::QueryMethods
|
||||
|
||||
self.table_name = "ahoy_events"
|
||||
|
||||
belongs_to :visit
|
||||
belongs_to :user, optional: true
|
||||
end
|
||||
6
app/models/ahoy/visit.rb
Normal file
6
app/models/ahoy/visit.rb
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
class Ahoy::Visit < ApplicationRecord
|
||||
self.table_name = "ahoy_visits"
|
||||
|
||||
has_many :events, class_name: "Ahoy::Event"
|
||||
belongs_to :user, optional: true
|
||||
end
|
||||
|
|
@ -6,7 +6,7 @@
|
|||
<img src="<%= ProfileImage.new(user).get %>" alt="link to <%= json_data["user"]["username"] %>'s profile">
|
||||
</div>
|
||||
</a>
|
||||
<div class="content notification-content broadcast-content">
|
||||
<div class="content notification-content broadcast-content" id="<%= sanitized_broadcast_id(json_data['broadcast']['title']) %>">
|
||||
<%= json_data["broadcast"]["processed_html"].html_safe %>
|
||||
|
||||
<% if notification.json_data['broadcast']['type_of'] == "Welcome" %>
|
||||
|
|
|
|||
|
|
@ -17,6 +17,20 @@
|
|||
<meta name="twitter:description" content="Notifications inbox for <%= community_name %>">
|
||||
<% end %>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* A script that tracks clicks for welcome notifications.
|
||||
* The notification must have `trackNotification` as its onclick event
|
||||
* in order for this to be triggered.
|
||||
*
|
||||
* @param {Event} The click event on the notification.
|
||||
*/
|
||||
function trackNotification(e) {
|
||||
let title = e.target.parentElement.id
|
||||
ahoy.track("Clicked Welcome Notification", { title });
|
||||
}
|
||||
</script>
|
||||
|
||||
<% if user_signed_in? %>
|
||||
<div class="home" id="notifications-container">
|
||||
<div class="side-bar">
|
||||
|
|
|
|||
8
config/initializers/ahoy.rb
Normal file
8
config/initializers/ahoy.rb
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
class Ahoy::Store < Ahoy::DatabaseStore
|
||||
end
|
||||
|
||||
# set to true for JavaScript tracking
|
||||
Ahoy.api = true
|
||||
|
||||
# set to false to disable geocode tracking
|
||||
Ahoy.geocode = false
|
||||
28
db/migrate/20200617183058_create_ahoy_visits_and_events.rb
Normal file
28
db/migrate/20200617183058_create_ahoy_visits_and_events.rb
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
class CreateAhoyVisitsAndEvents < ActiveRecord::Migration[6.0]
|
||||
# This migration includes a subset of the available fields provided by ahoy.
|
||||
# For the full list of options, please see https://github.com/ankane/ahoy.
|
||||
|
||||
def change
|
||||
create_table :ahoy_visits do |t|
|
||||
t.string :visit_token
|
||||
t.string :visitor_token
|
||||
|
||||
t.references :user
|
||||
t.timestamp :started_at
|
||||
end
|
||||
|
||||
add_index :ahoy_visits, [:visit_token], unique: true
|
||||
|
||||
create_table :ahoy_events do |t|
|
||||
t.references :visit
|
||||
t.references :user
|
||||
|
||||
t.string :name
|
||||
t.jsonb :properties
|
||||
t.timestamp :time
|
||||
end
|
||||
|
||||
add_index :ahoy_events, [:name, :time]
|
||||
add_index :ahoy_events, :properties, using: :gin, opclass: :jsonb_path_ops
|
||||
end
|
||||
end
|
||||
23
db/schema.rb
23
db/schema.rb
|
|
@ -10,11 +10,23 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 2020_06_17_014509) do
|
||||
ActiveRecord::Schema.define(version: 2020_06_17_183058) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
|
||||
create_table "ahoy_events", force: :cascade do |t|
|
||||
t.string "name"
|
||||
t.jsonb "properties"
|
||||
t.datetime "time"
|
||||
t.bigint "user_id"
|
||||
t.bigint "visit_id"
|
||||
t.index ["name", "time"], name: "index_ahoy_events_on_name_and_time"
|
||||
t.index ["properties"], name: "index_ahoy_events_on_properties", opclass: :jsonb_path_ops, using: :gin
|
||||
t.index ["user_id"], name: "index_ahoy_events_on_user_id"
|
||||
t.index ["visit_id"], name: "index_ahoy_events_on_visit_id"
|
||||
end
|
||||
|
||||
create_table "ahoy_messages", id: :serial, force: :cascade do |t|
|
||||
t.datetime "clicked_at"
|
||||
t.text "content"
|
||||
|
|
@ -37,6 +49,15 @@ ActiveRecord::Schema.define(version: 2020_06_17_014509) do
|
|||
t.index ["user_id", "user_type"], name: "index_ahoy_messages_on_user_id_and_user_type"
|
||||
end
|
||||
|
||||
create_table "ahoy_visits", force: :cascade do |t|
|
||||
t.datetime "started_at"
|
||||
t.bigint "user_id"
|
||||
t.string "visit_token"
|
||||
t.string "visitor_token"
|
||||
t.index ["user_id"], name: "index_ahoy_visits_on_user_id"
|
||||
t.index ["visit_token"], name: "index_ahoy_visits_on_visit_token", unique: true
|
||||
end
|
||||
|
||||
create_table "api_secrets", force: :cascade do |t|
|
||||
t.datetime "created_at", null: false
|
||||
t.string "description", null: false
|
||||
|
|
|
|||
|
|
@ -128,6 +128,7 @@
|
|||
"@babel/preset-env": "^7.9.6",
|
||||
"@github/clipboard-copy-element": "^1.1.2",
|
||||
"@rails/webpacker": "5.1.1",
|
||||
"ahoy.js": "^0.3.6",
|
||||
"babel-preset-preact": "^2.0.0",
|
||||
"chart.js": "^2.9.3",
|
||||
"clipboard-polyfill": "^2.8.6",
|
||||
|
|
|
|||
|
|
@ -68,5 +68,9 @@ FactoryBot.define do
|
|||
type_of { "Announcement" }
|
||||
processed_html { "<p>Hello, World!</p>" }
|
||||
end
|
||||
|
||||
trait :with_tracking do
|
||||
processed_html { "Sloan here again! 👋 DEV is a friendly community. Why not introduce yourself by leaving a comment in <a href='/welcome' onclick='trackNotification(event)'>the welcome thread</a>!" }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -85,4 +85,54 @@ RSpec.describe "Notifications page", type: :system, js: true do
|
|||
validate_reply(comment.id)
|
||||
end
|
||||
end
|
||||
|
||||
context "with welcome notifications" do
|
||||
let(:mascot_account) { create(:user) }
|
||||
|
||||
before do
|
||||
allow(Notification).to receive(:send_welcome_notification).and_call_original
|
||||
allow(User).to receive(:mascot_account).and_return(mascot_account)
|
||||
allow(SiteConfig).to receive(:staff_user_id).and_return(mascot_account.id)
|
||||
alex.update!(created_at: 1.day.ago)
|
||||
end
|
||||
|
||||
context "without tracking enabled" do
|
||||
before do
|
||||
create(:welcome_broadcast)
|
||||
Broadcasts::WelcomeNotification::Generator.call(alex.id)
|
||||
sidekiq_perform_enqueued_jobs
|
||||
end
|
||||
|
||||
it "renders the notification" do
|
||||
visit "/notifications"
|
||||
|
||||
expect(page).to have_css(".broadcast-content")
|
||||
expect(page).to have_css("#welcome_notification_welcome_thread")
|
||||
end
|
||||
|
||||
it "does not track events" do
|
||||
visit "/notifications"
|
||||
click_link("the welcome thread")
|
||||
|
||||
expect(page).to have_current_path("/welcome")
|
||||
expect(Ahoy::Event.count).to eq(0)
|
||||
end
|
||||
end
|
||||
|
||||
context "with tracking enabled" do
|
||||
before do
|
||||
create(:welcome_broadcast, :with_tracking)
|
||||
Broadcasts::WelcomeNotification::Generator.call(alex.id)
|
||||
sidekiq_perform_enqueued_jobs
|
||||
end
|
||||
|
||||
it "tracks events" do
|
||||
visit "/notifications"
|
||||
click_link("the welcome thread")
|
||||
|
||||
expect(page).to have_current_path("/welcome")
|
||||
expect(Ahoy::Event.count).to eq(1)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
BIN
vendor/cache/ahoy_matey-3.0.4.gem
vendored
Normal file
BIN
vendor/cache/ahoy_matey-3.0.4.gem
vendored
Normal file
Binary file not shown.
BIN
vendor/cache/device_detector-1.0.3.gem
vendored
Normal file
BIN
vendor/cache/device_detector-1.0.3.gem
vendored
Normal file
Binary file not shown.
BIN
vendor/cache/geocoder-1.6.3.gem
vendored
Normal file
BIN
vendor/cache/geocoder-1.6.3.gem
vendored
Normal file
Binary file not shown.
12
yarn.lock
12
yarn.lock
|
|
@ -2550,6 +2550,13 @@ aggregate-error@^3.0.0:
|
|||
clean-stack "^2.0.0"
|
||||
indent-string "^4.0.0"
|
||||
|
||||
ahoy.js@^0.3.6:
|
||||
version "0.3.6"
|
||||
resolved "https://registry.yarnpkg.com/ahoy.js/-/ahoy.js-0.3.6.tgz#ca27cb816a1de1f537616e4ea3213950259cd821"
|
||||
integrity sha512-9X1g5xJioXk+AY5ti1LIlHExZ+8SjhuQOzAAXkNAZrZ6lmp88lFW7IeHADfii1/p5Cf3azg9hF2dk8Zsu4OfWA==
|
||||
dependencies:
|
||||
object-to-formdata ">=3.0.0"
|
||||
|
||||
airbnb-js-shims@^2.2.1:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/airbnb-js-shims/-/airbnb-js-shims-2.2.1.tgz#db481102d682b98ed1daa4c5baa697a05ce5c040"
|
||||
|
|
@ -10057,6 +10064,11 @@ object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1:
|
|||
resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
|
||||
integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==
|
||||
|
||||
object-to-formdata@>=3.0.0:
|
||||
version "3.0.9"
|
||||
resolved "https://registry.yarnpkg.com/object-to-formdata/-/object-to-formdata-3.0.9.tgz#40e3314522345789259738811c0222b7d6e556e9"
|
||||
integrity sha512-1JDHRFSpk6wzhPBAAqdVncdvbjZ+bjB0tioruNdKn8UyudBBXiBxRa7PJyvYqp4ioEKX98dEOX9Fw1RxA+vLzg==
|
||||
|
||||
object-visit@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue