Skip to content

Commit

Permalink
Merge pull request #1309 from code-corps/update-conversation
Browse files Browse the repository at this point in the history
Update conversation route
  • Loading branch information
joshsmith committed Dec 20, 2017
2 parents 5911b36 + c1c15fa commit faa4353
Show file tree
Hide file tree
Showing 8 changed files with 112 additions and 2 deletions.
4 changes: 4 additions & 0 deletions lib/code_corps/messages/messages.ex
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ defmodule CodeCorps.Messages do
Conversation |> Repo.get(id)
end

def update_conversation(conversation, params) do
conversation |> Conversation.update_changeset(params) |> Repo.update
end

@doc ~S"""
Gets a `CodeCorps.ConversationPart` record
"""
Expand Down
10 changes: 10 additions & 0 deletions lib/code_corps/model/conversation.ex
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,14 @@ defmodule CodeCorps.Conversation do

timestamps()
end

def update_changeset(struct, %{"status" => status} = params) do
struct
|> cast(params, [:status])
|> validate_inclusion(:status, statuses())
end

defp statuses do
~w{ open closed }
end
end
6 changes: 6 additions & 0 deletions lib/code_corps/policy/conversation.ex
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,10 @@ defmodule CodeCorps.Policy.Conversation do
conversation |> get_message() |> get_project() |> administered_by?(user)
end
def show?(_, _), do: false

def update?(%User{admin: true}, _conversation), do: true
def update?(%User{} = user, %Conversation{} = conversation) do
conversation |> get_message() |> get_project() |> administered_by?(user)
end
def update?(_, _), do: false
end
1 change: 1 addition & 0 deletions lib/code_corps/policy/policy.ex
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ defmodule CodeCorps.Policy do

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

# ConversationPart
defp can?(%User{} = current_user, :create, %ConversationPart{}, %{} = params), do: Policy.ConversationPart.create?(current_user, params)
Expand Down
12 changes: 12 additions & 0 deletions lib/code_corps_web/controllers/conversation_controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,18 @@ defmodule CodeCorpsWeb.ConversationController do
end
end

@spec update(Conn.t, map) :: Conn.t
def update(%Conn{} = conn, %{"id" => id} = params) do
with %Conversation{} = conversation <- Messages.get_conversation(id) |> preload(),
%User{} = current_user <- conn |> CodeCorps.Guardian.Plug.current_resource,
{:ok, :authorized} <- current_user |> Policy.authorize(:update, conversation),
{:ok, %Conversation{} = updated_conversation} <- conversation |> Messages.update_conversation(params)
do

conn |> render("show.json-api", data: updated_conversation)
end
end

@preloads [:conversation_parts, :message, :user]

def preload(data) do
Expand Down
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, :show]
resources "/conversations", ConversationController, only: [:index, :show, :update]
resources "/conversation-parts", ConversationPartController, only: [:index, :show, :create]
resources "/donation-goals", DonationGoalController, only: [:create, :update, :delete]
post "/oauth/github", UserController, :github_oauth
Expand Down
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, show?: 2]
import CodeCorps.Policy.Conversation, only: [scope: 2, show?: 2, update?: 2]

alias CodeCorps.{Conversation, Repo}

Expand Down Expand Up @@ -113,4 +113,46 @@ defmodule CodeCorps.Policy.ConversationTest do
assert show?(user, conversation)
end
end

describe "update?" do
test "returns true when user is admin" do
user = insert(:user, admin: true)
message = insert(:message)
conversation = insert(:conversation, message: message, user: user)

assert update?(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 update?(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 update?(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 update?(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 update?(user, conversation)
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,39 @@ defmodule CodeCorpsWeb.ConversationControllerTest do
assert conn |> request_show(conversation) |> json_response(403)
end
end

describe "update" do
@tag authenticated: :admin
test "updates and renders chosen resource when data is valid", %{conn: conn, current_user: user} do
%{project: project} = insert(:project_user, role: "admin", user: user)
message_on_user_administered_project = insert(:message, project: project)
conversation_on_user_administered_project =
insert(:conversation, message: message_on_user_administered_project)

data =
conn
|> request_update(conversation_on_user_administered_project, %{status: "closed"})
|> json_response(200)
|> Map.get("data")

assert data["attributes"]["status"] == "closed"
end

@tag authenticated: :admin
test "renders 422 when data is invalid", %{conn: conn, current_user: current_user} do
conversation = insert(:conversation, user: current_user)
assert conn |> request_update(conversation, %{status: "wat"}) |> json_response(422)
end

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

@tag :authenticated
test "does not update resource and renders 403 when not authorized", %{conn: conn} do
user = insert(:user)
insert(:conversation, user: user)
assert conn |> request_update() |> json_response(403)
end
end
end

0 comments on commit faa4353

Please sign in to comment.