Skip to content

Commit faa4353

Browse files
authored
Merge pull request #1309 from code-corps/update-conversation
Update conversation route
2 parents 5911b36 + c1c15fa commit faa4353

File tree

8 files changed

+112
-2
lines changed

8 files changed

+112
-2
lines changed

lib/code_corps/messages/messages.ex

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ defmodule CodeCorps.Messages do
5353
Conversation |> Repo.get(id)
5454
end
5555

56+
def update_conversation(conversation, params) do
57+
conversation |> Conversation.update_changeset(params) |> Repo.update
58+
end
59+
5660
@doc ~S"""
5761
Gets a `CodeCorps.ConversationPart` record
5862
"""

lib/code_corps/model/conversation.ex

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,14 @@ defmodule CodeCorps.Conversation do
2626

2727
timestamps()
2828
end
29+
30+
def update_changeset(struct, %{"status" => status} = params) do
31+
struct
32+
|> cast(params, [:status])
33+
|> validate_inclusion(:status, statuses())
34+
end
35+
36+
defp statuses do
37+
~w{ open closed }
38+
end
2939
end

lib/code_corps/policy/conversation.ex

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,10 @@ defmodule CodeCorps.Policy.Conversation do
4141
conversation |> get_message() |> get_project() |> administered_by?(user)
4242
end
4343
def show?(_, _), do: false
44+
45+
def update?(%User{admin: true}, _conversation), do: true
46+
def update?(%User{} = user, %Conversation{} = conversation) do
47+
conversation |> get_message() |> get_project() |> administered_by?(user)
48+
end
49+
def update?(_, _), do: false
4450
end

lib/code_corps/policy/policy.ex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ defmodule CodeCorps.Policy do
7575

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

7980
# ConversationPart
8081
defp can?(%User{} = current_user, :create, %ConversationPart{}, %{} = params), do: Policy.ConversationPart.create?(current_user, params)

lib/code_corps_web/controllers/conversation_controller.ex

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,18 @@ defmodule CodeCorpsWeb.ConversationController do
2929
end
3030
end
3131

32+
@spec update(Conn.t, map) :: Conn.t
33+
def update(%Conn{} = conn, %{"id" => id} = params) do
34+
with %Conversation{} = conversation <- Messages.get_conversation(id) |> preload(),
35+
%User{} = current_user <- conn |> CodeCorps.Guardian.Plug.current_resource,
36+
{:ok, :authorized} <- current_user |> Policy.authorize(:update, conversation),
37+
{:ok, %Conversation{} = updated_conversation} <- conversation |> Messages.update_conversation(params)
38+
do
39+
40+
conn |> render("show.json-api", data: updated_conversation)
41+
end
42+
end
43+
3244
@preloads [:conversation_parts, :message, :user]
3345

3446
def preload(data) do

lib/code_corps_web/router.ex

Lines changed: 1 addition & 1 deletion
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, :show]
74+
resources "/conversations", ConversationController, only: [:index, :show, :update]
7575
resources "/conversation-parts", ConversationPartController, only: [:index, :show, :create]
7676
resources "/donation-goals", DonationGoalController, only: [:create, :update, :delete]
7777
post "/oauth/github", UserController, :github_oauth

test/lib/code_corps/policy/conversation_test.exs

Lines changed: 43 additions & 1 deletion
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, show?: 2]
4+
import CodeCorps.Policy.Conversation, only: [scope: 2, show?: 2, update?: 2]
55

66
alias CodeCorps.{Conversation, Repo}
77

@@ -113,4 +113,46 @@ defmodule CodeCorps.Policy.ConversationTest do
113113
assert show?(user, conversation)
114114
end
115115
end
116+
117+
describe "update?" do
118+
test "returns true when user is admin" do
119+
user = insert(:user, admin: true)
120+
message = insert(:message)
121+
conversation = insert(:conversation, message: message, user: user)
122+
123+
assert update?(user, conversation)
124+
end
125+
126+
test "returns false when user is a pending project member" do
127+
%{project: project, user: user} = insert(:project_user, role: "pending")
128+
message = insert(:message, project: project)
129+
conversation = insert(:conversation, message: message)
130+
131+
refute update?(user, conversation)
132+
end
133+
134+
test "returns false when user is a project contributor" do
135+
%{project: project, user: user} = insert(:project_user, role: "contributor")
136+
message = insert(:message, project: project)
137+
conversation = insert(:conversation, message: message)
138+
139+
refute update?(user, conversation)
140+
end
141+
142+
test "returns true when user is a project admin" do
143+
%{project: project, user: user} = insert(:project_user, role: "admin")
144+
message = insert(:message, project: project)
145+
conversation = insert(:conversation, message: message)
146+
147+
assert update?(user, conversation)
148+
end
149+
150+
test "returns true when user is project owner" do
151+
%{project: project, user: user} = insert(:project_user, role: "owner")
152+
message = insert(:message, project: project)
153+
conversation = insert(:conversation, message: message)
154+
155+
assert update?(user, conversation)
156+
end
157+
end
116158
end

test/lib/code_corps_web/controllers/conversation_controller_test.exs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,4 +65,39 @@ defmodule CodeCorpsWeb.ConversationControllerTest do
6565
assert conn |> request_show(conversation) |> json_response(403)
6666
end
6767
end
68+
69+
describe "update" do
70+
@tag authenticated: :admin
71+
test "updates and renders chosen resource when data is valid", %{conn: conn, current_user: user} do
72+
%{project: project} = insert(:project_user, role: "admin", user: user)
73+
message_on_user_administered_project = insert(:message, project: project)
74+
conversation_on_user_administered_project =
75+
insert(:conversation, message: message_on_user_administered_project)
76+
77+
data =
78+
conn
79+
|> request_update(conversation_on_user_administered_project, %{status: "closed"})
80+
|> json_response(200)
81+
|> Map.get("data")
82+
83+
assert data["attributes"]["status"] == "closed"
84+
end
85+
86+
@tag authenticated: :admin
87+
test "renders 422 when data is invalid", %{conn: conn, current_user: current_user} do
88+
conversation = insert(:conversation, user: current_user)
89+
assert conn |> request_update(conversation, %{status: "wat"}) |> json_response(422)
90+
end
91+
92+
test "renders 401 when unauthenticated", %{conn: conn} do
93+
assert conn |> request_update |> json_response(401)
94+
end
95+
96+
@tag :authenticated
97+
test "does not update resource and renders 403 when not authorized", %{conn: conn} do
98+
user = insert(:user)
99+
insert(:conversation, user: user)
100+
assert conn |> request_update() |> json_response(403)
101+
end
102+
end
68103
end

0 commit comments

Comments
 (0)