Skip to content

Commit e5505ec

Browse files
committed
Add github-events index and show endpoints
- Add pagination - Add admin to the user view
1 parent 6d9c919 commit e5505ec

File tree

14 files changed

+289
-90
lines changed

14 files changed

+289
-90
lines changed

lib/code_corps/model/github_event.ex

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
defmodule CodeCorps.GithubEvent do
22
use CodeCorps.Model
3+
use Scrivener, page_size: 20
34

45
@type t :: %__MODULE__{}
56

67
schema "github_events" do
78
field :action, :string
9+
field :failure_reason, :string
810
field :github_delivery_id, :string
911
field :payload, :map
1012
field :status, :string
1113
field :type, :string
12-
field :failure_reason, :string
1314

1415
timestamps()
1516
end
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
defmodule CodeCorps.Policy.GithubEvent do
2+
alias CodeCorps.User
3+
4+
def index?(%User{admin: true}), do: true
5+
def index?(%User{admin: false}), do: false
6+
7+
def show?(%User{admin: true}), do: true
8+
def show?(%User{admin: false}), do: false
9+
end

lib/code_corps/policy/policy.ex

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ defmodule CodeCorps.Policy do
33
Handles authorization for various API actions performed on objects in the database.
44
"""
55

6-
alias CodeCorps.{Category, Comment, DonationGoal, GithubAppInstallation, Organization, OrganizationInvite, OrganizationGithubAppInstallation, Preview, Project, ProjectCategory, ProjectGithubRepo, ProjectSkill, ProjectUser, Role, RoleSkill, Skill, StripeConnectAccount, StripeConnectPlan, StripeConnectSubscription, StripePlatformCard, StripePlatformCustomer, Task, TaskSkill, User, UserCategory, UserRole, UserSkill, UserTask}
6+
alias CodeCorps.{Category, Comment, DonationGoal, GithubAppInstallation, GithubEvent, Organization, OrganizationInvite, OrganizationGithubAppInstallation, Preview, Project, ProjectCategory, ProjectGithubRepo, ProjectSkill, ProjectUser, Role, RoleSkill, Skill, StripeConnectAccount, StripeConnectPlan, StripeConnectSubscription, StripePlatformCard, StripePlatformCustomer, Task, TaskSkill, User, UserCategory, UserRole, UserSkill, UserTask}
77

88
alias CodeCorps.Policy
99

@@ -40,6 +40,10 @@ defmodule CodeCorps.Policy do
4040
# GithubAppInstallation
4141
defp can?(%User{} = current_user, :create, %GithubAppInstallation{}, %{} = params), do: Policy.GithubAppInstallation.create?(current_user, params)
4242

43+
# GithubEvent
44+
defp can?(%User{} = current_user, :index, %GithubEvent{}, %{}), do: Policy.GithubEvent.index?(current_user)
45+
defp can?(%User{} = current_user, :show, %GithubEvent{}, %{}), do: Policy.GithubEvent.show?(current_user)
46+
4347
# Organization
4448
defp can?(%User{} = current_user, :create, %Organization{}, %{}), do: Policy.Organization.create?(current_user)
4549
defp can?(%User{} = current_user, :update, %Organization{} = organization, %{}), do: Policy.Organization.update?(current_user, organization)
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
defmodule CodeCorpsWeb.GithubEventController do
2+
@moduledoc false
3+
use CodeCorpsWeb, :controller
4+
5+
alias CodeCorps.{GithubEvent, Helpers.Query, Repo, User}
6+
alias CodeCorps.GitHub.Webhook.{
7+
EventSupport, Processor
8+
}
9+
10+
action_fallback CodeCorpsWeb.FallbackController
11+
plug CodeCorpsWeb.Plug.DataToAttributes
12+
plug CodeCorpsWeb.Plug.IdsToIntegers
13+
14+
@spec index(Conn.t, map) :: Conn.t
15+
def index(%Conn{} = conn, %{} = params) do
16+
with %User{} = current_user <- conn |> Guardian.Plug.current_resource,
17+
{:ok, :authorized} <- current_user |> Policy.authorize(:index, %GithubEvent{}, params)
18+
do
19+
github_events =
20+
GithubEvent
21+
|> Query.id_filter(params)
22+
|> paginate(params)
23+
24+
conn |> render("index.json-api", data: github_events)
25+
end
26+
end
27+
28+
@spec show(Conn.t, map) :: Conn.t
29+
def show(%Conn{} = conn, %{"id" => id} = params) do
30+
with %User{} = current_user <- conn |> Guardian.Plug.current_resource,
31+
%GithubEvent{} = github_event <- GithubEvent |> Repo.get(id),
32+
{:ok, :authorized} <- current_user |> Policy.authorize(:show, github_event, params)
33+
do
34+
conn |> render("show.json-api", data: github_event)
35+
end
36+
end
37+
38+
def create(conn, event_payload) do
39+
event_type = conn |> get_event_type()
40+
41+
case event_type |> EventSupport.status do
42+
:supported ->
43+
Processor.process_async(event_type, conn |> get_delivery_id, event_payload)
44+
conn |> send_resp(200, "")
45+
:unsupported ->
46+
conn |> send_resp(202, "")
47+
end
48+
end
49+
50+
defp get_event_type(conn) do
51+
conn |> get_req_header("x-github-event") |> List.first
52+
end
53+
54+
defp get_delivery_id(conn) do
55+
conn |> get_req_header("x-github-delivery") |> List.first
56+
end
57+
58+
@spec paginate(Ecto.Queryable.t, map) :: list(GithubEvent.t)
59+
defp paginate(query, %{"page" => page_params}) do
60+
query |> Repo.paginate(page_params)
61+
end
62+
defp paginate(query, _) do
63+
query |> Repo.all()
64+
end
65+
end

lib/code_corps_web/controllers/github_events_controller.ex

Lines changed: 0 additions & 28 deletions
This file was deleted.

lib/code_corps_web/router.ex

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ defmodule CodeCorpsWeb.Router do
5959
scope "/", CodeCorpsWeb, host: "api." do
6060
pipe_through [:github_webhooks]
6161

62-
post "/webhooks/github", GitHubEventsController, :create, as: :github_events
62+
post "/webhooks/github", GithubEventController, :create, as: :github_events
6363
end
6464

6565
scope "/", CodeCorpsWeb, host: "api." do
@@ -70,6 +70,7 @@ defmodule CodeCorpsWeb.Router do
7070
resources "/donation-goals", DonationGoalController, only: [:create, :update, :delete]
7171
post "/oauth/github", UserController, :github_oauth
7272
resources "/github-app-installations", GithubAppInstallationController, only: [:create]
73+
resources "/github-events", GithubEventController, only: [:index, :show]
7374
resources "/organization-github-app-installations", OrganizationGithubAppInstallationController, only: [:create, :delete]
7475
resources "/organizations", OrganizationController, only: [:create, :update]
7576
resources "/organization-invites", OrganizationInviteController, only: [:create, :update]
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
defmodule CodeCorpsWeb.GithubEventView do
2+
@moduledoc false
3+
use CodeCorpsWeb, :view
4+
use JaSerializer.PhoenixView
5+
6+
attributes [
7+
:action, :event_type, :failure_reason, :github_delivery_id, :inserted_at,
8+
:payload, :status, :updated_at
9+
]
10+
11+
def event_type(github_event, _conn) do
12+
github_event.type
13+
end
14+
end

lib/code_corps_web/views/user_view.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ defmodule CodeCorpsWeb.UserView do
66
use JaSerializer.PhoenixView
77

88
attributes [
9-
:biography, :cloudinary_public_id, :email, :first_name,
9+
:admin, :biography, :cloudinary_public_id, :email, :first_name,
1010
:github_avatar_url, :github_id, :github_username, :intercom_user_hash,
1111
:inserted_at, :last_name, :name, :photo_large_url, :photo_thumb_url,
1212
:sign_up_context, :state, :state_transition, :twitter, :username,
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
defmodule CodeCorps.GithubEventPolicyTest do
2+
use CodeCorps.PolicyCase
3+
4+
import CodeCorps.Policy.GithubEvent, only: [index?: 1, show?: 1]
5+
6+
describe "index" do
7+
test "returns true when user is an admin" do
8+
user = build(:user, admin: true)
9+
assert index?(user)
10+
end
11+
12+
test "returns false when user is not an admin" do
13+
user = build(:user, admin: false)
14+
refute index?(user)
15+
end
16+
end
17+
18+
describe "show" do
19+
test "returns true when user is an admin" do
20+
user = insert(:user, admin: true)
21+
assert show?(user)
22+
end
23+
24+
test "returns false when user is not an admin" do
25+
user = insert(:user, admin: false)
26+
refute show?(user)
27+
end
28+
end
29+
end
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
defmodule CodeCorpsWeb.GithubEventControllerTest do
2+
@moduledoc false
3+
4+
use CodeCorpsWeb.ApiCase, resource_name: :github_event
5+
use CodeCorps.BackgroundProcessingCase
6+
7+
import CodeCorps.GitHub.TestHelpers
8+
9+
alias CodeCorps.GithubEvent
10+
11+
defp for_event(conn, type, id) do
12+
conn
13+
|> put_req_header("x-github-event", type)
14+
|> put_req_header("x-github-delivery", id)
15+
end
16+
17+
describe "index" do
18+
@tag authenticated: :admin
19+
test "paginates on index", %{conn: conn} do
20+
[_github_event_1, github_event_2] = insert_pair(:github_event)
21+
22+
path = "github-events/?page[page]=2&page[page-size]=1"
23+
24+
conn
25+
|> get(path)
26+
|> json_response(200)
27+
|> assert_ids_from_response([github_event_2.id])
28+
end
29+
30+
@tag authenticated: :admin
31+
test "lists all entries on index", %{conn: conn} do
32+
[github_event_1, github_event_2] = insert_pair(:github_event)
33+
34+
conn
35+
|> request_index
36+
|> json_response(200)
37+
|> assert_ids_from_response([github_event_1.id, github_event_2.id])
38+
end
39+
40+
@tag authenticated: :admin
41+
test "filters resources on index", %{conn: conn} do
42+
[github_event_1, github_event_2 | _] = insert_list(3, :github_event)
43+
44+
path = "github-events/?filter[id]=#{github_event_1.id},#{github_event_2.id}"
45+
46+
conn
47+
|> get(path)
48+
|> json_response(200)
49+
|> assert_ids_from_response([github_event_1.id, github_event_2.id])
50+
end
51+
52+
test "renders 401 when unauthenticated", %{conn: conn} do
53+
assert conn |> request_index() |> json_response(401)
54+
end
55+
56+
@tag :authenticated
57+
test "renders 403 when unauthorized", %{conn: conn} do
58+
assert conn |> request_index() |> json_response(403)
59+
end
60+
end
61+
62+
describe "show" do
63+
@tag authenticated: :admin
64+
test "shows chosen resource", %{conn: conn} do
65+
github_event = insert(:github_event)
66+
67+
conn
68+
|> request_show(github_event)
69+
|> json_response(200)
70+
|> assert_id_from_response(github_event.id)
71+
end
72+
73+
test "renders 401 when unauthenticated", %{conn: conn} do
74+
github_event = insert(:github_event)
75+
assert conn |> request_show(github_event) |> json_response(401)
76+
end
77+
78+
@tag :authenticated
79+
test "renders 403 when unauthorized", %{conn: conn} do
80+
github_event = insert(:github_event)
81+
assert conn |> request_show(github_event) |> json_response(403)
82+
end
83+
end
84+
85+
describe "create" do
86+
@tag :github_webhook
87+
test "responds with 200 for a supported event", %{conn: conn} do
88+
path = conn |> github_events_path(:create)
89+
90+
payload = load_event_fixture("installation_created")
91+
assert conn |> for_event("installation", "foo") |> post(path, payload) |> response(200)
92+
93+
wait_for_supervisor()
94+
95+
assert Repo.get_by(GithubEvent, github_delivery_id: "foo")
96+
end
97+
98+
@tag :github_webhook
99+
test "responds with 202 for an unsupported event", %{conn: conn} do
100+
path = conn |> github_events_path(:create)
101+
assert conn |> for_event("gollum", "foo") |> post(path, %{}) |> response(202)
102+
103+
wait_for_supervisor()
104+
105+
refute Repo.get_by(GithubEvent, github_delivery_id: "foo")
106+
end
107+
108+
@tag :github_webhook
109+
test "responds with 202 for an unknown event", %{conn: conn} do
110+
path = conn |> github_events_path(:create)
111+
assert conn |> for_event("unknown", "foo") |> post(path, %{}) |> response(202)
112+
113+
wait_for_supervisor()
114+
115+
refute Repo.get_by(GithubEvent, github_delivery_id: "foo")
116+
end
117+
end
118+
end

0 commit comments

Comments
 (0)