Skip to content

Commit 79b92aa

Browse files
authored
Merge pull request #1298 from code-corps/1287-add-conversation-show
Add conversation show endpoint
2 parents 9cc48a3 + 4f32e52 commit 79b92aa

File tree

10 files changed

+140
-6
lines changed

10 files changed

+140
-6
lines changed

lib/code_corps/messages/messages.ex

+8
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,14 @@ defmodule CodeCorps.Messages do
2929
|> Repo.all()
3030
end
3131

32+
@doc ~S"""
33+
Gets a `CodeCorps.Conversation` record
34+
"""
35+
@spec get_conversation(integer) :: Conversation.t
36+
def get_conversation(id) do
37+
Conversation |> Repo.get(id)
38+
end
39+
3240
@doc ~S"""
3341
Creates a `CodeCorps.Message` from a set of parameters.
3442
"""

lib/code_corps/policy/conversation.ex

+12-1
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@ defmodule CodeCorps.Policy.Conversation do
44
records.
55
"""
66

7+
import CodeCorps.Policy.Helpers,
8+
only: [administered_by?: 2, get_message: 1, get_project: 1]
79
import Ecto.Query
810

9-
alias CodeCorps.{Message, Policy, Repo, User}
11+
alias CodeCorps.{Conversation, Message, Policy, Repo, User}
1012

1113
@spec scope(Ecto.Queryable.t, User.t) :: Ecto.Queryable.t
1214
def scope(queryable, %User{admin: true}), do: queryable
@@ -21,4 +23,13 @@ defmodule CodeCorps.Policy.Conversation do
2123
|> where(user_id: ^id)
2224
|> or_where([c], c.message_id in ^scoped_message_ids)
2325
end
26+
27+
def show?(%User{id: user_id}, %Conversation{user_id: target_user_id})
28+
when user_id == target_user_id do
29+
true
30+
end
31+
def show?(%User{} = user, %Conversation{} = conversation) do
32+
conversation |> get_message() |> get_project() |> administered_by?(user)
33+
end
34+
def show?(_, _), do: false
2435
end

lib/code_corps/policy/helpers.ex

+10
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ defmodule CodeCorps.Policy.Helpers do
55
"""
66

77
alias CodeCorps.{
8+
Conversation,
9+
Message,
810
Organization,
911
ProjectUser,
1012
Project,
@@ -98,6 +100,14 @@ defmodule CodeCorps.Policy.Helpers do
98100
defp owner?("owner"), do: true
99101
defp owner?(_), do: false
100102

103+
@doc """
104+
Retrieves message from associated record
105+
"""
106+
@spec get_message(Changeset.t() | Conversation.t() | map) :: Message.t()
107+
def get_message(%Conversation{message_id: message_id}), do: Repo.get(Message, message_id)
108+
def get_message(%{"message_id" => message_id}), do: Repo.get(Message, message_id)
109+
def get_message(%Changeset{changes: %{message_id: message_id}}), do: Repo.get(Message, message_id)
110+
101111
@doc """
102112
Retrieves task from associated record
103113
"""

lib/code_corps/policy/policy.ex

+3
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ defmodule CodeCorps.Policy do
4040
defp can?(%User{} = current_user, :create, %Comment{}, %{} = params), do: Policy.Comment.create?(current_user, params)
4141
defp can?(%User{} = current_user, :update, %Comment{} = comment, %{}), do: Policy.Comment.update?(current_user, comment)
4242

43+
# Conversation
44+
defp can?(%User{} = current_user, :show, %Conversation{} = conversation, %{}), do: Policy.Conversation.show?(current_user, conversation)
45+
4346
# DonationGoal
4447
defp can?(%User{} = current_user, :create, %DonationGoal{}, %{} = params), do: Policy.DonationGoal.create?(current_user, params)
4548
defp can?(%User{} = current_user, :update, %DonationGoal{} = donation_goal, %{}), do: Policy.DonationGoal.update?(current_user, donation_goal)

lib/code_corps_web/controllers/conversation_controller.ex

+9
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,13 @@ defmodule CodeCorpsWeb.ConversationController do
1919
conn |> render("index.json-api", data: conversations)
2020
end
2121
end
22+
23+
@spec show(Conn.t, map) :: Conn.t
24+
def show(%Conn{} = conn, %{"id" => id}) do
25+
with %User{} = current_user <- conn |> CodeCorps.Guardian.Plug.current_resource,
26+
%Conversation{} = conversation <- Messages.get_conversation(id),
27+
{:ok, :authorized} <- current_user |> Policy.authorize(:show, conversation, %{}) do
28+
conn |> render("show.json-api", data: conversation)
29+
end
30+
end
2231
end

lib/code_corps_web/router.ex

+1-1
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ defmodule CodeCorpsWeb.Router do
7171

7272
resources "/categories", CategoryController, only: [:create, :update]
7373
resources "/comments", CommentController, only: [:create, :update]
74-
resources "/conversations", ConversationController, only: [:index]
74+
resources "/conversations", ConversationController, only: [:index, :show]
7575
resources "/donation-goals", DonationGoalController, only: [:create, :update, :delete]
7676
post "/oauth/github", UserController, :github_oauth
7777
resources "/github-app-installations", GithubAppInstallationController, only: [:create]

test/lib/code_corps/helpers/policy_test.exs

+21-3
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@ defmodule CodeCorps.Policy.HelpersTest do
5454
end
5555

5656
describe "administered_by?/2" do
57-
5857
test "returns false if given invalid arguments" do
5958
refute Helpers.administered_by?(nil, 2)
6059
end
@@ -81,7 +80,6 @@ defmodule CodeCorps.Policy.HelpersTest do
8180
end
8281

8382
describe "contributed_by?/2" do
84-
8583
test "returns false if given invalid arguments" do
8684
refute Helpers.contributed_by?(nil, 2)
8785
end
@@ -133,6 +131,27 @@ defmodule CodeCorps.Policy.HelpersTest do
133131
end
134132
end
135133

134+
describe "get_message/1" do
135+
test "should return message of a map" do
136+
message = insert(:message)
137+
result = Helpers.get_message(%{"message_id" => message.id})
138+
assert result.id == message.id
139+
end
140+
141+
test "should return message of a Conversation" do
142+
message = insert(:message)
143+
conversation = insert(:conversation, message: message)
144+
result = Helpers.get_message(conversation)
145+
assert result.id == message.id
146+
end
147+
148+
test "should return message of a Changeset" do
149+
message = insert(:message)
150+
changeset = %Changeset{changes: %{message_id: message.id}}
151+
result = Helpers.get_message(changeset)
152+
assert result.id == message.id
153+
end
154+
end
136155

137156
describe "get_project/1" do
138157
test "return project if the project_id is defined on the struct" do
@@ -219,5 +238,4 @@ defmodule CodeCorps.Policy.HelpersTest do
219238
refute Helpers.task_authored_by?(task, other_user)
220239
end
221240
end
222-
223241
end

test/lib/code_corps/messages/messages_test.exs

+10
Original file line numberDiff line numberDiff line change
@@ -282,4 +282,14 @@ defmodule CodeCorps.MessagesTest do
282282
assert other_conversation_started_by_admin_with_reply.id in result_ids
283283
end
284284
end
285+
286+
describe "get_conversation/1" do
287+
test "gets a single conversation" do
288+
conversation = insert(:conversation)
289+
290+
result = Messages.get_conversation(conversation.id)
291+
292+
assert result.id == conversation.id
293+
end
294+
end
285295
end

test/lib/code_corps/policy/conversation_test.exs

+43-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
defmodule CodeCorps.Policy.ConversationTest do
22
use CodeCorps.PolicyCase
33

4-
import CodeCorps.Policy.Conversation, only: [scope: 2]
4+
import CodeCorps.Policy.Conversation, only: [scope: 2, show?: 2]
55

66
alias CodeCorps.{Conversation, Repo}
77

@@ -71,4 +71,46 @@ defmodule CodeCorps.Policy.ConversationTest do
7171
refute some_other_conversation.id in result_ids
7272
end
7373
end
74+
75+
describe "show?" do
76+
test "returns true when user is the target" do
77+
user = insert(:user)
78+
message = insert(:message)
79+
conversation = insert(:conversation, message: message, user: user)
80+
81+
assert show?(user, conversation)
82+
end
83+
84+
test "returns false when user is a pending project member" do
85+
%{project: project, user: user} = insert(:project_user, role: "pending")
86+
message = insert(:message, project: project)
87+
conversation = insert(:conversation, message: message)
88+
89+
refute show?(user, conversation)
90+
end
91+
92+
test "returns false when user is a project contributor" do
93+
%{project: project, user: user} = insert(:project_user, role: "contributor")
94+
message = insert(:message, project: project)
95+
conversation = insert(:conversation, message: message)
96+
97+
refute show?(user, conversation)
98+
end
99+
100+
test "returns true when user is a project admin" do
101+
%{project: project, user: user} = insert(:project_user, role: "admin")
102+
message = insert(:message, project: project)
103+
conversation = insert(:conversation, message: message)
104+
105+
assert show?(user, conversation)
106+
end
107+
108+
test "returns true when user is project owner" do
109+
%{project: project, user: user} = insert(:project_user, role: "owner")
110+
message = insert(:message, project: project)
111+
conversation = insert(:conversation, message: message)
112+
113+
assert show?(user, conversation)
114+
end
115+
end
74116
end

test/lib/code_corps_web/controllers/conversation_controller_test.exs

+23
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,27 @@ defmodule CodeCorpsWeb.ConversationControllerTest do
3030
|> assert_ids_from_response([conversation_1.id, conversation_2.id])
3131
end
3232
end
33+
34+
describe "show" do
35+
@tag :authenticated
36+
test "shows chosen resource", %{conn: conn, current_user: user} do
37+
conversation = insert(:conversation, user: user)
38+
39+
conn
40+
|> request_show(conversation)
41+
|> json_response(200)
42+
|> assert_id_from_response(conversation.id)
43+
end
44+
45+
test "renders 401 when unauthenticated", %{conn: conn} do
46+
conversation = insert(:conversation)
47+
assert conn |> request_show(conversation) |> json_response(401)
48+
end
49+
50+
@tag :authenticated
51+
test "renders 403 when unauthorized", %{conn: conn} do
52+
conversation = insert(:conversation)
53+
assert conn |> request_show(conversation) |> json_response(403)
54+
end
55+
end
3356
end

0 commit comments

Comments
 (0)