Skip to content

Commit f7b2fbe

Browse files
authored
Merge pull request #998 from code-corps/888-modify-task-timestamps-for-github-sync
Modify Task timestamps for GitHub sync
2 parents de0bbf7 + 9e66661 commit f7b2fbe

10 files changed

Lines changed: 103 additions & 17 deletions

File tree

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
defmodule CodeCorps.GitHub.Adapters.Task do
22
@moduledoc """
33
Used to adapt a GitHub issue payload into attributes for creating or updating
4-
a `CodeCorps.Task`.
4+
a `CodeCorps.Task` and vice-versa.
55
"""
66

77
alias CodeCorps.{
@@ -10,22 +10,34 @@ defmodule CodeCorps.GitHub.Adapters.Task do
1010
}
1111

1212
@mapping [
13+
{:created_at, ["created_at"]},
1314
{:github_issue_number, ["number"]},
1415
{:markdown, ["body"]},
16+
{:modified_at, ["updated_at"]},
1517
{:status, ["state"]},
1618
{:title, ["title"]}
1719
]
1820

21+
@doc ~S"""
22+
Converts a GitHub issue payled into a set of attributes used to update or
23+
create a `Task` record.
24+
"""
1925
@spec from_issue(map) :: map
2026
def from_issue(%{} = payload) do
2127
payload |> MapTransformer.transform(@mapping)
2228
end
2329

30+
@autogenerated_github_keys ~w(created_at number updated_at)
31+
32+
@doc ~S"""
33+
Converts a `Task` into a set of attributes used to update or create an
34+
associated GitHub issue
35+
"""
2436
@spec to_issue(Task.t) :: map
2537
def to_issue(%Task{} = task) do
2638
task
2739
|> Map.from_struct
2840
|> MapTransformer.transform_inverse(@mapping)
29-
|> Map.delete("number")
41+
|> Map.drop(@autogenerated_github_keys)
3042
end
3143
end

lib/code_corps/github/event/issues/changeset_builder.ex

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@ defmodule CodeCorps.GitHub.Event.Issues.ChangesetBuilder do
1616
alias Ecto.Changeset
1717

1818
@doc ~S"""
19-
Constructs a changeset for syncing a task when processing an Issues webhook
19+
Constructs a changeset for syncing a `Task` when processing an Issues or
20+
IssueComment webhook.
21+
22+
The changeset can be used to create or update a `Task`
2023
"""
2124
@spec build_changeset(Task.t, map, ProjectGithubRepo.t, User.t) :: Changeset.t
2225
def build_changeset(
@@ -31,6 +34,8 @@ defmodule CodeCorps.GitHub.Event.Issues.ChangesetBuilder do
3134
end
3235
end
3336

37+
@create_attrs ~w(created_at github_issue_number markdown modified_at status title)a
38+
@spec create_changeset(Task.t, map, ProjectGithubRepo.t, User.t) :: Changeset.t
3439
defp create_changeset(
3540
%Task{} = task,
3641
%{} = issue_attrs,
@@ -41,8 +46,9 @@ defmodule CodeCorps.GitHub.Event.Issues.ChangesetBuilder do
4146
TaskList |> Repo.get_by(project_id: project_id, inbox: true)
4247

4348
task
44-
|> Changeset.change(TaskAdapter.from_issue(issue_attrs))
49+
|> Changeset.cast(TaskAdapter.from_issue(issue_attrs), @create_attrs)
4550
|> MarkdownRendererService.render_markdown_to_html(:markdown, :body)
51+
|> Changeset.put_change(:created_on, "github")
4652
|> Changeset.put_change(:github_repo_id, github_repo_id)
4753
|> Changeset.put_change(:project_id, project_id)
4854
|> Changeset.put_change(:task_list_id, task_list_id)
@@ -54,10 +60,13 @@ defmodule CodeCorps.GitHub.Event.Issues.ChangesetBuilder do
5460
|> Changeset.assoc_constraint(:user)
5561
end
5662

57-
defp update_changeset(%Task{} = task, issue_attrs) do
63+
@update_attrs ~w(github_issue_number markdown modified_at status title)a
64+
@spec update_changeset(Task.t, map) :: Changeset.t
65+
defp update_changeset(%Task{} = task, %{} = issue_attrs) do
5866
task
59-
|> Changeset.change(issue_attrs |> TaskAdapter.from_issue())
67+
|> Changeset.cast(TaskAdapter.from_issue(issue_attrs), @update_attrs)
6068
|> MarkdownRendererService.render_markdown_to_html(:markdown, :body)
69+
|> Changeset.put_change(:updated_on, "github")
6170
|> Changeset.validate_required([:project_id, :title, :user_id])
6271
|> Changeset.assoc_constraint(:github_repo)
6372
|> Changeset.assoc_constraint(:project)

lib/code_corps/model/task.ex

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,13 @@ defmodule CodeCorps.Task do
99
@type t :: %__MODULE__{}
1010

1111
schema "tasks" do
12-
field :closed_at, :utc_datetime
1312
field :body, :string
13+
field :closed_at, :utc_datetime
14+
field :created_at, :utc_datetime
15+
field :created_from, :string, default: "code_corps"
1416
field :markdown, :string
17+
field :modified_at, :utc_datetime
18+
field :modified_from, :string, default: "code_corps"
1519
field :number, :integer, read_after_writes: true
1620
field :order, :integer
1721
field :status, :string, default: "open"
@@ -48,6 +52,7 @@ defmodule CodeCorps.Task do
4852
struct
4953
|> changeset(params)
5054
|> cast(params, [:project_id, :user_id, :github_repo_id])
55+
|> set_created_and_modified_at()
5156
|> validate_required([:project_id, :user_id])
5257
|> assoc_constraint(:project)
5358
|> assoc_constraint(:user)
@@ -61,6 +66,7 @@ defmodule CodeCorps.Task do
6166
|> cast(params, [:status])
6267
|> validate_inclusion(:status, statuses())
6368
|> set_closed_at()
69+
|> update_modified_at()
6470
end
6571

6672
def apply_position(changeset) do
@@ -79,10 +85,21 @@ defmodule CodeCorps.Task do
7985
case changeset do
8086
%Changeset{valid?: true, changes: %{status: "closed"}} ->
8187
put_change(changeset, :closed_at, DateTime.utc_now)
82-
%Changeset{valid?: true, changes: %{status: "open"}} ->
88+
%Changeset{valid?: true, changes: %{status: "open"}} ->
8389
put_change(changeset, :closed_at, nil)
8490
_ ->
8591
changeset
86-
end
92+
end
93+
end
94+
95+
defp set_created_and_modified_at(changeset) do
96+
now = DateTime.utc_now
97+
changeset
98+
|> put_change(:created_at, now)
99+
|> put_change(:modified_at, now)
100+
end
101+
102+
defp update_modified_at(changeset) do
103+
put_change(changeset, :modified_at, DateTime.utc_now)
87104
end
88105
end

lib/code_corps_web/views/task_view.ex

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ defmodule CodeCorpsWeb.TaskView do
44
use CodeCorpsWeb, :view
55
use JaSerializer.PhoenixView
66

7-
attributes ~w(body markdown number status title order inserted_at updated_at)a
7+
attributes ~w(
8+
body created_at inserted_at markdown modified_at number order status title
9+
updated_at
10+
)a
811

912
has_one :github_repo, serializer: CodeCorpsWeb.GithubRepoView
1013
has_one :project, serializer: CodeCorpsWeb.ProjectView
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
defmodule CodeCorps.Repo.Migrations.AddCreatedAtAndModifiedAtToTasks do
2+
use Ecto.Migration
3+
4+
def change do
5+
alter table(:tasks) do
6+
add :created_at, :utc_datetime
7+
add :modified_at, :utc_datetime
8+
add :created_from, :string, default: "code_corps"
9+
add :modified_from, :string, default: "code_corps"
10+
end
11+
end
12+
end

priv/repo/structure.sql

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1368,7 +1368,11 @@ CREATE TABLE tasks (
13681368
"order" integer,
13691369
github_issue_number integer,
13701370
github_repo_id bigint,
1371-
closed_at timestamp without time zone
1371+
closed_at timestamp without time zone,
1372+
created_at timestamp without time zone,
1373+
modified_at timestamp without time zone,
1374+
created_from character varying(255) DEFAULT 'code_corps'::character varying,
1375+
modified_from character varying(255) DEFAULT 'code_corps'::character varying
13721376
);
13731377

13741378

@@ -3036,5 +3040,5 @@ ALTER TABLE ONLY user_tasks
30363040
-- PostgreSQL database dump complete
30373041
--
30383042

3039-
INSERT INTO "schema_migrations" (version) VALUES (20160723215749), (20160804000000), (20160804001111), (20160805132301), (20160805203929), (20160808143454), (20160809214736), (20160810124357), (20160815125009), (20160815143002), (20160816020347), (20160816034021), (20160817220118), (20160818000944), (20160818132546), (20160820113856), (20160820164905), (20160822002438), (20160822004056), (20160822011624), (20160822020401), (20160822044612), (20160830081224), (20160830224802), (20160911233738), (20160912002705), (20160912145957), (20160918003206), (20160928232404), (20161003185918), (20161019090945), (20161019110737), (20161020144622), (20161021131026), (20161031001615), (20161121005339), (20161121014050), (20161121043941), (20161121045709), (20161122015942), (20161123081114), (20161123150943), (20161124085742), (20161125200620), (20161126045705), (20161127054559), (20161205024856), (20161207112519), (20161209192504), (20161212005641), (20161214005935), (20161215052051), (20161216051447), (20161218005913), (20161219160401), (20161219163909), (20161220141753), (20161221085759), (20161226213600), (20161231063614), (20170102130055), (20170102181053), (20170104113708), (20170104212623), (20170104235423), (20170106013143), (20170115035159), (20170115230549), (20170121014100), (20170131234029), (20170201014901), (20170201025454), (20170201035458), (20170201183258), (20170220032224), (20170224233516), (20170226050552), (20170228085250), (20170308214128), (20170308220713), (20170308222552), (20170313130611), (20170318032449), (20170318082740), (20170324194827), (20170424215355), (20170501225441), (20170505224222), (20170526095401), (20170602000208), (20170622205732), (20170626231059), (20170628092119), (20170628213609), (20170629183404), (20170630140136), (20170706132431), (20170707213648), (20170711122252), (20170717092127), (20170725060612), (20170727052644), (20170731130121), (20170814131722), (20170913114958), (20170921014405), (20170925214512), (20170925230419), (20170926134646), (20170927100300);
3043+
INSERT INTO "schema_migrations" (version) VALUES (20160723215749), (20160804000000), (20160804001111), (20160805132301), (20160805203929), (20160808143454), (20160809214736), (20160810124357), (20160815125009), (20160815143002), (20160816020347), (20160816034021), (20160817220118), (20160818000944), (20160818132546), (20160820113856), (20160820164905), (20160822002438), (20160822004056), (20160822011624), (20160822020401), (20160822044612), (20160830081224), (20160830224802), (20160911233738), (20160912002705), (20160912145957), (20160918003206), (20160928232404), (20161003185918), (20161019090945), (20161019110737), (20161020144622), (20161021131026), (20161031001615), (20161121005339), (20161121014050), (20161121043941), (20161121045709), (20161122015942), (20161123081114), (20161123150943), (20161124085742), (20161125200620), (20161126045705), (20161127054559), (20161205024856), (20161207112519), (20161209192504), (20161212005641), (20161214005935), (20161215052051), (20161216051447), (20161218005913), (20161219160401), (20161219163909), (20161220141753), (20161221085759), (20161226213600), (20161231063614), (20170102130055), (20170102181053), (20170104113708), (20170104212623), (20170104235423), (20170106013143), (20170115035159), (20170115230549), (20170121014100), (20170131234029), (20170201014901), (20170201025454), (20170201035458), (20170201183258), (20170220032224), (20170224233516), (20170226050552), (20170228085250), (20170308214128), (20170308220713), (20170308222552), (20170313130611), (20170318032449), (20170318082740), (20170324194827), (20170424215355), (20170501225441), (20170505224222), (20170526095401), (20170602000208), (20170622205732), (20170626231059), (20170628092119), (20170628213609), (20170629183404), (20170630140136), (20170706132431), (20170707213648), (20170711122252), (20170717092127), (20170725060612), (20170727052644), (20170731130121), (20170814131722), (20170913114958), (20170921014405), (20170925214512), (20170925230419), (20170926134646), (20170927100300), (20170928234412);
30403044

test/lib/code_corps/github/adapters/task_test.exs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@ defmodule CodeCorps.GitHub.Adapters.TaskTest do
1212
%{"issue" => payload} = load_event_fixture("issues_opened")
1313

1414
assert Adapters.Task.from_issue(payload) == %{
15+
created_at: payload["created_at"],
1516
github_issue_number: payload["number"],
16-
title: payload["title"],
1717
markdown: payload["body"],
18+
modified_at: payload["updated_at"],
19+
title: payload["title"],
1820
status: payload["state"]
1921
}
2022
end
@@ -26,10 +28,12 @@ defmodule CodeCorps.GitHub.Adapters.TaskTest do
2628
%Task{number: 5, title: "Foo", markdown: "bar", status: "open"}
2729
|> Adapters.Task.to_issue
2830

29-
assert payload["title"] == "Foo"
3031
assert payload["body"] == "bar"
3132
assert payload["state"] == "open"
33+
assert payload["title"] == "Foo"
34+
refute payload["created_at"]
3235
refute payload["number"]
36+
refute payload["updated_at"]
3337
end
3438
end
3539
end

test/lib/code_corps/github/event/issues/changeset_builder_test.exs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,21 @@ defmodule CodeCorps.GitHub.Event.Issues.ChangesetBuilderTest do
2424
task, payload, project_github_repo, user
2525
)
2626

27+
{:ok, created_at, _} = payload["issue"]["created_at"] |> DateTime.from_iso8601()
28+
{:ok, updated_at, _} = payload["issue"]["updated_at"] |> DateTime.from_iso8601()
29+
2730
# adapted fields
28-
assert get_change(changeset, :name) == payload["issue"]["name"]
31+
assert get_change(changeset, :created_at) == created_at
2932
assert get_change(changeset, :github_issue_number) == payload["issue"]["number"]
3033
assert get_change(changeset, :markdown) == payload["issue"]["body"]
34+
assert get_change(changeset, :modified_at) == updated_at
35+
assert get_change(changeset, :name) == payload["issue"]["name"]
3136
assert get_field(changeset, :status) == payload["issue"]["state"]
3237

33-
# html was rendered
38+
# markdown was rendered into html
3439
assert get_change(changeset, :body) ==
35-
Earmark.as_html!(payload["issue"]["body"], %Earmark.Options{code_class_prefix: "language-"})
40+
payload["issue"]["body"]
41+
|> Earmark.as_html!(%Earmark.Options{code_class_prefix: "language-"})
3642

3743
# relationships are proper
3844
assert get_change(changeset, :github_repo_id) == project_github_repo.github_repo_id

test/lib/code_corps/model/task_test.exs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,23 @@ defmodule CodeCorps.TaskTest do
3131
end
3232
end
3333

34+
describe "create_changeset/2" do
35+
test "sets created_at and modified_at to the same time" do
36+
project = insert(:project)
37+
task_list = insert(:task_list)
38+
user = insert(:user)
39+
changes = Map.merge(@valid_attrs, %{
40+
project_id: project.id,
41+
task_list_id: task_list.id,
42+
user_id: user.id
43+
})
44+
changeset = Task.create_changeset(%Task{}, changes)
45+
assert changeset.valid?
46+
{:ok, %Task{created_at: created_at, modified_at: modified_at}} = Repo.insert(changeset)
47+
assert created_at == modified_at
48+
end
49+
end
50+
3451
describe "update_changeset/2" do
3552
test "only allows specific values for status" do
3653
changes = Map.put(@valid_attrs, :status, "nonexistent")

test/lib/code_corps_web/views/task_view_test.exs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@ defmodule CodeCorpsWeb.TaskViewTest do
1414
"data" => %{
1515
"attributes" => %{
1616
"body" => task.body,
17+
"created-at" => task.created_at,
1718
"inserted-at" => task.inserted_at,
1819
"markdown" => task.markdown,
20+
"modified-at" => task.modified_at,
1921
"number" => task.number,
2022
"order" => task.order,
2123
"status" => task.status,

0 commit comments

Comments
 (0)