Skip to content

Commit c4a3b07

Browse files
authored
Merge pull request #1305 from code-corps/fix-messages
Fix message queries
2 parents 8d55213 + bb3ec89 commit c4a3b07

File tree

6 files changed

+71
-12
lines changed

6 files changed

+71
-12
lines changed

lib/code_corps/messages/conversation_query.ex

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,17 @@ defmodule CodeCorps.Messages.ConversationQuery do
2020
end
2121
def project_filter(queryable, %{}), do: queryable
2222

23+
@doc ~S"""
24+
Narrows down a `CodeCorps.Conversation` query by `user_id`, if specified in a
25+
params map
26+
"""
27+
@spec user_filter(Queryable.t, map) :: Queryable.t
28+
def user_filter(queryable, %{"user_id" => user_id}) do
29+
queryable
30+
|> where([c], c.user_id == ^user_id)
31+
end
32+
def user_filter(queryable, %{}), do: queryable
33+
2334

2435
@doc ~S"""
2536
Narrows down a `CodeCorps.Conversation` query to return only those records

lib/code_corps/messages/messages.ex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ defmodule CodeCorps.Messages do
3333
scope
3434
|> Messages.ConversationQuery.project_filter(params)
3535
|> Messages.ConversationQuery.status_filter(params)
36+
|> Messages.ConversationQuery.user_filter(params)
3637
|> Repo.all()
3738
end
3839

lib/code_corps/policy/conversation.ex

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,23 @@ defmodule CodeCorps.Policy.Conversation do
88
only: [administered_by?: 2, get_message: 1, get_project: 1]
99
import Ecto.Query
1010

11-
alias CodeCorps.{Conversation, Message, Policy, Repo, User}
11+
alias CodeCorps.{Conversation, Message, Project, ProjectUser, Repo, User}
1212

1313
@spec scope(Ecto.Queryable.t, User.t) :: Ecto.Queryable.t
1414
def scope(queryable, %User{admin: true}), do: queryable
15-
def scope(queryable, %User{id: id} = current_user) do
15+
def scope(queryable, %User{id: id}) do
16+
projects_administered_by_user_ids =
17+
Project
18+
|> join(:inner, [p], pu in ProjectUser, pu.project_id == p.id)
19+
|> where([_p, pu], pu.user_id == ^id)
20+
|> where([_p, pu], pu.role in ~w(admin owner))
21+
|> select([p], p.id)
22+
|> Repo.all
23+
1624
scoped_message_ids =
1725
Message
18-
|> Policy.Message.scope(current_user)
26+
|> where([m], m.author_id == ^id)
27+
|> or_where([m], m.project_id in ^projects_administered_by_user_ids)
1928
|> select([m], m.id)
2029
|> Repo.all
2130

lib/code_corps/policy/message.ex

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ defmodule CodeCorps.Policy.Message do
66
import CodeCorps.Policy.Helpers, only: [administered_by?: 2, get_project: 1]
77
import Ecto.Query
88

9-
alias CodeCorps.{Message, Project, ProjectUser, User, Repo}
9+
alias CodeCorps.{Conversation, Message, Project, ProjectUser, Repo, User}
1010

1111
@spec scope(Ecto.Queryable.t, User.t) :: Ecto.Queryable.t
1212
def scope(queryable, %User{admin: true}), do: queryable
@@ -19,17 +19,32 @@ defmodule CodeCorps.Policy.Message do
1919
|> select([p], p.id)
2020
|> Repo.all
2121

22+
messages_targeted_at_user_ids =
23+
Message
24+
|> join(:inner, [m], c in Conversation, c.message_id == m.id)
25+
|> where([_m, c], c.user_id == ^id)
26+
|> select([m, _c], m.id)
27+
|> Repo.all
28+
2229
queryable
2330
|> where([m], m.author_id == ^id)
31+
|> or_where([m], m.id in ^messages_targeted_at_user_ids)
2432
|> or_where([m], m.project_id in ^projects_administered_by_user_ids)
2533
end
2634

27-
def show?(%User{id: user_id}, %{initiated_by: "user", author_id: author_id})
35+
def show?(
36+
%User{id: user_id},
37+
%Message{initiated_by: "user", author_id: author_id})
2838
when user_id == author_id do
39+
2940
true
3041
end
3142
def show?(%User{} = user, %Message{} = message) do
32-
message |> get_project() |> administered_by?(user)
43+
cond do
44+
message |> get_project() |> administered_by?(user) -> true
45+
message.conversations |> Enum.any?(fn c -> c.user_id == user.id end) -> true
46+
true -> false
47+
end
3348
end
3449
def show?(_, _), do: false
3550

test/lib/code_corps/policy/message_test.exs

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ defmodule CodeCorps.Policy.MessageTest do
2121
assert Message |> scope(user) |> Repo.all |> Enum.count == 3
2222
end
2323

24-
test "returns records where user is the author or they administer the project" do
24+
test "returns records where user is the author or they administer the project, or they are the target of the conversation" do
2525
user = insert(:user, admin: false)
2626

2727
%{project: project_user_applied_to} =
@@ -58,6 +58,9 @@ defmodule CodeCorps.Policy.MessageTest do
5858
message_from_owned_project =
5959
insert(:message, project: project_user_owns)
6060

61+
%{message: message_where_user_is_target} =
62+
insert(:conversation, user: user)
63+
6164
result_ids =
6265
Message
6366
|> scope(user)
@@ -71,6 +74,7 @@ defmodule CodeCorps.Policy.MessageTest do
7174
assert message_from_other_administered_project.id in result_ids
7275
assert message_from_owned_project.id in result_ids
7376
refute some_other_message.id in result_ids
77+
assert message_where_user_is_target.id in result_ids
7478
end
7579
end
7680

@@ -86,35 +90,42 @@ defmodule CodeCorps.Policy.MessageTest do
8690
user = insert(:user)
8791
message = insert(:message, initiated_by: "user")
8892

89-
refute show?(user, message)
93+
refute show?(user, message |> Repo.preload(:conversations))
9094
end
9195

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

96-
refute show?(user, message)
100+
refute show?(user, message |> Repo.preload(:conversations))
97101
end
98102

99103
test "returns false when user is a project contributor" do
100104
%{project: project, user: user} = insert(:project_user, role: "contributor")
101105
message = insert(:message, initiated_by: "user", project: project)
102106

103-
refute show?(user, message)
107+
refute show?(user, message |> Repo.preload(:conversations))
104108
end
105109

106110
test "returns true when user is a project admin" do
107111
%{project: project, user: user} = insert(:project_user, role: "admin")
108112
message = insert(:message, initiated_by: "user", project: project)
109113

110-
assert show?(user, message)
114+
assert show?(user, message |> Repo.preload(:conversations))
111115
end
112116

113117
test "returns true when user is project owner" do
114118
%{project: project, user: user} = insert(:project_user, role: "owner")
115119
message = insert(:message, initiated_by: "user", project: project)
116120

117-
assert show?(user, message)
121+
assert show?(user, message |> Repo.preload(:conversations))
122+
end
123+
124+
test "returns true when message conversation is targeted at user" do
125+
user = insert(:user)
126+
%{message: message} = insert(:conversation, user: user)
127+
128+
assert show?(user, message |> Repo.preload(:conversations))
118129
end
119130
end
120131

test/lib/code_corps_web/controllers/conversation_controller_test.exs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,18 @@ defmodule CodeCorpsWeb.ConversationControllerTest do
2929
|> json_response(200)
3030
|> assert_ids_from_response([conversation_1.id, conversation_2.id])
3131
end
32+
33+
@tag authenticated: :admin
34+
test "lists all entries by status", %{conn: conn} do
35+
insert_pair(:conversation)
36+
user = insert(:user)
37+
conversation_other = insert(:conversation, user: user)
38+
39+
conn
40+
|> get("conversations?user_id=#{user.id}")
41+
|> json_response(200)
42+
|> assert_ids_from_response([conversation_other.id])
43+
end
3244
end
3345

3446
describe "show" do

0 commit comments

Comments
 (0)