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

Merge branch 'release/0.0.10'

parents 2178511c 94690b8e
......@@ -12,7 +12,12 @@ build: ## Build the Docker image
@echo APP_NAME=$(APP_NAME)
@echo APP_VSN=$(APP_VSN)
@echo APP_BUILD=$(APP_BUILD)
docker build \
@echo docker build \
--no-cache \
--build-arg APP_NAME=$(APP_NAME) \
--build-arg APP_VSN=$(APP_VSN) \
-t moodlenet/moodlenet:$(APP_VSN)-$(APP_BUILD) .
@docker build \
--no-cache \
--build-arg APP_NAME=$(APP_NAME) \
--build-arg APP_VSN=$(APP_VSN) \
......@@ -23,19 +28,29 @@ build_with_cache: ## Build the Docker image
@echo APP_NAME=$(APP_NAME)
@echo APP_VSN=$(APP_VSN)
@echo APP_BUILD=$(APP_BUILD)
docker build \
@echo docker build \
--build-arg APP_NAME=$(APP_NAME) \
--build-arg APP_VSN=$(APP_VSN) \
-t moodlenet/moodlenet:$(APP_VSN)-$(APP_BUILD) .
@docker build \
--build-arg APP_NAME=$(APP_NAME) \
--build-arg APP_VSN=$(APP_VSN) \
-t moodlenet/moodlenet:$(APP_VSN)-$(APP_BUILD) .
@echo moodlenet/moodlenet:$(APP_VSN)-$(APP_BUILD)
tag:
push:
@echo docker tag moodlenet/moodlenet:$(APP_VSN)-$(APP_BUILD) moodlenet/moodlenet:latest
@docker tag moodlenet/moodlenet:$(APP_VSN)-$(APP_BUILD) moodlenet/moodlenet:latest
@echo docker push moodlenet/moodlenet:latest
@docker push moodlenet/moodlenet:latest
push_stable:
@echo docker tag moodlenet/moodlenet:$(APP_VSN)-$(APP_BUILD) moodlenet/moodlenet:latest
@docker tag moodlenet/moodlenet:$(APP_VSN)-$(APP_BUILD) moodlenet/moodlenet:latest
@echo docker tag moodlenet/moodlenet:$(APP_VSN)-$(APP_BUILD) moodlenet/moodlenet:$(APP_VSN)
@docker tag moodlenet/moodlenet:$(APP_VSN)-$(APP_BUILD) moodlenet/moodlenet:$(APP_VSN)
push:
@echo docker tag moodlenet/moodlenet:$(APP_VSN)-$(APP_BUILD) moodlenet/moodlenet:stable
@docker tag moodlenet/moodlenet:$(APP_VSN)-$(APP_BUILD) moodlenet/moodlenet:stable
@echo docker push moodlenet/moodlenet:latest
@docker push moodlenet/moodlenet:latest
@echo docker push moodlenet/moodlenet:$(APP_VSN)
......
......@@ -26,6 +26,7 @@ defmodule ActivityPub.SQL.Query do
def one(%Ecto.Query{} = query) do
query
# |> print_query()
|> Repo.one()
|> to_entity()
end
......@@ -169,25 +170,6 @@ 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))
def has?(subject, rel, target)
when APG.is_entity(subject) and APG.has_status(subject, :loaded) and APG.is_entity(target) and
APG.has_status(target, :loaded)
......@@ -202,6 +184,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 +241,56 @@ 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
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 +304,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
......
......@@ -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))
......
......@@ -15,7 +15,7 @@ defmodule MoodleNetWeb.GraphQL.MiscSchema do
end
def fetch_web_metadata(%{url: url}, info) do
with {:ok, actor} <- current_actor(info) do
with {:ok, _actor} <- current_actor(info) do
case MoodleNet.MetadataScraper.fetch(url) do
{:error, _} -> Errors.bad_gateway_error()
ret -> ret
......
......@@ -248,6 +248,19 @@ defmodule MoodleNetWeb.GraphQL.MoodleNetSchema do
field(:author, :user, do: resolve(with_assoc(:attributed_to, single: true)))
field(:in_reply_to, :comment, do: resolve(with_assoc(:in_reply_to, single: true)))
field(:replies, list_of(:comment), do: resolve(with_assoc(:replies)))
field(:context, :comment_context, do: resolve(with_assoc(:context, single: true)))
end
union :comment_context do
description("Where the comment resides")
types([:collection, :community])
resolve_type(fn
e, _ when APG.has_type(e, "MoodleNet:Community") -> :community
e, _ when APG.has_type(e, "MoodleNet:Collection") -> :collection
end)
end
input_object :comment_input do
......@@ -271,6 +284,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 +306,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)
......
......@@ -4,7 +4,7 @@ defmodule MoodleNet.Mixfile do
def project do
[
app: :moodle_net,
version: "0.0.9",
version: "0.0.10",
elixir: "~> 1.7.4",
elixirc_paths: elixirc_paths(Mix.env()),
compilers: [:phoenix, :gettext] ++ Mix.compilers(),
......
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,158 @@ defmodule MoodleNetWeb.GraphQL.MoodleNetSchemaTest do
import ActivityPub.Entity, only: [local_id: 1]
@moduletag format: :json
@tag :user
test "comment context", %{conn: conn, actor: actor} do
community = Factory.community(actor)
collection = Factory.collection(actor, community)
resource = Factory.resource(actor, collection)
%{id: comm_comment_id} = Factory.comment(actor, community)
%{id: coll_comment_id} = Factory.comment(actor, collection)
query = """
{
threads(contextLocalId: #{local_id(community)}) {
id
context {
__typename
... on Community {
id
name
collections {
id
}
}
... on Collection {
id
name
resources {
id
}
}
}
}
}
"""
assert [comm_comment_map] =
conn
|> post("/api/graphql", %{query: query})
|> json_response(200)
|> Map.fetch!("data")
|> Map.fetch!("threads")
assert %{
"id" => ^comm_comment_id,
"context" => community_map
} = comm_comment_map
assert community_map["__typename"] == "Community"
assert community_map["id"] == community.id
assert community_map["name"] == community.name["und"]
assert [%{"id" => collection_id}] = community_map["collections"]
assert collection_id == collection.id
query = """
{
threads(contextLocalId: #{local_id(collection)}) {
id
context {
__typename
... on Community {
id
name
collections {
id
}
}
... on Collection {
id
name
resources {
id
}
}
}
}
}
"""
assert [coll_comment_map] =
conn
|> post("/api/graphql", %{query: query})
|> json_response(200)
|> Map.fetch!("data")
|> Map.fetch!("threads")
assert %{
"id" => ^coll_comment_id,
"context" => collection_map
} = coll_comment_map
assert collection_map["__typename"] == "Collection"
assert collection_map["id"] == collection.id
assert collection_map["name"] == collection.name["und"]
assert [%{"id" => resource_id}] = collection_map["resources"]
assert resource_id == resource.id
end
@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 +168,7 @@ defmodule MoodleNetWeb.GraphQL.MoodleNetSchemaTest do
query = """
{
threads(context_local_id: #{local_id(community)}) {
threads(contextLocalId: #{local_id(community)}) {
id
author {
id
......@@ -39,13 +191,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 +316,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