Commit b39926d9 authored by Alex Castaño's avatar Alex Castaño

Following communities and collections

parent e06518af
......@@ -26,6 +26,7 @@ defmodule ActivityPub.SQL.Query do
def one(%Ecto.Query{} = query) do
query
# |> print_query()
|> Repo.one()
|> to_entity()
end
......@@ -169,24 +170,12 @@ defmodule ActivityPub.SQL.Query do
end)
end
def belongs_to(%Ecto.Query{} = query, assoc_name, local_id) when is_integer(local_id),
do: belongs_to(query, assoc_name, [local_id])
def belongs_to(%Ecto.Query{} = query, assoc_name, entity) when APG.is_entity(entity),
do: belongs_to(query, assoc_name, [Entity.local_id(entity)])
def belongs_to(%Ecto.Query{} = query, assoc_name, [entity | _] = list)
when APG.is_entity(entity),
do: belongs_to(query, assoc_name, to_local_ids(list))
def has(%Ecto.Query{} = query, assoc_name, local_id) when is_integer(local_id),
do: has(query, assoc_name, [local_id])
def has(%Ecto.Query{} = query, assoc_name, entity) when APG.is_entity(entity),
do: has(query, assoc_name, [Entity.local_id(entity)])
def has(%Ecto.Query{} = query, assoc_name, [entity | _] = list) when APG.is_entity(entity),
do: has(query, assoc_name, to_local_ids(list))
defp to_local_ids(entities, assoc) do
Enum.map(entities, fn
e when APG.is_entity(e) -> Common.local_id(e[assoc])
int when is_integer(int) -> int
end)
end
def has?(subject, rel, target)
when APG.is_entity(subject) and APG.has_status(subject, :loaded) and APG.is_entity(target) and
......@@ -202,6 +191,26 @@ defmodule ActivityPub.SQL.Query do
table_name: table_name,
join_keys: [subject_key, target_key]
} ->
def belongs_to(%Ecto.Query{} = query, unquote(name), local_id) when is_integer(local_id),
do: belongs_to(query, unquote(name), [local_id])
def belongs_to(%Ecto.Query{} = query, unquote(name), entity) when APG.is_entity(entity),
do: belongs_to(query, unquote(name), [Entity.local_id(entity)])
def belongs_to(%Ecto.Query{} = query, unquote(name), [entity | _] = list)
when APG.is_entity(entity),
do: belongs_to(query, unquote(name), to_local_ids(list))
def has(%Ecto.Query{} = query, unquote(name), local_id) when is_integer(local_id),
do: has(query, unquote(name), [local_id])
def has(%Ecto.Query{} = query, unquote(name), entity) when APG.is_entity(entity),
do: has(query, unquote(name), [Entity.local_id(entity)])
def has(%Ecto.Query{} = query, unquote(name), [entity | _] = list)
when APG.is_entity(entity),
do: has(query, unquote(name), to_local_ids(list))
def has(%Ecto.Query{} = query, unquote(name), ext_ids) when is_list(ext_ids) do
from([entity: entity] in query,
join: rel in fragment(unquote(table_name)),
......@@ -239,10 +248,58 @@ defmodule ActivityPub.SQL.Query do
%Collection{
name: name,
sql_aspect: sql_aspect,
aspect: aspect,
table_name: table_name,
join_keys: [subject_key, target_key]
} ->
def belongs_to(%Ecto.Query{} = query, unquote(name), local_id) when is_integer(local_id),
do: belongs_to(query, unquote(name), [local_id])
def belongs_to(%Ecto.Query{} = query, unquote(name), entity) when APG.is_entity(entity),
do: belongs_to(query, unquote(name), [Common.local_id(entity[unquote(name)])])
def belongs_to(%Ecto.Query{} = query, unquote(name), [entity | _] = list)
when APG.is_entity(entity),
do: belongs_to(query, unquote(name), to_local_ids(list))
def belongs_to(%Ecto.Query{} = query, unquote(name), ext_ids)
when is_list(ext_ids) do
field_name = "#{unquote(name)}_id"
from([entity: entity] in query,
join: rel in fragment(unquote(table_name)),
as: unquote(name),
on:
entity.local_id == field(rel, unquote(target_key)) and
field(rel, unquote(subject_key)) in ^ext_ids
)
end
def has(%Ecto.Query{} = query, unquote(name), local_id) when is_integer(local_id),
do: has(query, unquote(name), [local_id])
def has(%Ecto.Query{} = query, unquote(name), entity) when APG.is_entity(entity),
do: has(query, unquote(name), [Entity.local_id(entity)])
def has(%Ecto.Query{} = query, unquote(name), [entity | _] = list)
when APG.is_entity(entity),
do: has(query, unquote(name), to_local_ids(list))
def has(%Ecto.Query{} = query, unquote(name), ext_ids) when is_list(ext_ids) do
%{owner_key: owner_key} = unquote(sql_aspect).__schema__(:association, unquote(name))
# FIXME THIS works perfectly for all aspects except Object!
query = preload_aspect(query, unquote(aspect))
from([{unquote(sql_aspect.field_name), entity}] in query,
join: rel in fragment(unquote(table_name)),
as: unquote(name),
on:
field(entity, ^owner_key) == field(rel, unquote(subject_key)) and
field(rel, unquote(target_key)) in ^ext_ids
)
end
defp do_has?(subject, unquote(name), target)
when APG.has_aspect(subject, unquote(aspect)) do
subject_id = Common.local_id(subject[unquote(name)])
......@@ -256,11 +313,8 @@ defmodule ActivityPub.SQL.Query do
|> Repo.exists?()
end
# TODO has and belongs_to
# TODO all belongs_to assoc
%BelongsTo{} ->
# TODO has and belongs_to
[]
end)
end
......@@ -353,9 +407,9 @@ defmodule ActivityPub.SQL.Query do
"Invalid status: #{Entity.status(e)}. Only entities with status :loaded can be preloaded"
)
# defp print_query(query) do
# {query_str, args} = Ecto.Adapters.SQL.to_sql(:all, Repo, query)
# IO.puts("#{query_str} <=> #{inspect(args)}")
# query
# end
defp print_query(query) do
{query_str, args} = Ecto.Adapters.SQL.to_sql(:all, Repo, query)
IO.puts("#{query_str} <=> #{inspect(args)}")
query
end
end
......@@ -11,6 +11,14 @@ defmodule MoodleNet do
|> Query.all()
end
def list_following_communities(actor, opts \\ %{}) do
Query.new()
|> Query.with_type("MoodleNet:Community")
|> Query.belongs_to(:following, actor)
|> Query.paginate(opts)
|> Query.all()
end
def list_communities_with_collection(collection, opts \\ %{}) do
Query.new()
|> Query.with_type("MoodleNet:Community")
......@@ -33,6 +41,14 @@ defmodule MoodleNet do
list_collections(entity[:local_id], opts)
end
def list_following_collections(actor, opts \\ %{}) do
Query.new()
|> Query.with_type("MoodleNet:Collection")
|> Query.belongs_to(:following, actor)
|> Query.paginate(opts)
|> Query.all()
end
def list_resources(entity_id, opts \\ %{})
def list_resources(entity_id, opts) when is_integer(entity_id) do
......
......@@ -18,6 +18,11 @@ defmodule MoodleNetWeb.GraphQL.Schema do
resolve(MoodleNetSchema.resolve_by_id_and_type("MoodleNet:Community"))
end
@desc "Get list of following communities"
field :following_communities, non_null(list_of(non_null(:community))) do
resolve(&MoodleNetSchema.list_following_communities/2)
end
@desc "Get list of collections"
field :collections, non_null(list_of(non_null(:collection))) do
arg(:community_local_id, non_null(:integer))
......@@ -30,6 +35,11 @@ defmodule MoodleNetWeb.GraphQL.Schema do
resolve(MoodleNetSchema.resolve_by_id_and_type("MoodleNet:Collection"))
end
@desc "Get list of following collections"
field :following_collections, non_null(list_of(non_null(:collection))) do
resolve(&MoodleNetSchema.list_following_collections/2)
end
@desc "Get list of resources"
field :resources, non_null(list_of(non_null(:resource))) do
arg(:collection_local_id, non_null(:integer))
......
......@@ -271,6 +271,18 @@ defmodule MoodleNetWeb.GraphQL.MoodleNetSchema do
{:ok, comms}
end
def list_following_communities(_field_arguments, info) do
fields = requested_fields(info)
with {:ok, current_actor} <- current_actor(info) do
comms =
MoodleNet.list_following_communities(current_actor)
|> prepare(fields)
{:ok, comms}
end
end
def list_collections(%{community_local_id: community_local_id}, info) do
fields = requested_fields(info)
......@@ -281,6 +293,18 @@ defmodule MoodleNetWeb.GraphQL.MoodleNetSchema do
{:ok, cols}
end
def list_following_collections(_field_arguments, info) do
fields = requested_fields(info)
with {:ok, current_actor} <- current_actor(info) do
colls =
MoodleNet.list_following_collections(current_actor)
|> prepare(fields)
{:ok, colls}
end
end
def list_resources(%{collection_local_id: collection_local_id}, info) do
fields = requested_fields(info)
......
defmodule ActivityPub.SQL.QueryTest do
use MoodleNet.DataCase, async: true
alias ActivityPub.SQL.Query
alias ActivityPub.SQL.{Alter, Query}
alias ActivityPub.SQL.{FieldNotLoaded, AssociationNotLoaded}
def insert(map) do
......@@ -144,19 +144,39 @@ defmodule ActivityPub.SQL.QueryTest do
end
end
test "has/3 and belongs_to/3 work" do
child =
%{id: child_id, attributed_to: [parent = %{id: parent_id}]} = insert(%{attributed_to: %{}})
describe "has/3 and belongs_to/3" do
test "work with many_to_many relation" do
child =
%{id: child_id, attributed_to: [parent = %{id: parent_id}]} =
insert(%{attributed_to: %{}})
assert %{id: ^child_id} =
Query.new()
|> Query.has(:attributed_to, parent)
|> Query.one()
assert %{id: ^child_id} =
Query.new()
|> Query.has(:attributed_to, parent)
|> Query.one()
assert %{id: ^parent_id} =
Query.new()
|> Query.belongs_to(:attributed_to, child)
|> Query.one()
end
test "work with collection relation" do
%{id: follower_id} = follower = Factory.actor()
%{id: following_id} = following = Factory.actor()
assert %{id: ^parent_id} =
Query.new()
|> Query.belongs_to(:attributed_to, child)
|> Query.one()
assert {:ok, 1} = Alter.add(follower, :following, following)
assert %{id: ^following_id} =
Query.new()
|> Query.belongs_to(:following, follower)
|> Query.one()
assert %{id: ^follower_id} =
Query.new()
|> Query.has(:following, following)
|> Query.one()
end
end
describe "has?/3" do
......
defmodule MoodleNetTest do
use MoodleNet.DataCase, async: true
describe "list following communities" do
test "works" do
owner = Factory.actor()
%{id: comm_id} = comm = Factory.community(owner)
assert [%{id: ^comm_id}] = MoodleNet.list_following_communities(owner)
assert {:ok, true} = MoodleNet.undo_follow(owner, comm)
assert [] = MoodleNet.list_following_communities(owner)
end
end
describe "list following collections" do
test "works" do
owner = Factory.actor()
comm = Factory.community(owner)
%{id: coll_id} = coll = Factory.collection(owner, comm)
assert [%{id: ^coll_id}] = MoodleNet.list_following_collections(owner)
assert {:ok, true} = MoodleNet.undo_follow(owner, coll)
assert [] = MoodleNet.list_following_collections(owner)
end
end
describe "list_threads" do
test "works" do
owner = Factory.actor()
......@@ -86,7 +111,6 @@ defmodule MoodleNetTest do
assert comment["primary_language"] == attrs["primary_language"]
assert comment.content == %{"und" => attrs["content"]}
assert {:ok, comment} = MoodleNet.create_thread(actor, coll, attrs)
assert comment["primary_language"] == attrs["primary_language"]
assert comment.content == %{"und" => attrs["content"]}
......@@ -113,7 +137,6 @@ defmodule MoodleNetTest do
assert comment["primary_language"] == attrs["primary_language"]
assert comment.content == %{"und" => attrs["content"]}
assert {:ok, comment} = MoodleNet.create_reply(actor, c2, attrs)
assert comment["primary_language"] == attrs["primary_language"]
assert comment.content == %{"und" => attrs["content"]}
......
......@@ -7,6 +7,65 @@ defmodule MoodleNetWeb.GraphQL.MoodleNetSchemaTest do
import ActivityPub.Entity, only: [local_id: 1]
@moduletag format: :json
@tag :user
test "list following communities", %{conn: conn, actor: actor} do
%{id: community_id} = community = Factory.community(actor)
query = """
{
followingCommunities {
id
}
}
"""
assert [%{"id" => ^community_id}] =
conn
|> post("/api/graphql", %{query: query})
|> json_response(200)
|> Map.fetch!("data")
|> Map.fetch!("followingCommunities")
MoodleNet.undo_follow(actor, community)
assert [] =
conn
|> post("/api/graphql", %{query: query})
|> json_response(200)
|> Map.fetch!("data")
|> Map.fetch!("followingCommunities")
end
@tag :user
test "list following collections", %{conn: conn, actor: actor} do
community = Factory.community(actor)
%{id: collection_id} = collection = Factory.collection(actor, community)
query = """
{
followingCollections {
id
}
}
"""
assert [%{"id" => ^collection_id}] =
conn
|> post("/api/graphql", %{query: query})
|> json_response(200)
|> Map.fetch!("data")
|> Map.fetch!("followingCollections")
MoodleNet.undo_follow(actor, collection)
assert [] =
conn
|> post("/api/graphql", %{query: query})
|> json_response(200)
|> Map.fetch!("data")
|> Map.fetch!("followingCollections")
end
@tag :user
test "list threads", %{conn: conn, actor: actor} do
community = Factory.community(actor)
......@@ -16,7 +75,7 @@ defmodule MoodleNetWeb.GraphQL.MoodleNetSchemaTest do
query = """
{
threads(context_local_id: #{local_id(community)}) {
threads(contextLocalId: #{local_id(community)}) {
id
author {
id
......@@ -39,13 +98,15 @@ defmodule MoodleNetWeb.GraphQL.MoodleNetSchemaTest do
|> Map.fetch!("threads")
assert %{
"id" => thread.id,
"author" => %{"id" => actor.id},
"replies" => [%{
"id" => reply.id,
"author" => %{"id" => actor.id},
}]
} == thread_map
"id" => thread.id,
"author" => %{"id" => actor.id},
"replies" => [
%{
"id" => reply.id,
"author" => %{"id" => actor.id}
}
]
} == thread_map
end
@tag :user
......@@ -162,9 +223,10 @@ defmodule MoodleNetWeb.GraphQL.MoodleNetSchemaTest do
},
"code" => "validation",
"locations" => [%{"column" => 0, "line" => 2}],
"message" => "should be at least 6 character(s)",
"path" => ["createUser"]
} = error
assert error["message"] == "debería tener al menos 6 elemento(s)"
end
test "confirm email", %{conn: conn} do
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment