Skip to content

Commit

Permalink
Merge pull request #1298 from code-corps/1287-add-conversation-show
Browse files Browse the repository at this point in the history
Add conversation show endpoint
  • Loading branch information
joshsmith authored Dec 15, 2017
2 parents 9cc48a3 + 4f32e52 commit 79b92aa
Show file tree
Hide file tree
Showing 10 changed files with 140 additions and 6 deletions.
8 changes: 8 additions & 0 deletions lib/code_corps/messages/messages.ex
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ defmodule CodeCorps.Messages do
|> Repo.all()
end

@doc ~S"""
Gets a `CodeCorps.Conversation` record
"""
@spec get_conversation(integer) :: Conversation.t
def get_conversation(id) do
Conversation |> Repo.get(id)
end

@doc ~S"""
Creates a `CodeCorps.Message` from a set of parameters.
"""
Expand Down
13 changes: 12 additions & 1 deletion lib/code_corps/policy/conversation.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ defmodule CodeCorps.Policy.Conversation do
records.
"""

import CodeCorps.Policy.Helpers,
only: [administered_by?: 2, get_message: 1, get_project: 1]
import Ecto.Query

alias CodeCorps.{Message, Policy, Repo, User}
alias CodeCorps.{Conversation, Message, Policy, Repo, User}

@spec scope(Ecto.Queryable.t, User.t) :: Ecto.Queryable.t
def scope(queryable, %User{admin: true}), do: queryable
Expand All @@ -21,4 +23,13 @@ defmodule CodeCorps.Policy.Conversation do
|> where(user_id: ^id)
|> or_where([c], c.message_id in ^scoped_message_ids)
end

def show?(%User{id: user_id}, %Conversation{user_id: target_user_id})
when user_id == target_user_id do
true
end
def show?(%User{} = user, %Conversation{} = conversation) do
conversation |> get_message() |> get_project() |> administered_by?(user)
end
def show?(_, _), do: false
end
10 changes: 10 additions & 0 deletions lib/code_corps/policy/helpers.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ defmodule CodeCorps.Policy.Helpers do
"""

alias CodeCorps.{
Conversation,
Message,
Organization,
ProjectUser,
Project,
Expand Down Expand Up @@ -98,6 +100,14 @@ defmodule CodeCorps.Policy.Helpers do
defp owner?("owner"), do: true
defp owner?(_), do: false

@doc """
Retrieves message from associated record
"""
@spec get_message(Changeset.t() | Conversation.t() | map) :: Message.t()
def get_message(%Conversation{message_id: message_id}), do: Repo.get(Message, message_id)
def get_message(%{"message_id" => message_id}), do: Repo.get(Message, message_id)
def get_message(%Changeset{changes: %{message_id: message_id}}), do: Repo.get(Message, message_id)

@doc """
Retrieves task from associated record
"""
Expand Down
3 changes: 3 additions & 0 deletions lib/code_corps/policy/policy.ex
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ defmodule CodeCorps.Policy do
defp can?(%User{} = current_user, :create, %Comment{}, %{} = params), do: Policy.Comment.create?(current_user, params)
defp can?(%User{} = current_user, :update, %Comment{} = comment, %{}), do: Policy.Comment.update?(current_user, comment)

# Conversation
defp can?(%User{} = current_user, :show, %Conversation{} = conversation, %{}), do: Policy.Conversation.show?(current_user, conversation)

# DonationGoal
defp can?(%User{} = current_user, :create, %DonationGoal{}, %{} = params), do: Policy.DonationGoal.create?(current_user, params)
defp can?(%User{} = current_user, :update, %DonationGoal{} = donation_goal, %{}), do: Policy.DonationGoal.update?(current_user, donation_goal)
Expand Down
9 changes: 9 additions & 0 deletions lib/code_corps_web/controllers/conversation_controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,13 @@ defmodule CodeCorpsWeb.ConversationController do
conn |> render("index.json-api", data: conversations)
end
end

@spec show(Conn.t, map) :: Conn.t
def show(%Conn{} = conn, %{"id" => id}) do
with %User{} = current_user <- conn |> CodeCorps.Guardian.Plug.current_resource,
%Conversation{} = conversation <- Messages.get_conversation(id),
{:ok, :authorized} <- current_user |> Policy.authorize(:show, conversation, %{}) do
conn |> render("show.json-api", data: conversation)
end
end
end
2 changes: 1 addition & 1 deletion lib/code_corps_web/router.ex
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ defmodule CodeCorpsWeb.Router do

resources "/categories", CategoryController, only: [:create, :update]
resources "/comments", CommentController, only: [:create, :update]
resources "/conversations", ConversationController, only: [:index]
resources "/conversations", ConversationController, only: [:index, :show]
resources "/donation-goals", DonationGoalController, only: [:create, :update, :delete]
post "/oauth/github", UserController, :github_oauth
resources "/github-app-installations", GithubAppInstallationController, only: [:create]
Expand Down
24 changes: 21 additions & 3 deletions test/lib/code_corps/helpers/policy_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ defmodule CodeCorps.Policy.HelpersTest do
end

describe "administered_by?/2" do

test "returns false if given invalid arguments" do
refute Helpers.administered_by?(nil, 2)
end
Expand All @@ -81,7 +80,6 @@ defmodule CodeCorps.Policy.HelpersTest do
end

describe "contributed_by?/2" do

test "returns false if given invalid arguments" do
refute Helpers.contributed_by?(nil, 2)
end
Expand Down Expand Up @@ -133,6 +131,27 @@ defmodule CodeCorps.Policy.HelpersTest do
end
end

describe "get_message/1" do
test "should return message of a map" do
message = insert(:message)
result = Helpers.get_message(%{"message_id" => message.id})
assert result.id == message.id
end

test "should return message of a Conversation" do
message = insert(:message)
conversation = insert(:conversation, message: message)
result = Helpers.get_message(conversation)
assert result.id == message.id
end

test "should return message of a Changeset" do
message = insert(:message)
changeset = %Changeset{changes: %{message_id: message.id}}
result = Helpers.get_message(changeset)
assert result.id == message.id
end
end

describe "get_project/1" do
test "return project if the project_id is defined on the struct" do
Expand Down Expand Up @@ -219,5 +238,4 @@ defmodule CodeCorps.Policy.HelpersTest do
refute Helpers.task_authored_by?(task, other_user)
end
end

end
10 changes: 10 additions & 0 deletions test/lib/code_corps/messages/messages_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -282,4 +282,14 @@ defmodule CodeCorps.MessagesTest do
assert other_conversation_started_by_admin_with_reply.id in result_ids
end
end

describe "get_conversation/1" do
test "gets a single conversation" do
conversation = insert(:conversation)

result = Messages.get_conversation(conversation.id)

assert result.id == conversation.id
end
end
end
44 changes: 43 additions & 1 deletion test/lib/code_corps/policy/conversation_test.exs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
defmodule CodeCorps.Policy.ConversationTest do
use CodeCorps.PolicyCase

import CodeCorps.Policy.Conversation, only: [scope: 2]
import CodeCorps.Policy.Conversation, only: [scope: 2, show?: 2]

alias CodeCorps.{Conversation, Repo}

Expand Down Expand Up @@ -71,4 +71,46 @@ defmodule CodeCorps.Policy.ConversationTest do
refute some_other_conversation.id in result_ids
end
end

describe "show?" do
test "returns true when user is the target" do
user = insert(:user)
message = insert(:message)
conversation = insert(:conversation, message: message, user: user)

assert show?(user, conversation)
end

test "returns false when user is a pending project member" do
%{project: project, user: user} = insert(:project_user, role: "pending")
message = insert(:message, project: project)
conversation = insert(:conversation, message: message)

refute show?(user, conversation)
end

test "returns false when user is a project contributor" do
%{project: project, user: user} = insert(:project_user, role: "contributor")
message = insert(:message, project: project)
conversation = insert(:conversation, message: message)

refute show?(user, conversation)
end

test "returns true when user is a project admin" do
%{project: project, user: user} = insert(:project_user, role: "admin")
message = insert(:message, project: project)
conversation = insert(:conversation, message: message)

assert show?(user, conversation)
end

test "returns true when user is project owner" do
%{project: project, user: user} = insert(:project_user, role: "owner")
message = insert(:message, project: project)
conversation = insert(:conversation, message: message)

assert show?(user, conversation)
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,27 @@ defmodule CodeCorpsWeb.ConversationControllerTest do
|> assert_ids_from_response([conversation_1.id, conversation_2.id])
end
end

describe "show" do
@tag :authenticated
test "shows chosen resource", %{conn: conn, current_user: user} do
conversation = insert(:conversation, user: user)

conn
|> request_show(conversation)
|> json_response(200)
|> assert_id_from_response(conversation.id)
end

test "renders 401 when unauthenticated", %{conn: conn} do
conversation = insert(:conversation)
assert conn |> request_show(conversation) |> json_response(401)
end

@tag :authenticated
test "renders 403 when unauthorized", %{conn: conn} do
conversation = insert(:conversation)
assert conn |> request_show(conversation) |> json_response(403)
end
end
end

0 comments on commit 79b92aa

Please sign in to comment.