Skip to content

Commit d6591ee

Browse files
authored
Merge pull request #1105 from code-corps/1038-add-analytics-tracking-for-core-actions
Add analytics tracking for core actions
2 parents f17e846 + 067c3fa commit d6591ee

23 files changed

+729
-150
lines changed

lib/code_corps/analytics/segment_tracking_support.ex

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@ defmodule CodeCorps.Analytics.SegmentTrackingSupport do
1919
def includes?(:create, %CodeCorps.StripeConnectSubscription{}), do: true
2020
def includes?(:create, %CodeCorps.StripePlatformCard{}), do: true
2121
def includes?(:create, %CodeCorps.StripePlatformCustomer{}), do: true
22-
def includes?(:create, %CodeCorps.Task{}), do: true
23-
def includes?(:update, %CodeCorps.Task{}), do: true
2422
def includes?(:create, %CodeCorps.User{}), do: true
2523
def includes?(:update, %CodeCorps.User{}), do: true
2624
def includes?(:create, %CodeCorps.UserCategory{}), do: true

lib/code_corps/analytics/segment_traits_builder.ex

Lines changed: 153 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -3,47 +3,79 @@ defmodule CodeCorps.Analytics.SegmentTraitsBuilder do
33
Builds Segment traits from provided data
44
"""
55

6-
@spec build(struct) :: map
7-
def build(record), do: traits(record)
6+
alias CodeCorps.Repo
87

9-
defp traits(user = %CodeCorps.User{}) do
10-
%{
11-
admin: user.admin,
12-
biography: user.biography,
13-
created_at: user.inserted_at,
14-
email: user.email,
15-
first_name: user.first_name,
16-
github_id: user.github_id,
17-
github_username: user.github_username,
18-
last_name: user.last_name,
19-
sign_up_context: user.sign_up_context,
20-
state: user.state,
21-
twitter: user.twitter,
22-
type: user.type,
23-
username: user.username,
24-
website: user.website
25-
}
26-
end
8+
@spec build(struct | map) :: map
9+
def build(record), do: traits(record)
2710

28-
defp traits(comment = %CodeCorps.Comment{}) do
29-
comment = comment |> CodeCorps.Repo.preload(:task)
11+
@spec traits(struct | map) :: map
12+
defp traits(%CodeCorps.Comment{} = comment) do
13+
comment = comment |> Repo.preload(:task)
3014
%{
3115
comment_id: comment.id,
3216
task: comment.task.title,
3317
task_id: comment.task.id,
3418
project_id: comment.task.project_id
3519
}
3620
end
37-
38-
defp traits(record = %CodeCorps.ProjectUser{}) do
39-
record = record |> CodeCorps.Repo.preload(:project)
21+
defp traits(%CodeCorps.DonationGoal{} = donation_goal) do
4022
%{
23+
amount: donation_goal.amount,
24+
current: donation_goal.current,
25+
project_id: donation_goal.project_id
26+
}
27+
end
28+
defp traits(%CodeCorps.GithubAppInstallation{} = installation) do
29+
%{
30+
access_token_expires_at: installation.access_token_expires_at,
31+
github_account_login: installation.github_account_login,
32+
github_account_type: installation.github_account_type,
33+
github_id: installation.github_id,
34+
origin: installation.origin,
35+
state: installation.state,
36+
project_id: installation.project_id,
37+
user_id: installation.user_id
38+
}
39+
end
40+
defp traits(%CodeCorps.ProjectGithubRepo{} = record) do
41+
record = record |> Repo.preload([:project, :github_repo])
42+
%{
43+
project: record.project.title,
44+
project_id: record.project_id,
45+
github_repo_id: record.github_repo_id,
46+
github_repo_github_account_login: record.github_repo.github_account_login,
47+
github_repo_github_account_type: record.github_repo.github_account_type,
48+
github_repo_github_id: record.github_repo.github_id,
49+
github_repo_name: record.github_repo.name
50+
}
51+
end
52+
defp traits(%CodeCorps.ProjectSkill{} = record) do
53+
record = record |> Repo.preload([:project, :skill])
54+
%{
55+
skill: record.skill.title,
56+
skill_id: record.skill_id,
4157
project: record.project.title,
4258
project_id: record.project_id
4359
}
4460
end
45-
46-
defp traits(charge = %CodeCorps.StripeConnectCharge{}) do
61+
defp traits(%CodeCorps.ProjectUser{} = record) do
62+
record = record |> Repo.preload(:project)
63+
%{
64+
project: record.project.title,
65+
project_id: record.project_id
66+
}
67+
end
68+
defp traits(%CodeCorps.StripeConnectAccount{} = account) do
69+
%{
70+
id: account.id,
71+
business_name: account.business_name,
72+
display_name: account.display_name,
73+
email: account.email,
74+
id_from_stripe: account.id_from_stripe,
75+
organization_id: account.organization_id,
76+
}
77+
end
78+
defp traits(%CodeCorps.StripeConnectCharge{} = charge) do
4779
# NOTE: this only works for some currencies
4880
revenue = charge.amount / 100
4981
currency = String.capitalize(charge.currency) # ISO 4127 format
@@ -55,38 +87,121 @@ defmodule CodeCorps.Analytics.SegmentTraitsBuilder do
5587
user_id: charge.user_id
5688
}
5789
end
90+
defp traits(%CodeCorps.StripeConnectPlan{} = plan) do
91+
%{
92+
id: plan.id,
93+
amount: plan.amount,
94+
created: plan.created,
95+
id_from_stripe: plan.id_from_stripe,
96+
name: plan.name,
97+
project_id: plan.project_id
98+
}
99+
end
100+
defp traits(%CodeCorps.StripeConnectSubscription{} = subscription) do
101+
subscription = subscription |> Repo.preload(:stripe_connect_plan)
58102

59-
defp traits(task = %CodeCorps.Task{}) do
60103
%{
104+
id: subscription.id,
105+
created: subscription.created,
106+
cancelled_at: subscription.cancelled_at,
107+
current_period_start: subscription.current_period_start,
108+
current_period_end: subscription.current_period_end,
109+
ended_at: subscription.ended_at,
110+
id_from_stripe: subscription.id_from_stripe,
111+
quantity: subscription.quantity,
112+
status: subscription.status,
113+
start: subscription.start,
114+
plan_id: subscription.stripe_connect_plan_id,
115+
user_id: subscription.user_id,
116+
project_id: subscription.stripe_connect_plan.project_id
117+
}
118+
end
119+
defp traits(%CodeCorps.StripePlatformCard{} = card) do
120+
%{
121+
id: card.id,
122+
brand: card.brand,
123+
exp_month: card.exp_month,
124+
exp_year: card.exp_year,
125+
id_from_stripe: card.id_from_stripe,
126+
last4: card.last4,
127+
name: card.name,
128+
user_id: card.user_id
129+
}
130+
end
131+
defp traits(%CodeCorps.StripePlatformCustomer{} = customer) do
132+
%{
133+
id: customer.id,
134+
created: customer.created,
135+
currency: customer.currency,
136+
delinquent: customer.delinquent,
137+
email: customer.email,
138+
id_from_stripe: customer.id_from_stripe,
139+
user_id: customer.user_id
140+
}
141+
end
142+
defp traits(%CodeCorps.Task{} = task) do
143+
%{
144+
order: task.order,
61145
task: task.title,
62146
task_id: task.id,
147+
task_list_id: task.task_list_id,
63148
project_id: task.project_id
64149
}
65150
end
66-
67-
defp traits(user_category = %CodeCorps.UserCategory{}) do
68-
user_category = user_category |> CodeCorps.Repo.preload(:category)
151+
defp traits(%CodeCorps.TaskSkill{} = task_skill) do
152+
task_skill = task_skill |> Repo.preload([:skill, :task])
153+
%{
154+
skill: task_skill.skill.title,
155+
skill_id: task_skill.skill.id,
156+
task: task_skill.task.title
157+
}
158+
end
159+
defp traits(%CodeCorps.User{} = user) do
160+
%{
161+
admin: user.admin,
162+
biography: user.biography,
163+
created_at: user.inserted_at,
164+
email: user.email,
165+
first_name: user.first_name,
166+
github_id: user.github_id,
167+
github_username: user.github_username,
168+
last_name: user.last_name,
169+
sign_up_context: user.sign_up_context,
170+
state: user.state,
171+
twitter: user.twitter,
172+
type: user.type,
173+
username: user.username,
174+
website: user.website
175+
}
176+
end
177+
defp traits(%CodeCorps.UserCategory{} = user_category) do
178+
user_category = user_category |> Repo.preload(:category)
69179
%{
70180
category: user_category.category.name,
71181
category_id: user_category.category.id
72182
}
73183
end
74-
75-
defp traits(user_role = %CodeCorps.UserRole{}) do
76-
user_role = user_role |> CodeCorps.Repo.preload(:role)
184+
defp traits(%CodeCorps.UserRole{} = user_role) do
185+
user_role = user_role |> Repo.preload(:role)
77186
%{
78187
role: user_role.role.name,
79188
role_id: user_role.role.id
80189
}
81190
end
82-
83-
defp traits(user_skill = %CodeCorps.UserSkill{}) do
84-
user_skill = user_skill |> CodeCorps.Repo.preload(:skill)
191+
defp traits(%CodeCorps.UserSkill{} = user_skill) do
192+
user_skill = user_skill |> Repo.preload(:skill)
85193
%{
86194
skill: user_skill.skill.title,
87195
skill_id: user_skill.skill.id
88196
}
89197
end
198+
defp traits(%CodeCorps.UserTask{} = user_task) do
199+
user_task = user_task |> Repo.preload(:task)
90200

91-
defp traits(_), do: %{}
201+
%{
202+
task: user_task.task.title,
203+
task_id: user_task.task_id
204+
}
205+
end
206+
defp traits(%{token: _, user_id: _}), do: %{}
92207
end

lib/code_corps/model/task.ex

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ defmodule CodeCorps.Task do
33

44
import EctoOrdered
55

6-
alias CodeCorps.Services.MarkdownRendererService
6+
alias CodeCorps.{Task, Services.MarkdownRendererService}
77
alias Ecto.Changeset
88

99
@type t :: %__MODULE__{}
@@ -67,13 +67,15 @@ defmodule CodeCorps.Task do
6767
|> put_change(:status, "open")
6868
end
6969

70-
def update_changeset(struct, params) do
70+
@spec update_changeset(struct, map) :: Ecto.Changeset.t
71+
def update_changeset(struct, %{} = params) do
7172
struct
7273
|> changeset(params)
7374
|> cast(params, [:archived, :status])
7475
|> validate_inclusion(:status, statuses())
7576
|> set_closed_at()
7677
|> update_modified_at()
78+
|> maybe_assoc_with_repo(params)
7779
end
7880

7981
def apply_position(changeset) do
@@ -109,4 +111,15 @@ defmodule CodeCorps.Task do
109111
defp update_modified_at(changeset) do
110112
put_change(changeset, :modified_at, DateTime.utc_now)
111113
end
114+
115+
@spec maybe_assoc_with_repo(Changeset.t, map) :: Changeset.t
116+
defp maybe_assoc_with_repo(
117+
%Changeset{data: %Task{github_repo_id: nil}} = changeset,
118+
%{} = params) do
119+
120+
changeset
121+
|> cast(params, [:github_repo_id])
122+
|> assoc_constraint(:github_repo)
123+
end
124+
defp maybe_assoc_with_repo(%Changeset{} = changeset, %{}), do: changeset
112125
end

lib/code_corps/task/service.ex

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,6 @@ defmodule CodeCorps.Task.Service do
2222
end
2323

2424
@spec update(Task.t, map) :: {:ok, Task.t} | {:error, Changeset.t} | {:error, :github}
25-
def update(%Task{github_issue_id: nil} = task, %{} = attributes) do
26-
Multi.new
27-
|> Multi.update(:task, task |> Task.update_changeset(attributes))
28-
|> Repo.transaction
29-
|> marshall_result()
30-
end
3125
def update(%Task{} = task, %{} = attributes) do
3226
Multi.new
3327
|> Multi.update(:task, task |> Task.update_changeset(attributes))
@@ -64,7 +58,7 @@ defmodule CodeCorps.Task.Service do
6458
defp create_on_github(%Task{github_repo: _} = task) do
6559
with %Task{github_repo: github_repo} = task <- task |> Repo.preload(@preloads),
6660
{:ok, payload} <- GitHub.API.Issue.create(task),
67-
{:ok, %GithubIssue{} = github_issue } <- IssueGithubIssueSyncer.create_or_update_issue({github_repo, nil}, payload) do
61+
{:ok, %GithubIssue{} = github_issue} <- IssueGithubIssueSyncer.create_or_update_issue({github_repo, nil}, payload) do
6862
task |> link_with_github_changeset(github_issue) |> Repo.update
6963
else
7064
{:error, error} -> {:error, error}
@@ -77,12 +71,13 @@ defmodule CodeCorps.Task.Service do
7771
end
7872

7973
@spec update_on_github(Task.t) :: {:ok, Task.t} :: {:error, GitHub.api_error_struct}
80-
defp update_on_github(%Task{github_repo_id: nil} = task), do: {:ok, task}
74+
defp update_on_github(%Task{github_repo_id: nil, github_issue_id: nil} = task), do: {:ok, task}
75+
defp update_on_github(%Task{github_repo_id: _, github_issue_id: nil} = task), do: task |> create_on_github()
8176
defp update_on_github(%Task{github_repo_id: _} = task) do
8277
with %Task{github_repo: github_repo} = task <- task |> Repo.preload(@preloads),
8378
{:ok, payload} <- GitHub.API.Issue.update(task),
84-
{:ok, %GithubIssue{} } <- IssueGithubIssueSyncer.create_or_update_issue({github_repo, nil}, payload) do
85-
{:ok, task}
79+
{:ok, %GithubIssue{}} <- IssueGithubIssueSyncer.create_or_update_issue({github_repo, nil}, payload) do
80+
{:ok, Task |> Repo.get(task.id)}
8681
else
8782
{:error, github_error} -> {:error, github_error}
8883
end

lib/code_corps_web/controllers/github_app_installation_controller.ex

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ defmodule CodeCorpsWeb.GithubAppInstallationController do
44

55
import CodeCorps.Helpers.Query, only: [id_filter: 2]
66

7-
alias CodeCorps.{GithubAppInstallation, User}
7+
alias CodeCorps.{Analytics.SegmentTracker, GithubAppInstallation, User}
88

99
action_fallback CodeCorpsWeb.FallbackController
1010
plug CodeCorpsWeb.Plug.DataToAttributes
@@ -29,7 +29,14 @@ defmodule CodeCorpsWeb.GithubAppInstallationController do
2929
with %User{} = current_user <- conn |> Guardian.Plug.current_resource,
3030
{:ok, :authorized} <- current_user |> Policy.authorize(:create, %GithubAppInstallation{}, params),
3131
{:ok, %GithubAppInstallation{} = installation} <- %GithubAppInstallation{} |> GithubAppInstallation.create_changeset(params) |> Repo.insert do
32+
33+
current_user |> track_created(installation)
3234
conn |> put_status(:created) |> render("show.json-api", data: installation)
3335
end
3436
end
37+
38+
@spec track_created(User.t, GithubAppInstallation.t) :: any
39+
defp track_created(%User{id: user_id}, %GithubAppInstallation{} = installation) do
40+
user_id |> SegmentTracker.track("Created GitHub App Installation", installation)
41+
end
3542
end

lib/code_corps_web/controllers/project_github_repo_controller.ex

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ defmodule CodeCorpsWeb.ProjectGithubRepoController do
22
@moduledoc false
33
use CodeCorpsWeb, :controller
44

5-
alias CodeCorps.{ProjectGithubRepo, User, Helpers.Query}
5+
alias CodeCorps.{Analytics.SegmentTracker, ProjectGithubRepo, User, Helpers.Query}
66

77
action_fallback CodeCorpsWeb.FallbackController
88
plug CodeCorpsWeb.Plug.DataToAttributes
@@ -27,6 +27,9 @@ defmodule CodeCorpsWeb.ProjectGithubRepoController do
2727
with %User{} = current_user <- conn |> Guardian.Plug.current_resource,
2828
{:ok, :authorized} <- current_user |> Policy.authorize(:create, %ProjectGithubRepo{}, params),
2929
{:ok, %ProjectGithubRepo{} = project_github_repo} <- create_project_repo_changeset(params) |> Repo.insert do
30+
31+
current_user |> track_created(project_github_repo)
32+
3033
conn |> put_status(:created) |> render("show.json-api", data: project_github_repo)
3134
end
3235
end
@@ -36,7 +39,10 @@ defmodule CodeCorpsWeb.ProjectGithubRepoController do
3639
with %ProjectGithubRepo{} = project_github_repo <- ProjectGithubRepo |> Repo.get(id),
3740
%User{} = current_user <- conn |> Guardian.Plug.current_resource,
3841
{:ok, :authorized} <- current_user |> Policy.authorize(:delete, project_github_repo, params),
39-
{:ok, _project_github_repo} <- project_github_repo |> Repo.delete do
42+
{:ok, project_github_repo} <- project_github_repo |> Repo.delete do
43+
44+
current_user |> track_deleted(project_github_repo)
45+
4046
conn |> send_resp(:no_content, "")
4147
end
4248
end
@@ -46,4 +52,14 @@ defmodule CodeCorpsWeb.ProjectGithubRepoController do
4652
%ProjectGithubRepo{}
4753
|> ProjectGithubRepo.create_changeset(params)
4854
end
55+
56+
@spec track_created(User.t, ProjectGithubRepo.t) :: any
57+
defp track_created(%User{id: user_id}, %ProjectGithubRepo{} = project_github_repo) do
58+
user_id |> SegmentTracker.track("Connected GitHub Repo to Project", project_github_repo)
59+
end
60+
61+
@spec track_deleted(User.t, ProjectGithubRepo.t) :: any
62+
defp track_deleted(%User{id: user_id}, %ProjectGithubRepo{} = project_github_repo) do
63+
user_id |> SegmentTracker.track("Disconnected GitHub Repo from Project", project_github_repo)
64+
end
4965
end

0 commit comments

Comments
 (0)