Skip to content

Add conversation show endpoint #1298

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 15, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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