add submission tracking events

pull/105/head
Alex Turchyn 2 years ago
parent 62cea05084
commit 8cabe31827

@ -0,0 +1,17 @@
# frozen_string_literal: true
module Api
class SubmitterEmailClicksController < ApiBaseController
skip_before_action :authenticate_user!
def create
submitter = Submitter.find_by!(slug: params[:submitter_slug])
if params[:t] == SubmissionEvents.build_tracking_param(submitter, 'click_email')
SubmissionEvents.create_with_tracking_data(submitter, 'click_email', request)
end
render json: {}
end
end
end

@ -0,0 +1,15 @@
# frozen_string_literal: true
module Api
class SubmitterFormViewsController < ApiBaseController
skip_before_action :authenticate_user!
def create
submitter = Submitter.find_by!(slug: params[:submitter_slug])
SubmissionEvents.create_with_tracking_data(submitter, 'view_form', request)
render json: {}
end
end
end

@ -8,6 +8,8 @@ class SubmittersSendEmailController < ApplicationController
SubmitterMailer.invitation_email(submitter).deliver_later!
SubmissionEvent.create!(submitter:, event_type: 'send_email')
submitter.sent_at ||= Time.current
submitter.save!

@ -493,10 +493,44 @@ export default {
this.$nextTick(() => {
this.recalculateButtonDisabledKey = Math.random()
this.maybeTrackEmailClick()
this.trackViewForm()
})
},
methods: {
t,
maybeTrackEmailClick () {
const queryParams = new URLSearchParams(window.location.search)
if (queryParams.has('t')) {
fetch(this.baseUrl + '/api/submitter_email_clicks', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
t: queryParams.get('t'),
submitter_slug: this.submitterSlug
})
})
queryParams.delete('t')
const newUrl = [window.location.pathname, queryParams.toString()].filter(Boolean).join('?')
window.history.replaceState({}, document.title, newUrl)
}
},
trackViewForm () {
fetch(this.baseUrl + '/api/submitter_form_views', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
submitter_slug: this.submitterSlug
})
})
},
goToStep (step, scrollToArea = false, clickUpload = false) {
this.currentStep = this.stepFields.indexOf(step)

@ -4,6 +4,8 @@ class SendSubmitterInvitationEmailJob < ApplicationJob
def perform(submitter)
SubmitterMailer.invitation_email(submitter).deliver_now!
SubmissionEvent.create!(submitter:, event_type: 'send_email')
submitter.sent_at ||= Time.current
submitter.save
end

@ -32,6 +32,7 @@ class Submission < ApplicationRecord
belongs_to :created_by_user, class_name: 'User', optional: true
has_many :submitters, dependent: :destroy
has_many :submission_events, dependent: :destroy
serialize :template_fields, JSON
serialize :template_schema, JSON

@ -0,0 +1,53 @@
# frozen_string_literal: true
# == Schema Information
#
# Table name: submission_events
#
# id :bigint not null, primary key
# data :text not null
# event_timestamp :datetime not null
# event_type :string not null
# created_at :datetime not null
# updated_at :datetime not null
# submission_id :bigint not null
# submitter_id :bigint
#
# Indexes
#
# index_submission_events_on_submission_id (submission_id)
# index_submission_events_on_submitter_id (submitter_id)
#
# Foreign Keys
#
# fk_rails_... (submission_id => submissions.id)
# fk_rails_... (submitter_id => submitters.id)
#
class SubmissionEvent < ApplicationRecord
belongs_to :submission
belongs_to :submitter, optional: true
attribute :data, :string, default: -> { {} }
attribute :event_timestamp, :datetime, default: -> { Time.current }
serialize :data, JSON
before_validation :set_submission_id, on: :create
enum :event_type, {
send_email: 'send_email',
send_sms: 'send_sms',
open_email: 'open_email',
click_email: 'click_email',
click_sms: 'click_sms',
start_form: 'start_form',
view_form: 'view_form',
complete_form: 'complete_form'
}, scope: false
private
def set_submission_id
self.submission_id = submitter&.submission_id
end
end

@ -44,6 +44,7 @@ class Submitter < ApplicationRecord
has_many_attached :attachments
has_many :document_generation_events, dependent: :destroy
has_many :submission_events, dependent: :destroy
def status
if completed_at?

@ -3,7 +3,7 @@
<% else %>
<p>Hi there,</p>
<%= simple_format(@message) %>
<p><%= link_to 'Submit Form', submit_form_url(slug: @submitter.slug) %></p>
<p><%= link_to 'Submit Form', submit_form_url(slug: @submitter.slug, t: SubmissionEvents.build_tracking_param(@submitter, 'click_email')) %></p>
<p>Please contact us by replying to this email if you didn't request this.</p>
<p>
Thanks,<br><%= @current_account.name %>

@ -31,6 +31,8 @@ Rails.application.routes.draw do
namespace :api, defaults: { format: :json } do
resources :attachments, only: %i[create]
resources :submitter_email_clicks, only: %i[create]
resources :submitter_form_views, only: %i[create]
resources :submissions, only: %i[create]
resources :templates, only: %i[update show index] do
resources :submissions, only: %i[create]

@ -0,0 +1,15 @@
# frozen_string_literal: true
class CreateSubmissionEvents < ActiveRecord::Migration[7.0]
def change
create_table :submission_events do |t|
t.references :submission, null: false, foreign_key: true, index: true
t.references :submitter, null: true, foreign_key: true, index: true
t.text :data, null: false
t.string :event_type, null: false
t.datetime :event_timestamp, null: false
t.timestamps
end
end
end

@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema[7.0].define(version: 2023_09_09_213212) do
ActiveRecord::Schema[7.0].define(version: 2023_09_10_084410) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@ -91,6 +91,18 @@ ActiveRecord::Schema[7.0].define(version: 2023_09_09_213212) do
t.index ["account_id"], name: "index_encrypted_configs_on_account_id"
end
create_table "submission_events", force: :cascade do |t|
t.bigint "submission_id", null: false
t.bigint "submitter_id"
t.text "data", null: false
t.string "event_type", null: false
t.datetime "event_timestamp", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["submission_id"], name: "index_submission_events_on_submission_id"
t.index ["submitter_id"], name: "index_submission_events_on_submitter_id"
end
create_table "submissions", force: :cascade do |t|
t.bigint "template_id", null: false
t.bigint "created_by_user_id"
@ -178,6 +190,8 @@ ActiveRecord::Schema[7.0].define(version: 2023_09_09_213212) do
add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id"
add_foreign_key "document_generation_events", "submitters"
add_foreign_key "encrypted_configs", "accounts"
add_foreign_key "submission_events", "submissions"
add_foreign_key "submission_events", "submitters"
add_foreign_key "submissions", "templates"
add_foreign_key "submissions", "users", column: "created_by_user_id"
add_foreign_key "submitters", "submissions"

@ -45,7 +45,9 @@ module ReplaceEmailVariables
def build_submitter_link(submitter)
Rails.application.routes.url_helpers.submit_form_url(
slug: submitter.slug, **Docuseal.default_url_options
slug: submitter.slug,
t: SubmissionEvents.build_tracking_param(submitter, 'click_email'),
**Docuseal.default_url_options
)
end

@ -0,0 +1,22 @@
# frozen_string_literal: true
module SubmissionEvents
TRACKING_PARAM_LENGTH = 6
module_function
def build_tracking_param(submitter, event_type = 'click_email')
Base64.urlsafe_encode64(
[submitter.slug, event_type, Rails.application.secrets.secret_key_base].join(':')
).first(TRACKING_PARAM_LENGTH)
end
def create_with_tracking_data(submitter, event_type, request)
SubmissionEvent.create!(submitter:, event_type:, data: {
ip: request.remote_ip,
ua: request.user_agent,
sid: request.session.id.to_s,
uid: request.env['warden'].user(:user)&.id
}.compact_blank)
end
end

@ -7,7 +7,11 @@ module Submitters
module_function
def call(submitter, params, request)
Submissions.update_template_fields!(submitter.submission) if submitter.submission.template_fields.blank?
if submitter.submission.template_fields.blank?
Submissions.update_template_fields!(submitter.submission)
SubmissionEvents.create_with_tracking_data(submitter, 'start_form', request)
end
update_submitter!(submitter, params, request)
@ -32,6 +36,8 @@ module Submitters
submitter.completed_at = Time.current
submitter.ip = request.remote_ip
submitter.ua = request.user_agent
SubmissionEvents.create_with_tracking_data(submitter, 'complete_form', request)
end
submitter.save!

Loading…
Cancel
Save