Introduce group basic federation, event new page and notifications

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
Thomas Citharel
2020-02-18 08:57:00 +01:00
parent 300ef8f245
commit 4144e9ffd0
416 changed files with 32220 additions and 16750 deletions

View File

@@ -10,11 +10,13 @@ defmodule Mobilizon.Federation.ActivityPubTest do
import Mock
import Mobilizon.Factory
alias Mobilizon.Actors
alias Mobilizon.{Actors, Conversations, Events}
alias Mobilizon.Actors.Actor
alias Mobilizon.Events
alias Mobilizon.Resources.Resource
alias Mobilizon.Todos.{Todo, TodoList}
alias Mobilizon.Federation.ActivityPub
alias Mobilizon.Federation.ActivityPub.Utils
alias Mobilizon.Federation.HTTPSignatures.Signature
@activity_pub_public_audience "https://www.w3.org/ns/activitystreams#Public"
@@ -189,7 +191,7 @@ defmodule Mobilizon.Federation.ActivityPubTest do
end
test "it deletes the original event but only locally if needed" do
with_mock ActivityPub.Utils,
with_mock Utils,
maybe_federate: fn _ -> :ok end,
lazy_put_activity_defaults: fn args -> args end do
event = insert(:event)
@@ -203,21 +205,21 @@ defmodule Mobilizon.Federation.ActivityPubTest do
assert Events.get_event_by_url(event.url) == nil
assert_called(ActivityPub.Utils.maybe_federate(delete))
assert_called(Utils.maybe_federate(delete))
end
end
test "it creates a delete activity and deletes the original comment" do
comment = insert(:comment)
comment = Events.get_comment_from_url_with_preload!(comment.url)
assert is_nil(Events.get_comment_from_url(comment.url).deleted_at)
comment = Conversations.get_comment_from_url_with_preload!(comment.url)
assert is_nil(Conversations.get_comment_from_url(comment.url).deleted_at)
{:ok, delete, _} = ActivityPub.delete(comment)
assert delete.data["type"] == "Delete"
assert delete.data["actor"] == comment.actor.url
assert delete.data["object"] == comment.url
refute is_nil(Events.get_comment_from_url(comment.url).deleted_at)
refute is_nil(Conversations.get_comment_from_url(comment.url).deleted_at)
end
end
@@ -253,4 +255,288 @@ defmodule Mobilizon.Federation.ActivityPubTest do
assert update.data["object"]["startTime"] == DateTime.to_iso8601(@updated_start_time)
end
end
describe "create a todo list" do
@todo_list_title "My TODO-list"
test "it creates a todo list" do
with_mock Utils, [:passthrough], maybe_federate: fn _ -> :ok end do
actor = insert(:actor)
group = insert(:group)
{:ok, create_data, %TodoList{url: todo_list_url}} =
ActivityPub.create(:todo_list, %{title: @todo_list_title, actor_id: group.id}, true, %{
"actor" => actor.url
})
assert create_data.local
assert create_data.data["object"]["id"] == todo_list_url
assert create_data.data["object"]["type"] == "TodoList"
assert create_data.data["object"]["title"] == @todo_list_title
assert create_data.data["to"] == [group.url]
assert create_data.data["actor"] == actor.url
assert_called(Utils.maybe_federate(create_data))
end
end
end
describe "create a todo" do
@todo_title "Finish this thing"
test "it creates a todo" do
with_mock Utils, [:passthrough], maybe_federate: fn _ -> :ok end do
actor = insert(:actor)
todo_list = insert(:todo_list)
{:ok, create_data, %Todo{url: todo_url}} =
ActivityPub.create(
:todo,
%{title: @todo_title, todo_list_id: todo_list.id, creator_id: actor.id},
true,
%{"actor" => actor.url}
)
assert create_data.local
assert create_data.data["object"]["id"] == todo_url
assert create_data.data["object"]["type"] == "Todo"
assert create_data.data["object"]["name"] == @todo_title
assert create_data.data["to"] == [todo_list.actor.url]
assert create_data.data["actor"] == actor.url
assert_called(Utils.maybe_federate(create_data))
end
end
end
@resource_url "https://framasoft.org/fr/full"
@resource_title "my resource"
@updated_resource_title "my updated resource"
@folder_title "my folder"
describe "create resources" do
test "it creates a resource" do
with_mock Utils, [:passthrough], maybe_federate: fn _ -> :ok end do
actor = insert(:actor)
group = insert(:group)
{:ok, create_data, %Resource{url: url}} =
ActivityPub.create(
:resource,
%{
title: @resource_title,
creator_id: actor.id,
actor_id: group.id,
parent_id: nil,
resource_url: @resource_url,
type: :link
},
true
)
assert create_data.local
assert create_data.data["type"] == "Create"
assert create_data.data["object"]["id"] == url
assert create_data.data["object"]["type"] == "Document"
assert create_data.data["object"]["name"] == @resource_title
assert create_data.data["object"]["url"] == @resource_url
assert create_data.data["to"] == [group.url]
assert create_data.data["actor"] == actor.url
assert create_data.data["attributedTo"] == [actor.url]
assert_called(Utils.maybe_federate(create_data))
end
end
test "it creates a folder" do
with_mock Utils, [:passthrough], maybe_federate: fn _ -> :ok end do
actor = insert(:actor)
group = insert(:group)
{:ok, create_data, %Resource{url: url}} =
ActivityPub.create(
:resource,
%{
title: @folder_title,
creator_id: actor.id,
actor_id: group.id,
parent_id: nil,
type: :folder
},
true
)
assert create_data.local
assert create_data.data["type"] == "Create"
assert create_data.data["object"]["id"] == url
assert create_data.data["object"]["type"] == "ResourceCollection"
assert create_data.data["object"]["name"] == @folder_title
assert create_data.data["to"] == [group.url]
assert create_data.data["actor"] == actor.url
assert create_data.data["attributedTo"] == [actor.url]
assert_called(Utils.maybe_federate(create_data))
end
end
test "it creates a resource in a folder" do
with_mock Utils, [:passthrough], maybe_federate: fn _ -> :ok end do
actor = insert(:actor)
group = insert(:group)
%Resource{id: parent_id, url: parent_url} =
insert(:resource, type: :folder, resource_url: nil, actor: group)
{:ok, create_data, %Resource{url: url}} =
ActivityPub.create(
:resource,
%{
title: @resource_title,
creator_id: actor.id,
actor_id: group.id,
parent_id: parent_id,
resource_url: @resource_url,
type: :link
},
true
)
assert create_data.local
assert create_data.data["type"] == "Add"
assert create_data.data["target"] == parent_url
assert create_data.data["object"]["id"] == url
assert create_data.data["object"]["type"] == "Document"
assert create_data.data["object"]["name"] == @resource_title
assert create_data.data["object"]["url"] == @resource_url
assert create_data.data["to"] == [group.url]
assert create_data.data["actor"] == actor.url
assert create_data.data["attributedTo"] == [actor.url]
assert_called(Utils.maybe_federate(create_data))
end
end
end
describe "move resources" do
test "rename resource" do
with_mock Utils, [:passthrough], maybe_federate: fn _ -> :ok end do
actor = insert(:actor)
group = insert(:group)
%Resource{} =
resource =
insert(:resource,
resource_url: @resource_url,
actor: group,
creator: actor,
title: @resource_title
)
{:ok, update_data, %Resource{url: url}} =
ActivityPub.update(
:resource,
resource,
%{
title: @updated_resource_title
},
true
)
assert update_data.local
assert update_data.data["type"] == "Update"
assert update_data.data["object"]["id"] == url
assert update_data.data["object"]["type"] == "Document"
assert update_data.data["object"]["name"] == @updated_resource_title
assert update_data.data["object"]["url"] == @resource_url
assert update_data.data["to"] == [group.url]
assert update_data.data["actor"] == actor.url
assert update_data.data["attributedTo"] == [actor.url]
assert_called(Utils.maybe_federate(update_data))
end
end
test "move resource" do
with_mock Utils, [:passthrough], maybe_federate: fn _ -> :ok end do
actor = insert(:actor)
group = insert(:group)
%Resource{} =
resource =
insert(:resource,
resource_url: @resource_url,
actor: group,
creator: actor,
title: @resource_title
)
%Resource{id: parent_id, url: parent_url} =
insert(:resource, type: :folder, resource_url: nil, actor: group)
{:ok, update_data, %Resource{url: url}} =
ActivityPub.move(
:resource,
resource,
%{
parent_id: parent_id
},
true
)
assert update_data.local
assert update_data.data["type"] == "Move"
assert update_data.data["object"]["id"] == url
assert update_data.data["object"]["type"] == "Document"
assert update_data.data["object"]["name"] == @resource_title
assert update_data.data["object"]["url"] == @resource_url
assert update_data.data["to"] == [group.url]
assert update_data.data["actor"] == actor.url
assert update_data.data["origin"] == nil
assert update_data.data["target"] == parent_url
assert_called(Utils.maybe_federate(update_data))
end
end
end
describe "delete resources" do
test "delete resource" do
with_mock Utils, [:passthrough], maybe_federate: fn _ -> :ok end do
actor = insert(:actor)
group = insert(:group)
%Resource{} =
resource =
insert(:resource,
resource_url: @resource_url,
actor: group,
creator: actor,
title: @resource_title
)
{:ok, update_data, %Resource{url: url}} =
ActivityPub.delete(
resource,
true
)
assert update_data.local
assert update_data.data["type"] == "Delete"
assert update_data.data["object"] == url
assert update_data.data["to"] == [group.url]
# TODO : Add actor parameter to ActivityPub.delete/2
# assert update_data.data["actor"] == actor.url
# assert update_data.data["attributedTo"] == [actor.url]
assert_called(Utils.maybe_federate(update_data))
end
end
end
end

View File

@@ -0,0 +1,39 @@
defmodule Mobilizon.Federation.ActivityPub.RefresherTest do
use Mobilizon.DataCase
alias Mobilizon.Actors.{Actor, Member}
alias Mobilizon.Federation.ActivityPub
alias Mobilizon.Federation.ActivityPub.Refresher
alias Mobilizon.Web.ActivityPub.ActorView
import Mobilizon.Factory
import Mock
test "refreshes a members collection" do
%Actor{members_url: members_url, url: group_url} = group = insert(:group)
%Actor{url: actor_url} = actor = insert(:actor)
%Member{} = insert(:member, parent: group, actor: actor, role: :member)
data =
ActorView.render("members.json", %{group: group, actor_applicant: actor}) |> Jason.encode!()
with_mocks([
{HTTPoison, [],
[
get!: fn ^members_url, _headers, _options ->
%HTTPoison.Response{status_code: 200, body: data}
end
]},
{ActivityPub, [],
[
get_or_fetch_actor_by_url: fn url ->
case url do
^actor_url -> {:ok, actor}
^group_url -> {:ok, group}
end
end
]}
]) do
assert :ok == Refresher.fetch_collection(group.members_url, actor)
end
end
end

View File

@@ -10,15 +10,20 @@ defmodule Mobilizon.Federation.ActivityPub.TransmogrifierTest do
import Mobilizon.Factory
import ExUnit.CaptureLog
import Mock
alias Mobilizon.{Actors, Events, Tombstone}
alias Mobilizon.Actors.Actor
alias Mobilizon.Events.{Comment, Event, Participant}
alias Mobilizon.{Actors, Conversations, Events, Resources, Tombstone}
alias Mobilizon.Actors.{Actor, Member}
alias Mobilizon.Collections.Resource
alias Mobilizon.Conversations.Comment
alias Mobilizon.Events.{Event, Participant}
alias Mobilizon.Resources.Resource
alias Mobilizon.Todos.{Todo, TodoList}
alias Mobilizon.Federation.ActivityPub
alias Mobilizon.Federation.ActivityPub.Utils
alias Mobilizon.Federation.ActivityPub.{Activity, Relay, Transmogrifier}
alias Mobilizon.Federation.ActivityStream.{Convertible}
alias Mobilizon.Federation.ActivityStream.Convertible
alias Mobilizon.GraphQL.API
@@ -77,7 +82,7 @@ defmodule Mobilizon.Federation.ActivityPub.TransmogrifierTest do
end
end
describe "handle incoming notices" do
describe "handle incoming comments" do
test "it ignores an incoming comment if we already have it" do
comment = insert(:comment)
@@ -113,7 +118,7 @@ defmodule Mobilizon.Federation.ActivityPub.TransmogrifierTest do
%Comment{} =
origin_comment =
Events.get_comment_from_url(
Conversations.get_comment_from_url(
"https://blob.cat/objects/02fdea3d-932c-4348-9ecb-3f9eb3fbdd94"
)
@@ -241,7 +246,446 @@ defmodule Mobilizon.Federation.ActivityPub.TransmogrifierTest do
# assert data["object"]["url"] == "https://prismo.news/posts/83"
end
end
describe "handle incoming todo lists" do
test "it ignores an incoming todo list if we already have it" do
todo_list = insert(:todo_list)
actor = insert(:actor)
activity = %{
"type" => "Create",
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
"actor" => actor.url,
"object" => Convertible.model_to_as(todo_list)
}
data =
File.read!("test/fixtures/mastodon-post-activity.json")
|> Jason.decode!()
|> Map.put("object", activity["object"])
assert {:ok, nil, _} = Transmogrifier.handle_incoming(data)
end
test "it accepts incoming todo lists" do
actor = insert(:actor)
group = insert(:group, domain: "morebilizon.com")
activity = %{
"type" => "Create",
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
"actor" => actor.url,
"object" => %{
"type" => "TodoList",
"actor" => group.url,
"id" => "https://mobilizon.app/todo-list/gjfkghfkd",
"name" => "My new todo list"
}
}
assert {:ok, %Activity{data: data, local: false}, %TodoList{}} =
Transmogrifier.handle_incoming(activity)
assert data["actor"] == actor.url
assert data["object"]["actor"] == group.url
end
@mobilizon_group_url "https://mobilizon.app/@mygroupe"
test "it accepts incoming todo lists and fetches the group if needed" do
group = insert(:group, domain: "morebilizon.com", url: @mobilizon_group_url)
%Actor{url: actor_url} = actor = insert(:actor)
with_mock ActivityPub, [:passthrough],
get_or_fetch_actor_by_url: fn url ->
case url do
@mobilizon_group_url -> {:ok, group}
actor_url -> {:ok, actor}
end
end do
activity = %{
"type" => "Create",
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
"actor" => actor.url,
"object" => %{
"type" => "TodoList",
"actor" => @mobilizon_group_url,
"id" => "https://mobilizon.app/todo-list/gjfkghfkd",
"name" => "My new todo list"
}
}
assert {:ok, %Activity{data: data, local: false}, %TodoList{}} =
Transmogrifier.handle_incoming(activity)
assert data["actor"] == actor.url
assert data["object"]["actor"] == @mobilizon_group_url
end
end
test "it accepts incoming todo lists and handles group being not found" do
%Actor{url: actor_url} = actor = insert(:actor)
with_mock ActivityPub, [:passthrough],
get_or_fetch_actor_by_url: fn url ->
case url do
@mobilizon_group_url -> {:error, "Not found"}
^actor_url -> {:ok, actor}
end
end do
activity = %{
"type" => "Create",
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
"actor" => actor_url,
"object" => %{
"type" => "TodoList",
"actor" => @mobilizon_group_url,
"id" => "https://mobilizon.app/todo-list/gjfkghfkd",
"name" => "My new todo list"
}
}
assert :error = Transmogrifier.handle_incoming(activity)
end
end
end
describe "handle incoming todos" do
test "it ignores an incoming todo if we already have it" do
todo = insert(:todo)
actor = insert(:actor)
activity = %{
"type" => "Create",
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
"actor" => actor.url,
"object" => Convertible.model_to_as(todo)
}
data =
File.read!("test/fixtures/mastodon-post-activity.json")
|> Jason.decode!()
|> Map.put("object", activity["object"])
assert {:ok, nil, _} = Transmogrifier.handle_incoming(data)
end
test "it accepts incoming todos" do
actor = insert(:actor)
todo_list = insert(:todo_list)
activity = %{
"type" => "Create",
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
"actor" => actor.url,
"object" => %{
"type" => "Todo",
"actor" => actor.url,
"todoList" => todo_list.url,
"id" => "https://mobilizon.app/todo/gjfkghfkd",
"name" => "My new todo",
"status" => false
}
}
assert {:ok, %Activity{data: data, local: false},
%Todo{todo_list: %TodoList{id: todo_list_id}}} =
Transmogrifier.handle_incoming(activity)
assert data["actor"] == actor.url
assert data["object"]["todoList"] == todo_list.url
assert todo_list_id == todo_list.id
end
@mobilizon_group_url "https://mobilizon.app/@mygroupe"
test "it accepts incoming todos and fetches the todo list if needed" do
group = insert(:group, domain: "morebilizon.com", url: @mobilizon_group_url)
%Actor{url: actor_url} = actor = insert(:actor)
with_mock ActivityPub, [:passthrough],
get_or_fetch_actor_by_url: fn url ->
case url do
@mobilizon_group_url -> {:ok, group}
actor_url -> {:ok, actor}
end
end do
activity = %{
"type" => "Create",
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
"actor" => actor.url,
"object" => %{
"type" => "TodoList",
"actor" => @mobilizon_group_url,
"id" => "https://mobilizon.app/todo-list/gjfkghfkd",
"name" => "My new todo list"
}
}
assert {:ok, %Activity{data: data, local: false}, %TodoList{}} =
Transmogrifier.handle_incoming(activity)
assert data["actor"] == actor.url
assert data["object"]["actor"] == @mobilizon_group_url
end
end
test "it accepts incoming todo lists and handles group being not found" do
%Actor{url: actor_url} = actor = insert(:actor)
with_mock ActivityPub, [:passthrough],
get_or_fetch_actor_by_url: fn url ->
case url do
@mobilizon_group_url -> {:error, "Not found"}
^actor_url -> {:ok, actor}
end
end do
activity = %{
"type" => "Create",
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
"actor" => actor_url,
"object" => %{
"type" => "TodoList",
"actor" => @mobilizon_group_url,
"id" => "https://mobilizon.app/todo-list/gjfkghfkd",
"name" => "My new todo list"
}
}
assert :error = Transmogrifier.handle_incoming(activity)
end
end
end
describe "handle incoming resources" do
test "it ignores an incoming resource if we already have it" do
actor = insert(:actor)
group = insert(:group)
%Resource{} = resource = insert(:resource, actor: group, creator: actor)
activity = %{
"type" => "Add",
"to" => [group.url],
"actor" => actor.url,
"target" => group.resources_url,
"object" => Convertible.model_to_as(resource)
}
assert {:ok, nil, _} = Transmogrifier.handle_incoming(activity)
end
test "it accepts incoming resources" do
creator =
insert(:actor,
domain: "mobilizon.app",
url: "https://mobilizon.app/@myremoteactor",
preferred_username: "myremoteactor"
)
group =
insert(:group,
domain: "somewhere.com",
url: "https://somewhere.com/@myremotegroup",
preferred_username: "myremotegroup"
)
insert(:member, parent: group, actor: creator, role: :member)
activity = %{
"type" => "Add",
"to" => [group.url],
"actor" => creator.url,
"target" => group.resources_url,
"object" => %{
"type" => "Document",
"actor" => creator.url,
"attributedTo" => [group.url],
"id" => "https://mobilizon.app/resource/gjfkghfkd",
"name" => "My new resource",
"summary" => "A description for the resource",
"url" => "https://framasoft.org"
}
}
assert {:ok, %Activity{data: data, local: false}, %Resource{} = resource} =
Transmogrifier.handle_incoming(activity)
assert resource.actor_id == group.id
assert resource.creator_id == creator.id
assert resource.title == "My new resource"
assert resource.type == :link
assert is_nil(resource.parent_id)
end
test "it accepts incoming folders" do
creator =
insert(:actor,
domain: "mobilizon.app",
url: "https://mobilizon.app/@myremoteactor",
preferred_username: "myremoteactor"
)
group =
insert(:group,
domain: "somewhere.com",
url: "https://somewhere.com/@myremotegroup",
preferred_username: "myremotegroup"
)
insert(:member, parent: group, actor: creator, role: :member)
activity = %{
"type" => "Add",
"to" => [group.url],
"actor" => creator.url,
"target" => group.resources_url,
"object" => %{
"type" => "ResourceCollection",
"actor" => creator.url,
"attributedTo" => [group.url],
"id" => "https://mobilizon.app/resource/gjfkghfkd",
"name" => "My new folder"
}
}
assert {:ok, %Activity{data: data, local: false}, %Resource{} = resource} =
Transmogrifier.handle_incoming(activity)
assert resource.actor_id == group.id
assert resource.creator_id == creator.id
assert resource.title == "My new folder"
assert resource.type == :folder
assert is_nil(resource.parent_id)
end
@parent_url "http://mobilizon1.com/resource/e4ce71bd-6bcc-4c61-9774-7999dde0cc68"
test "it accepts incoming resources that are in a folder" do
creator =
insert(:actor,
domain: "mobilizon1.com",
url: "http://mobilizon1.com/@tcit",
preferred_username: "tcit",
user: nil
)
group =
insert(:group,
domain: "mobilizon1.com",
url: "http://mobilizon1.com/@demo",
preferred_username: "demo",
resources_url: "http://mobilizon1.com/@demo/resources"
)
insert(:member, parent: group, actor: creator, role: :member)
parent_resource =
insert(:resource,
type: :folder,
title: "folder",
path: "/folder",
actor: group,
creator: creator
)
activity = %{
"type" => "Add",
"to" => [group.url],
"actor" => creator.url,
"target" => parent_resource.url,
"object" => %{
"type" => "Document",
"actor" => creator.url,
"attributedTo" => [group.url],
"id" => "https://mobilizon.app/resource/gjfkghfkd",
"name" => "My new resource",
"summary" => "A description for the resource",
"context" => parent_resource.url,
"url" => "https://framasoft.org"
}
}
assert {:ok, %Activity{data: data, local: false}, %Resource{} = resource} =
Transmogrifier.handle_incoming(activity)
assert resource.actor_id == group.id
assert resource.creator_id == creator.id
assert resource.title == "My new resource"
assert resource.type == :link
refute is_nil(resource.parent_id)
assert resource.parent_id == parent_resource.id
end
test "it accepts incoming resources and handles group being not found" do
creator =
insert(:actor,
domain: "mobilizon.app",
url: "https://mobilizon.app/@myremoteactor",
preferred_username: "myremoteactor"
)
group =
insert(:group,
domain: "somewhere.com",
url: "https://somewhere.com/@myremotegroup",
preferred_username: "myremotegroup"
)
insert(:member, parent: group, actor: creator, role: :member)
activity = %{
"type" => "Add",
"to" => [group.url],
"actor" => creator.url,
"target" => group.resources_url,
"object" => %{
"type" => "Document",
"actor" => "https://someurl.com/notfound",
"attributedTo" => "https://someurl.com/notfound",
"id" => "https://mobilizon.app/resource/gjfkghfkd",
"name" => "My new resource",
"summary" => "A description for the resource",
"url" => "https://framasoft.org"
}
}
assert :error = Transmogrifier.handle_incoming(activity)
end
test "it refuses incoming resources if actor is not a member of the group" do
creator =
insert(:actor,
domain: "mobilizon.app",
url: "https://mobilizon.app/@myremoteactor",
preferred_username: "myremoteactor"
)
group =
insert(:group,
domain: "somewhere.com",
url: "https://somewhere.com/@myremotegroup",
preferred_username: "myremotegroup"
)
activity = %{
"type" => "Add",
"to" => [group.url],
"actor" => creator.url,
"target" => group.resources_url,
"object" => %{
"type" => "Document",
"actor" => creator.url,
"attributedTo" => [group.url],
"id" => "https://mobilizon.app/resource/gjfkghfkd",
"name" => "My new resource",
"summary" => "A description for the resource",
"url" => "https://framasoft.org"
}
}
assert :error = Transmogrifier.handle_incoming(activity)
end
end
describe "handle incoming follow requests" do
test "it works for incoming follow requests" do
use_cassette "activity_pub/mastodon_follow_activity" do
actor = insert(:actor)
@@ -262,6 +706,18 @@ defmodule Mobilizon.Federation.ActivityPub.TransmogrifierTest do
end
end
test "it rejects activities without a valid ID" do
actor = insert(:actor)
data =
File.read!("test/fixtures/mastodon-follow-activity.json")
|> Jason.decode!()
|> Map.put("object", actor.url)
|> Map.put("id", "")
:error = Transmogrifier.handle_incoming(data)
end
# test "it works for incoming follow requests from hubzilla" do
# user = insert(:user)
@@ -278,58 +734,60 @@ defmodule Mobilizon.Federation.ActivityPub.TransmogrifierTest do
# assert data["id"] == "https://hubzilla.example.org/channel/kaniini#follows/2"
# assert User.is_following(User.get_by_ap_id(data["actor"]), user)
# end
end
# test "it works for incoming likes" do
# %Comment{url: url} = insert(:comment)
# test "it works for incoming likes" do
# %Comment{url: url} = insert(:comment)
# data =
# File.read!("test/fixtures/mastodon-like.json")
# |> Jason.decode!()
# |> Map.put("object", url)
# data =
# File.read!("test/fixtures/mastodon-like.json")
# |> Jason.decode!()
# |> Map.put("object", url)
# {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
# {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
# assert data["actor"] == "http://mastodon.example.org/users/admin"
# assert data["type"] == "Like"
# assert data["id"] == "http://mastodon.example.org/users/admin#likes/2"
# assert data["object"] == url
# end
# assert data["actor"] == "http://mastodon.example.org/users/admin"
# assert data["type"] == "Like"
# assert data["id"] == "http://mastodon.example.org/users/admin#likes/2"
# assert data["object"] == url
# end
# test "it returns an error for incoming unlikes wihout a like activity" do
# %Comment{url: url} = insert(:comment)
# test "it returns an error for incoming unlikes wihout a like activity" do
# %Comment{url: url} = insert(:comment)
# data =
# File.read!("test/fixtures/mastodon-undo-like.json")
# |> Jason.decode!()
# |> Map.put("object", url)
# data =
# File.read!("test/fixtures/mastodon-undo-like.json")
# |> Jason.decode!()
# |> Map.put("object", url)
# assert Transmogrifier.handle_incoming(data) == {:error, :not_supported}
# end
# assert Transmogrifier.handle_incoming(data) == {:error, :not_supported}
# end
# test "it works for incoming unlikes with an existing like activity" do
# comment = insert(:comment)
# test "it works for incoming unlikes with an existing like activity" do
# comment = insert(:comment)
# like_data =
# File.read!("test/fixtures/mastodon-like.json")
# |> Jason.decode!()
# |> Map.put("object", comment.url)
# like_data =
# File.read!("test/fixtures/mastodon-like.json")
# |> Jason.decode!()
# |> Map.put("object", comment.url)
# {:ok, %Activity{data: like_data, local: false}} = Transmogrifier.handle_incoming(like_data)
# {:ok, %Activity{data: like_data, local: false}} = Transmogrifier.handle_incoming(like_data)
# data =
# File.read!("test/fixtures/mastodon-undo-like.json")
# |> Jason.decode!()
# |> Map.put("object", like_data)
# |> Map.put("actor", like_data["actor"])
# data =
# File.read!("test/fixtures/mastodon-undo-like.json")
# |> Jason.decode!()
# |> Map.put("object", like_data)
# |> Map.put("actor", like_data["actor"])
# {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
# {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
# assert data["actor"] == "http://mastodon.example.org/users/admin"
# assert data["type"] == "Undo"
# assert data["id"] == "http://mastodon.example.org/users/admin#likes/2/undo"
# assert data["object"]["id"] == "http://mastodon.example.org/users/admin#likes/2"
# end
# assert data["actor"] == "http://mastodon.example.org/users/admin"
# assert data["type"] == "Undo"
# assert data["id"] == "http://mastodon.example.org/users/admin#likes/2/undo"
# assert data["object"]["id"] == "http://mastodon.example.org/users/admin#likes/2"
# end
describe "handle incoming follow announces" do
test "it works for incoming announces" do
use_cassette "activity_pub/mastodon_announce_activity" do
data = File.read!("test/fixtures/mastodon-announce.json") |> Jason.decode!()
@@ -345,7 +803,7 @@ defmodule Mobilizon.Federation.ActivityPub.TransmogrifierTest do
assert data["object"] ==
"https://framapiaf.org/users/Framasoft/statuses/102501959686438400"
assert %Comment{} = Events.get_comment_from_url(data["object"])
assert %Comment{} = Conversations.get_comment_from_url(data["object"])
end
end
@@ -369,7 +827,9 @@ defmodule Mobilizon.Federation.ActivityPub.TransmogrifierTest do
assert data["object"] == comment.url
end
end
end
describe "handle incoming update activities" do
test "it works for incoming update activities on actors" do
use_cassette "activity_pub/update_actor_activity" do
data = File.read!("test/fixtures/mastodon-post-activity.json") |> Jason.decode!()
@@ -448,7 +908,9 @@ defmodule Mobilizon.Federation.ActivityPub.TransmogrifierTest do
# user = User.get_cached_by_ap_id(data["actor"])
# assert user.info["locked"] == true
# end
end
describe "handle incoming delete activities" do
test "it works for incoming deletes" do
%Actor{url: actor_url} = actor = insert(:actor)
%Comment{url: comment_url} = insert(:comment, actor: nil, actor_id: actor.id)
@@ -466,12 +928,12 @@ defmodule Mobilizon.Federation.ActivityPub.TransmogrifierTest do
|> Map.put("object", object)
|> Map.put("actor", actor_url)
assert Events.get_comment_from_url(comment_url)
assert is_nil(Events.get_comment_from_url(comment_url).deleted_at)
assert Conversations.get_comment_from_url(comment_url)
assert is_nil(Conversations.get_comment_from_url(comment_url).deleted_at)
{:ok, %Activity{local: false}, _} = Transmogrifier.handle_incoming(data)
refute is_nil(Events.get_comment_from_url(comment_url).deleted_at)
refute is_nil(Conversations.get_comment_from_url(comment_url).deleted_at)
end
test "it fails for incoming deletes with spoofed origin" do
@@ -498,7 +960,7 @@ defmodule Mobilizon.Federation.ActivityPub.TransmogrifierTest do
:error = Transmogrifier.handle_incoming(data)
assert Events.get_comment_from_url(comment.url)
assert Conversations.get_comment_from_url(comment.url)
end
test "it works for incoming actor deletes" do
@@ -519,7 +981,7 @@ defmodule Mobilizon.Federation.ActivityPub.TransmogrifierTest do
assert {:ok, %Actor{suspended: true}} = Actors.get_actor_by_url(url)
assert {:error, :event_not_found} = Events.get_event(event1.id)
assert %Tombstone{} = Tombstone.find_tombstone(event1_url)
assert %Comment{deleted_at: deleted_at} = Events.get_comment(comment1.id)
assert %Comment{deleted_at: deleted_at} = Conversations.get_comment(comment1.id)
refute is_nil(deleted_at)
assert %Tombstone{} = Tombstone.find_tombstone(comment1_url)
end
@@ -538,7 +1000,9 @@ defmodule Mobilizon.Federation.ActivityPub.TransmogrifierTest do
assert Actors.get_actor_by_url(url)
end
end
describe "handle incoming undo activities" do
test "it works for incoming unannounces with an existing notice" do
use_cassette "activity_pub/mastodon_unannounce_activity" do
comment = insert(:comment)
@@ -595,83 +1059,85 @@ defmodule Mobilizon.Federation.ActivityPub.TransmogrifierTest do
refute Actors.is_following(followed, actor)
end
end
end
# test "it works for incoming blocks" do
# user = insert(:user)
# test "it works for incoming blocks" do
# user = insert(:user)
# data =
# File.read!("test/fixtures/mastodon-block-activity.json")
# |> Jason.decode!()
# |> Map.put("object", user.ap_id)
# data =
# File.read!("test/fixtures/mastodon-block-activity.json")
# |> Jason.decode!()
# |> Map.put("object", user.ap_id)
# {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
# {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
# assert data["type"] == "Block"
# assert data["object"] == user.ap_id
# assert data["actor"] == "http://mastodon.example.org/users/admin"
# assert data["type"] == "Block"
# assert data["object"] == user.ap_id
# assert data["actor"] == "http://mastodon.example.org/users/admin"
# blocker = User.get_by_ap_id(data["actor"])
# blocker = User.get_by_ap_id(data["actor"])
# assert User.blocks?(blocker, user)
# end
# assert User.blocks?(blocker, user)
# end
# test "incoming blocks successfully tear down any follow relationship" do
# blocker = insert(:user)
# blocked = insert(:user)
# test "incoming blocks successfully tear down any follow relationship" do
# blocker = insert(:user)
# blocked = insert(:user)
# data =
# File.read!("test/fixtures/mastodon-block-activity.json")
# |> Jason.decode!()
# |> Map.put("object", blocked.ap_id)
# |> Map.put("actor", blocker.ap_id)
# data =
# File.read!("test/fixtures/mastodon-block-activity.json")
# |> Jason.decode!()
# |> Map.put("object", blocked.ap_id)
# |> Map.put("actor", blocker.ap_id)
# {:ok, blocker} = User.follow(blocker, blocked)
# {:ok, blocked} = User.follow(blocked, blocker)
# {:ok, blocker} = User.follow(blocker, blocked)
# {:ok, blocked} = User.follow(blocked, blocker)
# assert User.following?(blocker, blocked)
# assert User.following?(blocked, blocker)
# assert User.following?(blocker, blocked)
# assert User.following?(blocked, blocker)
# {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
# {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
# assert data["type"] == "Block"
# assert data["object"] == blocked.ap_id
# assert data["actor"] == blocker.ap_id
# assert data["type"] == "Block"
# assert data["object"] == blocked.ap_id
# assert data["actor"] == blocker.ap_id
# blocker = User.get_by_ap_id(data["actor"])
# blocked = User.get_by_ap_id(data["object"])
# blocker = User.get_by_ap_id(data["actor"])
# blocked = User.get_by_ap_id(data["object"])
# assert User.blocks?(blocker, blocked)
# assert User.blocks?(blocker, blocked)
# refute User.following?(blocker, blocked)
# refute User.following?(blocked, blocker)
# end
# refute User.following?(blocker, blocked)
# refute User.following?(blocked, blocker)
# end
# test "it works for incoming unblocks with an existing block" do
# user = insert(:user)
# test "it works for incoming unblocks with an existing block" do
# user = insert(:user)
# block_data =
# File.read!("test/fixtures/mastodon-block-activity.json")
# |> Jason.decode!()
# |> Map.put("object", user.ap_id)
# block_data =
# File.read!("test/fixtures/mastodon-block-activity.json")
# |> Jason.decode!()
# |> Map.put("object", user.ap_id)
# {:ok, %Activity{data: _, local: false}} = Transmogrifier.handle_incoming(block_data)
# {:ok, %Activity{data: _, local: false}} = Transmogrifier.handle_incoming(block_data)
# data =
# File.read!("test/fixtures/mastodon-unblock-activity.json")
# |> Jason.decode!()
# |> Map.put("object", block_data)
# data =
# File.read!("test/fixtures/mastodon-unblock-activity.json")
# |> Jason.decode!()
# |> Map.put("object", block_data)
# {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
# assert data["type"] == "Undo"
# assert data["object"]["type"] == "Block"
# assert data["object"]["object"] == user.ap_id
# assert data["actor"] == "http://mastodon.example.org/users/admin"
# {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
# assert data["type"] == "Undo"
# assert data["object"]["type"] == "Block"
# assert data["object"]["object"] == user.ap_id
# assert data["actor"] == "http://mastodon.example.org/users/admin"
# blocker = User.get_by_ap_id(data["actor"])
# blocker = User.get_by_ap_id(data["actor"])
# refute User.blocks?(blocker, user)
# end
# refute User.blocks?(blocker, user)
# end
describe "handle incoming follow accept activities" do
test "it works for incoming accepts which were pre-accepted" do
follower = insert(:actor)
followed = insert(:actor)
@@ -743,7 +1209,9 @@ defmodule Mobilizon.Federation.ActivityPub.TransmogrifierTest do
refute Actors.is_following(follower, followed)
end
end
describe "handle incoming follow reject activities" do
test "it fails for incoming rejects which cannot be correlated" do
follower = insert(:actor)
followed = insert(:actor)
@@ -781,19 +1249,9 @@ defmodule Mobilizon.Federation.ActivityPub.TransmogrifierTest do
refute Actors.is_following(follower, followed)
end
end
test "it rejects activities without a valid ID" do
actor = insert(:actor)
data =
File.read!("test/fixtures/mastodon-follow-activity.json")
|> Jason.decode!()
|> Map.put("object", actor.url)
|> Map.put("id", "")
:error = Transmogrifier.handle_incoming(data)
end
describe "handle incoming flag activities" do
test "it accepts Flag activities" do
%Actor{url: reporter_url} = Relay.get_actor()
%Actor{url: reported_url} = reported = insert(:actor)
@@ -817,7 +1275,9 @@ defmodule Mobilizon.Federation.ActivityPub.TransmogrifierTest do
assert activity.data["actor"] == reporter_url
assert activity.data["cc"] == []
end
end
describe "handle incoming join activities" do
@join_message "I want to get in!"
test "it accepts Join activities" do
%Actor{url: organizer_url} = organizer = insert(:actor)
@@ -846,7 +1306,9 @@ defmodule Mobilizon.Federation.ActivityPub.TransmogrifierTest do
assert activity.data["actor"] == organizer_url
assert activity.data["id"] =~ "/accept/join/"
end
end
describe "handle incoming accept join activities" do
test "it accepts Accept activities for Join activities" do
%Actor{url: organizer_url} = organizer = insert(:actor)
%Actor{} = participant_actor = insert(:actor)
@@ -870,7 +1332,9 @@ defmodule Mobilizon.Federation.ActivityPub.TransmogrifierTest do
# We don't accept already accepted Accept activities
:error = Transmogrifier.handle_incoming(accept_data)
end
end
describe "handle incoming reject join activities" do
test "it accepts Reject activities for Join activities" do
%Actor{url: organizer_url} = organizer = insert(:actor)
%Actor{} = participant_actor = insert(:actor)
@@ -905,7 +1369,9 @@ defmodule Mobilizon.Federation.ActivityPub.TransmogrifierTest do
|> Enum.map(& &1.id) ==
[]
end
end
describe "handle incoming leave activities on events" do
test "it accepts Leave activities" do
%Actor{url: _organizer_url} = organizer = insert(:actor)
%Actor{url: participant_url} = participant_actor = insert(:actor)
@@ -955,6 +1421,58 @@ defmodule Mobilizon.Federation.ActivityPub.TransmogrifierTest do
end
end
describe "handle Invite activities on group" do
test "it accepts Invite activities" do
%Actor{url: group_url, id: group_id} = group = insert(:group)
%Actor{url: group_admin_url, id: group_admin_id} = group_admin = insert(:actor)
%Member{} =
_group_admin_member =
insert(:member, parent: group, actor: group_admin, role: :administrator)
%Actor{url: invitee_url, id: invitee_id} = _invitee = insert(:actor)
invite_data =
File.read!("test/fixtures/mobilizon-invite-activity.json")
|> Jason.decode!()
|> Map.put("actor", group_admin_url)
|> Map.put("object", group_url)
|> Map.put("target", invitee_url)
assert {:ok, activity, %Member{}} = Transmogrifier.handle_incoming(invite_data)
assert %Member{} = member = Actors.get_member_by_url(invite_data["id"])
assert member.actor.id == invitee_id
assert member.parent.id == group_id
assert member.role == :invited
assert member.invited_by_id == group_admin_id
end
test "it refuses Invite activities for " do
%Actor{url: group_url, id: group_id} = group = insert(:group)
%Actor{url: group_admin_url, id: group_admin_id} = group_admin = insert(:actor)
%Member{} =
_group_admin_member =
insert(:member, parent: group, actor: group_admin, role: :administrator)
%Actor{url: invitee_url, id: invitee_id} = _invitee = insert(:actor)
invite_data =
File.read!("test/fixtures/mobilizon-invite-activity.json")
|> Jason.decode!()
|> Map.put("actor", group_admin_url)
|> Map.put("object", group_url)
|> Map.put("target", invitee_url)
assert {:ok, activity, %Member{}} = Transmogrifier.handle_incoming(invite_data)
assert %Member{} = member = Actors.get_member_by_url(invite_data["id"])
assert member.actor.id == invitee_id
assert member.parent.id == group_id
assert member.role == :invited
assert member.invited_by_id == group_admin_id
end
end
describe "prepare outgoing" do
test "it turns mentions into tags" do
actor = insert(:actor)

View File

@@ -16,7 +16,7 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.ActorTest do
describe "AS to Actor" do
test "valid as data to model" do
{:ok, actor} =
actor =
ActorConverter.as_to_model_data(%{
"id" => "https://somedomain.tld/users/someone",
"type" => "Person",

View File

@@ -0,0 +1,42 @@
{
"type": "Invite",
"signature": {
"type": "RsaSignature2017",
"signatureValue": "Kn1/UkAQGJVaXBfWLAHcnwHg8YMAUqlEaBuYLazAG+pz5hqivsyrBmPV186Xzr+B4ZLExA9+SnOoNx/GOz4hBm0kAmukNSILAsUd84tcJ2yT9zc1RKtembK4WiwOw7li0+maeDN0HaB6t+6eTqsCWmtiZpprhXD8V1GGT8yG7X24fQ9oFGn+ng7lasbcCC0988Y1eGqNe7KryxcPuQz57YkDapvtONzk8gyLTkZMV4De93MyRHq6GVjQVIgtiYabQAxrX6Q8C+4P/jQoqdWJHEe+MY5JKyNaT/hMPt2Md1ok9fZQBGHlErk22/zy8bSN19GdG09HmIysBUHRYpBLig==",
"creator": "http://mobilizon.test/users/tcit#main-key",
"created": "2018-02-17T13:29:31Z"
},
"object": "http://mobilizon.test/@mygroup",
"id": "http://mobilizon2.test/member/some-uuid",
"actor": "http://mobilizon2.test/@admin",
"target": "http://mobilizon.test/@someuser",
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://litepub.social/litepub/context.jsonld",
{
"Hashtag": "as:Hashtag",
"category": "sc:category",
"ical": "http://www.w3.org/2002/12/cal/ical#",
"joinMode": {
"@id": "mz:joinMode",
"@type": "mz:joinModeType"
},
"joinModeType": {
"@id": "mz:joinModeType",
"@type": "rdfs:Class"
},
"maximumAttendeeCapacity": "sc:maximumAttendeeCapacity",
"mz": "https://joinmobilizon.org/ns#",
"repliesModerationOption": {
"@id": "mz:repliesModerationOption",
"@type": "mz:repliesModerationOptionType"
},
"repliesModerationOptionType": {
"@id": "mz:repliesModerationOptionType",
"@type": "rdfs:Class"
},
"sc": "http://schema.org#",
"uuid": "sc:identifier"
}
]
}

View File

@@ -0,0 +1,84 @@
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://litepub.social/litepub/context.jsonld",
{
"Hashtag": "as:Hashtag",
"PostalAddress": "sc:PostalAddress",
"address": {
"@id": "sc:address",
"@type": "sc:PostalAddress"
},
"addressCountry": "sc:addressCountry",
"addressLocality": "sc:addressLocality",
"addressRegion": "sc:addressRegion",
"anonymousParticipationEnabled": {
"@id": "mz:anonymousParticipationEnabled",
"@type": "sc:Boolean"
},
"category": "sc:category",
"commentsEnabled": {
"@id": "pt:commentsEnabled",
"@type": "sc:Boolean"
},
"ical": "http://www.w3.org/2002/12/cal/ical#",
"joinMode": {
"@id": "mz:joinMode",
"@type": "mz:joinModeType"
},
"joinModeType": {
"@id": "mz:joinModeType",
"@type": "rdfs:Class"
},
"location": {
"@id": "sc:location",
"@type": "sc:Place"
},
"maximumAttendeeCapacity": "sc:maximumAttendeeCapacity",
"mz": "https://joinmobilizon.org/ns#",
"participationMessage": {
"@id": "mz:participationMessage",
"@type": "sc:Text"
},
"postalCode": "sc:postalCode",
"pt": "https://joinpeertube.org/ns#",
"repliesModerationOption": {
"@id": "mz:repliesModerationOption",
"@type": "mz:repliesModerationOptionType"
},
"repliesModerationOptionType": {
"@id": "mz:repliesModerationOptionType",
"@type": "rdfs:Class"
},
"sc": "http://schema.org#",
"streetAddress": "sc:streetAddress",
"uuid": "sc:identifier"
}
],
"attributedTo": "http://mobilizon.test/@demo",
"first": {
"attributedTo": "http://mobilizon.test/@demo",
"id": "http://mobilizon.test/@demo/members?page=1",
"orderedItems": [
{
"actor": "http://mobilizon.test/@tcit",
"id": "http://mobilizon.test/member/2fec2e84-5719-48f9-92bd-077f50ff2e6e",
"object": "http://mobilizon.test/@demo",
"role": "administrator",
"type": "Member"
},
{
"actor": "http://mobilizon2.com/@tcit",
"id": "http://mobilizon.test/member/13b0fc1e-2ceb-401c-bef7-0eba02fb92dc",
"object": "http://mobilizon.test/@demo",
"role": "member",
"type": "Member"
}
],
"partOf": "http://mobilizon.test/@demo/members",
"type": "OrderedCollectionPage"
},
"id": "http://mobilizon.test/@demo/members",
"totalItems": 2,
"type": "OrderedCollection"
}

File diff suppressed because one or more lines are too long

View File

@@ -4,7 +4,8 @@ defmodule Mobilizon.GraphQL.API.ReportTest do
import Mobilizon.Factory
alias Mobilizon.Actors.Actor
alias Mobilizon.Events.{Comment, Event}
alias Mobilizon.Conversations.Comment
alias Mobilizon.Events.Event
alias Mobilizon.Reports.{Note, Report}
alias Mobilizon.Users
alias Mobilizon.Users.User

View File

@@ -207,7 +207,7 @@ defmodule Mobilizon.Web.Resolvers.EventTest do
assert res["data"]["createEvent"]["title"] == "My Event title"
assert res["data"]["createEvent"]["description"] ==
"<b>My description</b> <img src=\"http://placekitten.com/g/200/300\" />"
"<b>My description</b> <img src=\"http://placekitten.com/g/200/300\"/>"
{id, ""} = res["data"]["createEvent"]["id"] |> Integer.parse()

View File

@@ -15,7 +15,7 @@ defmodule Mobilizon.Web.Resolvers.GroupTest do
{:ok, conn: conn, actor: actor, user: user}
end
describe "Group Resolver" do
describe "create a group" do
test "create_group/3 should check the user owns the identity", %{conn: conn, user: user} do
another_actor = insert(:actor)
@@ -84,65 +84,130 @@ defmodule Mobilizon.Web.Resolvers.GroupTest do
assert hd(json_response(res, 200)["errors"])["message"] ==
"A group with this name already exists"
end
end
test "list_groups/3 returns all public or unlisted groups", context do
describe "list groups" do
test "list_groups/3 returns all public or unlisted groups", %{conn: conn} do
group = insert(:group, visibility: :unlisted)
insert(:group, visibility: :private)
query = """
{
groups {
preferredUsername,
elements {
preferredUsername,
},
total
}
}
"""
res =
context.conn
|> get("/api", AbsintheHelpers.query_skeleton(query, "groups"))
res = AbsintheHelpers.graphql_query(conn, query: query)
assert length(json_response(res, 200)["data"]["groups"]) == 1
assert res["data"]["groups"]["total"] == 1
assert hd(json_response(res, 200)["data"]["groups"])["preferredUsername"] ==
assert hd(res["data"]["groups"]["elements"])["preferredUsername"] ==
group.preferred_username
end
end
test "find_group/3 returns a group by its username", context do
group = insert(:group)
query = """
{
group(preferredUsername: "#{group.preferred_username}") {
describe "find a group" do
@group_query """
query Group($preferredUsername: String!) {
group(preferredUsername: $preferredUsername) {
preferredUsername,
members {
total,
elements {
role,
actor {
preferredUsername
}
}
}
}
}
"""
"""
test "find_group/3 returns a group by its username", %{conn: conn, actor: actor, user: user} do
group = insert(:group)
insert(:member, parent: group, actor: actor, role: :administrator)
insert(:member, parent: group, role: :member)
res =
context.conn
|> get("/api", AbsintheHelpers.query_skeleton(query, "group"))
conn
|> AbsintheHelpers.graphql_query(
query: @group_query,
variables: %{
preferredUsername: group.preferred_username
}
)
assert json_response(res, 200)["data"]["group"]["preferredUsername"] ==
assert res["errors"] == nil
assert res["data"]["group"]["preferredUsername"] ==
group.preferred_username
query = """
{
group(preferredUsername: "#{@non_existent_username}") {
preferredUsername,
}
}
"""
assert res["data"]["group"]["members"]["total"] == 2
res =
context.conn
|> get("/api", AbsintheHelpers.query_skeleton(query, "group"))
conn
|> auth_conn(user)
|> AbsintheHelpers.graphql_query(
query: @group_query,
variables: %{
preferredUsername: group.preferred_username,
actorId: actor.id
}
)
assert json_response(res, 200)["data"]["group"] == nil
assert res["errors"] == nil
assert hd(json_response(res, 200)["errors"])["message"] ==
assert res["data"]["group"]["members"]["total"] == 2
assert hd(res["data"]["group"]["members"]["elements"])["role"] == "ADMINISTRATOR"
assert hd(res["data"]["group"]["members"]["elements"])["actor"]["preferredUsername"] ==
actor.preferred_username
res =
conn
|> AbsintheHelpers.graphql_query(
query: @group_query,
variables: %{preferredUsername: @non_existent_username}
)
assert res["data"]["group"] == nil
assert hd(res["errors"])["message"] ==
"Group with name #{@non_existent_username} not found"
end
test "find_group doesn't list group members access if group is private", %{
conn: conn,
actor: actor
} do
group = insert(:group, visibility: :private)
insert(:member, parent: group, actor: actor, role: :administrator)
res =
conn
|> AbsintheHelpers.graphql_query(
query: @group_query,
variables: %{
preferredUsername: group.preferred_username
}
)
assert res["errors"] == nil
assert res["data"]["group"]["preferredUsername"] ==
group.preferred_username
assert res["data"]["group"]["members"] == %{"elements" => [], "total" => 1}
end
end
describe "delete a group" do
test "delete_group/3 deletes a group", %{conn: conn, user: user, actor: actor} do
group = insert(:group)
insert(:member, parent: group, actor: actor, role: :administrator)

View File

@@ -12,7 +12,7 @@ defmodule Mobilizon.GraphQL.Resolvers.MemberTest do
{:ok, conn: conn, actor: actor, user: user}
end
describe "Member Resolver" do
describe "Member Resolver to join a group" do
test "join_group/3 should create a member", %{conn: conn, user: user, actor: actor} do
group = insert(:group)
@@ -39,7 +39,7 @@ defmodule Mobilizon.GraphQL.Resolvers.MemberTest do
|> post("/api", AbsintheHelpers.mutation_skeleton(mutation))
assert json_response(res, 200)["errors"] == nil
assert json_response(res, 200)["data"]["joinGroup"]["role"] == "not_approved"
assert json_response(res, 200)["data"]["joinGroup"]["role"] == "NOT_APPROVED"
assert json_response(res, 200)["data"]["joinGroup"]["parent"]["id"] == to_string(group.id)
assert json_response(res, 200)["data"]["joinGroup"]["actor"]["id"] == to_string(actor.id)
@@ -136,7 +136,9 @@ defmodule Mobilizon.GraphQL.Resolvers.MemberTest do
assert hd(json_response(res, 200)["errors"])["message"] =~ "Group id not found"
end
end
describe "Member Resolver to leave from a group" do
test "leave_group/3 should delete a member from a group", %{
conn: conn,
user: user,
@@ -286,4 +288,211 @@ defmodule Mobilizon.GraphQL.Resolvers.MemberTest do
assert hd(json_response(res, 200)["errors"])["message"] =~ "Member not found"
end
end
describe "Member Resolver to invite to a group" do
@invite_member_mutation """
mutation InviteMember($groupId: ID!, $targetActorUsername: String!) {
inviteMember(groupId: $groupId, targetActorUsername: $targetActorUsername) {
parent {
id
},
actor {
id
},
role
}
}
"""
setup %{conn: conn, actor: actor, user: user} do
group = insert(:group)
target_actor = insert(:actor, user: user)
{:ok, conn: conn, actor: actor, user: user, group: group, target_actor: target_actor}
end
test "invite_member/3 invites a local actor to a group", %{
conn: conn,
user: user,
actor: actor,
group: group,
target_actor: target_actor
} do
_admin_member = insert(:member, %{actor: actor, parent: group, role: :creator})
res =
conn
|> auth_conn(user)
|> AbsintheHelpers.graphql_query(
query: @invite_member_mutation,
variables: %{
groupId: group.id,
targetActorUsername: target_actor.preferred_username
}
)
assert is_nil(res["errors"])
assert res["data"]["inviteMember"]["role"] == "INVITED"
assert res["data"]["inviteMember"]["parent"]["id"] == to_string(group.id)
assert res["data"]["inviteMember"]["actor"]["id"] == to_string(target_actor.id)
end
test "invite_member/3 invites a remote actor to a group", %{
conn: conn,
user: user,
actor: actor,
group: group
} do
_admin_member = insert(:member, %{actor: actor, parent: group, role: :creator})
target_actor = insert(:actor, domain: "remote.tld")
res =
conn
|> auth_conn(user)
|> AbsintheHelpers.graphql_query(
query: @invite_member_mutation,
variables: %{
groupId: group.id,
targetActorUsername: "#{target_actor.preferred_username}@#{target_actor.domain}"
}
)
assert is_nil(res["errors"])
assert res["data"]["inviteMember"]["role"] == "INVITED"
assert res["data"]["inviteMember"]["parent"]["id"] == to_string(group.id)
assert res["data"]["inviteMember"]["actor"]["id"] == to_string(target_actor.id)
end
test "invite_member/3 fails to invite a local actor to a group that invitor isn't in", %{
conn: conn,
user: user,
actor: actor,
group: group,
target_actor: target_actor
} do
res =
conn
|> auth_conn(user)
|> AbsintheHelpers.graphql_query(
query: @invite_member_mutation,
variables: %{
groupId: group.id,
targetActorUsername: target_actor.preferred_username
}
)
assert hd(res["errors"])["message"] == "You are not a member of this group"
end
test "invite_member/3 fails to invite a non existing local actor", %{
conn: conn,
user: user,
actor: actor,
group: group
} do
insert(:member, %{actor: actor, parent: group, role: :administrator})
res =
conn
|> auth_conn(user)
|> AbsintheHelpers.graphql_query(
query: @invite_member_mutation,
variables: %{
groupId: group.id,
targetActorUsername: "not_existing"
}
)
assert hd(res["errors"])["message"] == "Actor invited doesn't exist"
end
test "invite_member/3 fails to invite a non existing remote actor", %{
conn: conn,
user: user,
actor: actor,
group: group
} do
insert(:member, %{actor: actor, parent: group, role: :administrator})
res =
conn
|> auth_conn(user)
|> AbsintheHelpers.graphql_query(
query: @invite_member_mutation,
variables: %{
groupId: group.id,
targetActorUsername: "not_existing@nowhere.absolute"
}
)
assert hd(res["errors"])["message"] == "Actor invited doesn't exist"
end
test "invite_member/3 fails to invite a actor for a non-existing group", %{
conn: conn,
user: user,
actor: actor,
target_actor: target_actor
} do
res =
conn
|> auth_conn(user)
|> AbsintheHelpers.graphql_query(
query: @invite_member_mutation,
variables: %{
groupId: "780907988778",
targetActorUsername: target_actor.preferred_username
}
)
assert hd(res["errors"])["message"] == "Group id not found"
end
test "invite_member/3 fails to invite a actor if we are not an admin for the group", %{
conn: conn,
user: user,
actor: actor,
group: group,
target_actor: target_actor
} do
_admin_member = insert(:member, %{actor: actor, parent: group, role: :member})
res =
conn
|> auth_conn(user)
|> AbsintheHelpers.graphql_query(
query: @invite_member_mutation,
variables: %{
groupId: group.id,
targetActorUsername: target_actor.preferred_username
}
)
assert hd(res["errors"])["message"] == "You cannot invite to this group"
end
test "invite_member/3 fails to invite a actor if it's already a member of the group", %{
conn: conn,
user: user,
actor: actor,
group: group,
target_actor: target_actor
} do
insert(:member, %{actor: actor, parent: group, role: :member})
insert(:member, %{actor: target_actor, parent: group, role: :member})
res =
conn
|> auth_conn(user)
|> AbsintheHelpers.graphql_query(
query: @invite_member_mutation,
variables: %{
groupId: group.id,
targetActorUsername: target_actor.preferred_username
}
)
assert hd(res["errors"])["message"] == "You cannot invite to this group"
end
end
end

View File

@@ -483,11 +483,10 @@ defmodule Mobilizon.GraphQL.Resolvers.ParticipantTest do
participant2 = insert(:participant, event: event, actor: actor3, role: :participant)
query = """
{
event(uuid: "#{event.uuid}") {
participants(page: 1, limit: 1, roles: "participant,moderator,administrator,creator", actorId: "#{
actor.id
}") {
query EventParticipants($uuid: UUID!, $actorId: ID, $roles: String, $page: Int, $limit: Int) {
event(uuid: $uuid) {
participants(page: $page, limit: $limit, roles: $roles, actorId: $actorId) {
total,
elements {
role,
actor {
@@ -502,45 +501,21 @@ defmodule Mobilizon.GraphQL.Resolvers.ParticipantTest do
res =
conn
|> auth_conn(user)
|> get("/api", AbsintheHelpers.query_skeleton(query, "participants"))
sorted_participants =
json_response(res, 200)["data"]["event"]["participants"]["elements"]
|> Enum.filter(&(&1["role"] == "PARTICIPANT"))
assert sorted_participants == [
%{
"actor" => %{
"preferredUsername" => participant2.actor.preferred_username
},
"role" => "PARTICIPANT"
}
]
query = """
{
event(uuid: "#{event.uuid}") {
participants(page: 2, limit: 1, roles: "participant,moderator,administrator,creator", actorId: "#{
actor.id
}") {
elements {
role,
actor {
preferredUsername
}
}
|> AbsintheHelpers.graphql_query(
query: query,
variables: %{
uuid: event.uuid,
actorId: actor.id,
roles: "participant,moderator,administrator,creator",
page: 1,
limit: 1
}
}
}
"""
)
res =
conn
|> auth_conn(user)
|> get("/api", AbsintheHelpers.query_skeleton(query, "participants"))
assert is_nil(res["errors"])
sorted_participants =
json_response(res, 200)["data"]["event"]["participants"]["elements"]
res["data"]["event"]["participants"]["elements"]
|> Enum.sort_by(
&(&1
|> Map.get("actor")
@@ -555,6 +530,35 @@ defmodule Mobilizon.GraphQL.Resolvers.ParticipantTest do
"role" => "CREATOR"
}
]
res =
conn
|> auth_conn(user)
|> AbsintheHelpers.graphql_query(
query: query,
variables: %{
uuid: event.uuid,
actorId: actor.id,
roles: "participant,moderator,administrator,creator",
page: 2,
limit: 1
}
)
assert is_nil(res["errors"])
sorted_participants =
res["data"]["event"]["participants"]["elements"]
|> Enum.filter(&(&1["role"] == "PARTICIPANT"))
assert sorted_participants == [
%{
"actor" => %{
"preferredUsername" => participant2.actor.preferred_username
},
"role" => "PARTICIPANT"
}
]
end
test "stats_participants_for_event/3 give the number of (un)approved participants", %{
@@ -1288,7 +1292,11 @@ defmodule Mobilizon.GraphQL.Resolvers.ParticipantTest do
assert %Participant{
role: :not_confirmed,
metadata: %{confirmation_token: confirmation_token, email: @email}
} = event.id |> Events.list_participants_for_event([]) |> Map.get(:elements) |> hd
} =
event.id
|> Events.list_participants_for_event([:not_confirmed])
|> Map.get(:elements)
|> hd
conn
|> AbsintheHelpers.graphql_query(
@@ -1307,7 +1315,10 @@ defmodule Mobilizon.GraphQL.Resolvers.ParticipantTest do
}} = Events.get_event(event.id)
assert %Participant{role: :not_approved, id: participant_id} =
event.id |> Events.list_participants_for_event([]) |> Map.get(:elements) |> hd
event.id
|> Events.list_participants_for_event([:not_approved])
|> Map.get(:elements)
|> hd
update_participation_mutation = """
mutation UpdateParticipation($participantId: ID!, $role: String!, $moderatorActorId: ID!) {
@@ -1339,7 +1350,10 @@ defmodule Mobilizon.GraphQL.Resolvers.ParticipantTest do
assert res["errors"] == nil
assert %Participant{role: :participant} =
event.id |> Events.list_participants_for_event([]) |> Map.get(:elements) |> hd
event.id
|> Events.list_participants_for_event([:participant])
|> Map.get(:elements)
|> hd
assert {:ok,
%Event{

View File

@@ -0,0 +1,864 @@
defmodule Mobilizon.GraphQL.Resolvers.ResourceTest do
use Mobilizon.Web.ConnCase
import Mobilizon.Factory
alias Mobilizon.Actors.{Actor, Member}
alias Mobilizon.Resources.Resource
alias Mobilizon.Users.User
alias Mobilizon.GraphQL.AbsintheHelpers
@metadata_fragment """
fragment ResourceMetadataBasicFields on ResourceMetadata {
imageRemoteUrl,
height,
width,
type,
faviconUrl
}
"""
@get_group_resources """
query($name: String!) {
group(preferredUsername: $name) {
id,
url,
name,
domain,
summary,
preferredUsername,
resources(page: 1, limit: 3) {
elements {
id,
title,
resourceUrl,
summary,
updatedAt,
type,
path,
metadata {
...ResourceMetadataBasicFields
}
},
total
},
}
}
#{@metadata_fragment}
"""
@get_resource """
query GetResource($path: String, $username: String) {
resource(path: $path, username: $username) {
id,
title,
summary,
url,
path,
type,
metadata {
...ResourceMetadataBasicFields
authorName,
authorUrl,
providerName,
providerUrl,
html
},
parent {
id
},
actor {
id,
preferredUsername
},
children {
total,
elements {
id,
title,
summary,
url,
type,
path,
resourceUrl,
metadata {
...ResourceMetadataBasicFields
}
}
}
}
}
#{@metadata_fragment}
"""
@create_resource """
mutation CreateResource($title: String!, $parentId: ID, $summary: String, $actorId: ID!, $resourceUrl: String, $type: String) {
createResource(title: $title, parentId: $parentId, summary: $summary, actorId: $actorId, resourceUrl: $resourceUrl, type: $type) {
id,
title,
summary,
url,
resourceUrl,
updatedAt,
path,
type,
metadata {
...ResourceMetadataBasicFields
authorName,
authorUrl,
providerName,
providerUrl,
html
}
}
}
#{@metadata_fragment}
"""
@update_resource """
mutation UpdateResource($id: ID!, $title: String, $summary: String, $parentId: ID, $resourceUrl: String) {
updateResource(id: $id, title: $title, parentId: $parentId, summary: $summary, resourceUrl: $resourceUrl) {
id,
title,
summary,
url,
path,
resourceUrl,
type,
children {
total,
elements {
id,
title,
summary,
url,
type,
path,
resourceUrl,
metadata {
...ResourceMetadataBasicFields
}
}
}
}
}
#{@metadata_fragment}
"""
@delete_resource """
mutation DeleteResource($id: ID!) {
deleteResource(id: $id) {
id
}
}
"""
@resource_url "https://framasoft.org/fr/full"
@resource_title "my resource"
@updated_resource_title "my updated resource"
@folder_title "my folder"
setup do
%User{} = user = insert(:user)
%Actor{} = actor = insert(:actor, user: user)
%Actor{} = group = insert(:group)
%Member{} = insert(:member, parent: group, actor: actor, role: :member)
resource_in_root = %Resource{} = insert(:resource, actor: group)
folder_in_root =
%Resource{id: parent_id, path: parent_path} =
insert(:resource,
type: :folder,
resource_url: nil,
actor: group,
title: "root folder",
path: "/root folder"
)
resource_in_folder =
%Resource{} =
insert(:resource,
resource_url: nil,
actor: group,
parent_id: parent_id,
path: "#{parent_path}/titre",
title: "titre"
)
{:ok,
user: user,
group: group,
root_resources: [folder_in_root, resource_in_root],
resource_in_folder: resource_in_folder}
end
describe "Resolver: Get group's resources" do
test "find_resources_for_group/3", %{
conn: conn,
user: user,
group: group,
root_resources: root_resources,
resource_in_folder: resource_in_folder
} do
res =
conn
|> auth_conn(user)
|> AbsintheHelpers.graphql_query(
query: @get_group_resources,
variables: %{
name: group.preferred_username
}
)
assert is_nil(res["errors"])
assert res["data"]["group"]["resources"]["total"] == 3
assert res["data"]["group"]["resources"]["elements"]
|> Enum.map(&{&1["path"], &1["type"]})
|> MapSet.new() ==
(root_resources ++ [resource_in_folder])
|> Enum.map(&{&1.path, Atom.to_string(&1.type)})
|> MapSet.new()
end
test "find_resources_for_group/3 when not member of group", %{
conn: conn,
group: group
} do
%User{} = user = insert(:user)
%Actor{} = insert(:actor, user: user)
res =
conn
|> auth_conn(user)
|> AbsintheHelpers.graphql_query(
query: @get_group_resources,
variables: %{
name: group.preferred_username
}
)
assert is_nil(res["errors"])
assert res["data"]["group"]["resources"]["total"] == 0
assert res["data"]["group"]["resources"]["elements"] == []
end
test "find_resources_for_group/3 when not connected", %{
conn: conn,
group: group
} do
res =
conn
|> AbsintheHelpers.graphql_query(
query: @get_group_resources,
variables: %{
name: group.preferred_username
}
)
assert is_nil(res["errors"])
assert res["data"]["group"]["resources"]["total"] == 0
assert res["data"]["group"]["resources"]["elements"] == []
end
end
describe "Resolver: Get a specific resource" do
test "get_resource/3 for the root path", %{
conn: conn,
user: user,
group: group,
root_resources: root_resources
} do
res =
conn
|> auth_conn(user)
|> AbsintheHelpers.graphql_query(
query: @get_resource,
variables: %{
path: "/",
username: group.preferred_username
}
)
assert is_nil(res["errors"])
assert res["data"]["resource"]["path"] == "/"
assert String.starts_with?(res["data"]["resource"]["id"], "root_")
assert res["data"]["resource"]["children"]["elements"]
|> Enum.map(& &1["id"])
|> MapSet.new() == root_resources |> Enum.map(& &1.id) |> MapSet.new()
end
test "get_resource/3 for a folder path", %{
conn: conn,
user: user,
group: group,
root_resources: [root_folder, _],
resource_in_folder: resource_in_folder
} do
res =
conn
|> auth_conn(user)
|> AbsintheHelpers.graphql_query(
query: @get_resource,
variables: %{
path: root_folder.path,
username: group.preferred_username
}
)
assert is_nil(res["errors"])
assert res["data"]["resource"]["type"] == "folder"
assert res["data"]["resource"]["path"] == root_folder.path
assert is_nil(res["data"]["resource"]["parent"]["id"])
assert res["data"]["resource"]["children"]["total"] == 1
assert res["data"]["resource"]["children"]["elements"]
|> Enum.map(& &1["id"])
|> MapSet.new() == [resource_in_folder] |> Enum.map(& &1.id) |> MapSet.new()
end
test "get_resource/3 for a non-existing path", %{
conn: conn,
user: user,
group: group
} do
res =
conn
|> auth_conn(user)
|> AbsintheHelpers.graphql_query(
query: @get_resource,
variables: %{
path: "/non existing",
username: group.preferred_username
}
)
assert hd(res["errors"])["message"] == "No such resource"
end
test "get_resource/3 for a non-existing group", %{
conn: conn,
user: user
} do
%Actor{preferred_username: group_name} = insert(:group)
res =
conn
|> auth_conn(user)
|> AbsintheHelpers.graphql_query(
query: @get_resource,
variables: %{
path: "/non existing",
username: group_name
}
)
assert hd(res["errors"])["message"] == "Actor is not member of group"
end
test "get_resource/3 when not connected", %{
conn: conn,
group: group,
resource_in_folder: resource_in_folder
} do
res =
conn
|> AbsintheHelpers.graphql_query(
query: @get_resource,
variables: %{
path: resource_in_folder.path,
username: group.preferred_username
}
)
assert hd(res["errors"])["message"] == "You need to be logged-in to access resources"
end
end
describe "Resolver: Create a resource" do
test "create_resource/3 creates a resource for a group", %{
conn: conn,
user: user,
group: group
} do
res =
conn
|> auth_conn(user)
|> AbsintheHelpers.graphql_query(
query: @create_resource,
variables: %{
title: @resource_title,
parentId: nil,
actorId: group.id,
resourceUrl: @resource_url
}
)
assert is_nil(res["errors"])
assert res["data"]["createResource"]["metadata"]["faviconUrl"] ==
"https://framasoft.org/icons/favicon.png"
assert res["data"]["createResource"]["metadata"]["imageRemoteUrl"] ==
"https://framasoft.org/img/opengraph/full.jpg"
assert res["data"]["createResource"]["path"] == "/#{@resource_title}"
assert res["data"]["createResource"]["resourceUrl"] == @resource_url
assert res["data"]["createResource"]["title"] == @resource_title
assert res["data"]["createResource"]["type"] == "link"
end
test "create_resource/3 creates a folder", %{conn: conn, user: user, group: group} do
res =
conn
|> auth_conn(user)
|> AbsintheHelpers.graphql_query(
query: @create_resource,
variables: %{
title: @folder_title,
parentId: nil,
actorId: group.id,
type: "folder"
}
)
assert is_nil(res["errors"])
assert res["data"]["createResource"]["path"] == "/#{@folder_title}"
assert res["data"]["createResource"]["title"] == @folder_title
assert res["data"]["createResource"]["type"] == "folder"
end
test "create_resource/3 creates a resource in a folder", %{
conn: conn,
user: user,
group: group
} do
%Resource{id: parent_id, path: parent_path} =
insert(:resource, type: :folder, resource_url: nil, actor: group)
res =
conn
|> auth_conn(user)
|> AbsintheHelpers.graphql_query(
query: @create_resource,
variables: %{
title: @resource_title,
parentId: parent_id,
actorId: group.id,
resourceUrl: @resource_url
}
)
assert is_nil(res["errors"])
assert res["data"]["createResource"]["metadata"]["faviconUrl"] ==
"https://framasoft.org/icons/favicon.png"
assert res["data"]["createResource"]["metadata"]["imageRemoteUrl"] ==
"https://framasoft.org/img/opengraph/full.jpg"
assert res["data"]["createResource"]["path"] == "#{parent_path}/#{@resource_title}"
assert res["data"]["createResource"]["resourceUrl"] == @resource_url
assert res["data"]["createResource"]["title"] == @resource_title
assert res["data"]["createResource"]["type"] == "link"
end
test "create_resource/3 doesn't create a resource in a folder if no group is defined", %{
conn: conn,
user: user
} do
res =
conn
|> auth_conn(user)
|> AbsintheHelpers.graphql_query(
query: @create_resource,
variables: %{
title: @resource_title,
parentId: nil,
resourceUrl: @resource_url
}
)
assert Enum.map(res["errors"], & &1["message"]) == [
"In argument \"actorId\": Expected type \"ID!\", found null.",
"Variable \"actorId\": Expected non-null, found null."
]
end
test "create_resource/3 doesn't create a resource if the actor is not a member of the group",
%{
conn: conn,
group: group
} do
%User{} = user = insert(:user)
%Actor{} = insert(:actor, user: user)
res =
conn
|> auth_conn(user)
|> AbsintheHelpers.graphql_query(
query: @create_resource,
variables: %{
title: @resource_title,
parentId: nil,
actorId: group.id,
resourceUrl: @resource_url
}
)
assert Enum.map(res["errors"], & &1["message"]) == [
"Actor id is not member of group"
]
end
test "create_resource/3 doesn't create a resource if the referenced parent folder is not owned by the group",
%{
conn: conn,
user: user,
group: group
} do
%Actor{} = group2 = insert(:group)
%Resource{id: parent_id} =
insert(:resource, type: :folder, resource_url: nil, actor: group2)
res =
conn
|> auth_conn(user)
|> AbsintheHelpers.graphql_query(
query: @create_resource,
variables: %{
title: @resource_title,
parentId: parent_id,
actorId: group.id,
resourceUrl: @resource_url
}
)
assert Enum.map(res["errors"], & &1["message"]) == [
"Parent resource doesn't match this group"
]
end
end
describe "Resolver: Update a resource" do
test "update_resource/3 renames a resource for a group", %{
conn: conn,
user: user,
group: group
} do
%Resource{id: resource_id} = insert(:resource, resource_url: @resource_url, actor: group)
res =
conn
|> auth_conn(user)
|> AbsintheHelpers.graphql_query(
query: @update_resource,
variables: %{
id: resource_id,
title: @updated_resource_title
}
)
assert is_nil(res["errors"])
assert res["data"]["updateResource"]["path"] == "/#{@updated_resource_title}"
assert res["data"]["updateResource"]["resourceUrl"] == @resource_url
assert res["data"]["updateResource"]["title"] == @updated_resource_title
assert res["data"]["updateResource"]["type"] == "link"
end
test "update_resource/3 moves and renames a resource for a group", %{
conn: conn,
user: user,
group: group,
root_resources: [root_folder, _]
} do
%Resource{id: resource_id} = insert(:resource, resource_url: @resource_url, actor: group)
res =
conn
|> auth_conn(user)
|> AbsintheHelpers.graphql_query(
query: @update_resource,
variables: %{
id: resource_id,
title: @updated_resource_title,
parentId: root_folder.id
}
)
assert is_nil(res["errors"])
assert res["data"]["updateResource"]["path"] ==
"#{root_folder.path}/#{@updated_resource_title}"
assert res["data"]["updateResource"]["resourceUrl"] == @resource_url
assert res["data"]["updateResource"]["title"] == @updated_resource_title
assert res["data"]["updateResource"]["type"] == "link"
end
test "update_resource/3 moves a resource in a subfolder for a group", %{
conn: conn,
user: user,
group: group,
root_resources: [root_folder, _]
} do
%Resource{id: resource_id} =
resource = insert(:resource, resource_url: @resource_url, actor: group)
folder =
insert(:resource,
parent_id: root_folder.id,
actor: group,
path: "#{root_folder.path}/subfolder",
title: "subfolder"
)
res =
conn
|> auth_conn(user)
|> AbsintheHelpers.graphql_query(
query: @update_resource,
variables: %{
id: resource_id,
parentId: folder.id
}
)
assert is_nil(res["errors"])
assert res["data"]["updateResource"]["path"] ==
"#{folder.path}/#{resource.title}"
assert res["data"]["updateResource"]["resourceUrl"] == @resource_url
assert res["data"]["updateResource"]["title"] == resource.title
assert res["data"]["updateResource"]["type"] == "link"
end
test "update_resource/3 renames a folder and all the paths for it's children", %{
conn: conn,
user: user,
group: group,
root_resources: [root_folder, _]
} do
folder =
insert(:resource,
parent_id: root_folder.id,
actor: group,
path: "#{root_folder.path}/subfolder",
title: "subfolder",
type: :folder
)
%Resource{} =
insert(:resource,
resource_url: @resource_url,
actor: group,
parent_id: folder.id,
path: "#{folder.path}/titre",
title: "titre"
)
res =
conn
|> auth_conn(user)
|> AbsintheHelpers.graphql_query(
query: @update_resource,
variables: %{
id: folder.id,
title: "updated subfolder"
}
)
assert is_nil(res["errors"])
assert res["data"]["updateResource"]["path"] ==
"#{root_folder.path}/updated subfolder"
assert res["data"]["updateResource"]["title"] == "updated subfolder"
assert res["data"]["updateResource"]["type"] == "folder"
assert hd(res["data"]["updateResource"]["children"]["elements"])["path"] ==
"#{root_folder.path}/updated subfolder/titre"
end
test "update_resource/3 moves a folder and updates all the paths for it's children", %{
conn: conn,
user: user,
group: group,
root_resources: [root_folder, _]
} do
folder =
insert(:resource,
parent_id: nil,
actor: group,
path: "/subfolder",
title: "subfolder",
type: :folder
)
%Resource{} =
insert(:resource,
resource_url: @resource_url,
actor: group,
parent_id: folder.id,
path: "#{folder.path}/titre",
title: "titre"
)
res =
conn
|> auth_conn(user)
|> AbsintheHelpers.graphql_query(
query: @update_resource,
variables: %{
id: folder.id,
parentId: root_folder.id,
title: "updated subfolder"
}
)
assert is_nil(res["errors"])
assert res["data"]["updateResource"]["path"] ==
"#{root_folder.path}/updated subfolder"
assert res["data"]["updateResource"]["title"] == "updated subfolder"
assert res["data"]["updateResource"]["type"] == "folder"
assert hd(res["data"]["updateResource"]["children"]["elements"])["path"] ==
"#{root_folder.path}/updated subfolder/titre"
end
end
describe "Resolver: Delete a resource" do
test "delete_resource/3 deletes a resource", %{
conn: conn,
user: user,
group: group
} do
%Resource{id: resource_id, path: resource_path} =
insert(:resource,
resource_url: @resource_url,
actor: group,
parent_id: nil
)
res =
conn
|> auth_conn(user)
|> AbsintheHelpers.graphql_query(
query: @delete_resource,
variables: %{
id: resource_id
}
)
assert is_nil(res["errors"])
assert res["data"]["deleteResource"]["id"] == resource_id
res =
conn
|> auth_conn(user)
|> AbsintheHelpers.graphql_query(
query: @get_resource,
variables: %{
path: resource_path,
username: group.preferred_username
}
)
assert hd(res["errors"])["message"] == "No such resource"
end
test "delete_resource/3 deletes a folder and children", %{
conn: conn,
user: user,
group: group
} do
%Resource{id: folder_id, path: folder_path} =
insert(:resource,
parent_id: nil,
actor: group,
path: "/subfolder",
title: "subfolder",
type: :folder
)
%Resource{path: resource_path} =
insert(:resource,
resource_url: @resource_url,
actor: group,
parent_id: folder_id,
path: "#{folder_path}/titre",
title: "titre"
)
res =
conn
|> auth_conn(user)
|> AbsintheHelpers.graphql_query(
query: @delete_resource,
variables: %{
id: folder_id
}
)
assert is_nil(res["errors"])
assert res["data"]["deleteResource"]["id"] == folder_id
res =
conn
|> auth_conn(user)
|> AbsintheHelpers.graphql_query(
query: @get_resource,
variables: %{
path: folder_path,
username: group.preferred_username
}
)
assert hd(res["errors"])["message"] == "No such resource"
res =
conn
|> auth_conn(user)
|> AbsintheHelpers.graphql_query(
query: @get_resource,
variables: %{
path: resource_path,
username: group.preferred_username
}
)
assert hd(res["errors"])["message"] == "No such resource"
end
test "delete_resource/3 deletes a resource not found", %{
conn: conn,
user: user
} do
res =
conn
|> auth_conn(user)
|> AbsintheHelpers.graphql_query(
query: @delete_resource,
variables: %{
id: "58869b5b-2beb-423a-b483-1585d847e2cc"
}
)
assert hd(res["errors"])["message"] == "Resource doesn't exist"
end
end
end

View File

@@ -5,9 +5,10 @@ defmodule Mobilizon.GraphQL.Resolvers.UserTest do
import Mobilizon.Factory
alias Mobilizon.{Actors, Config, Events, Users}
alias Mobilizon.{Actors, Config, Conversations, Events, Users}
alias Mobilizon.Actors.Actor
alias Mobilizon.Events.{Comment, Event, Participant}
alias Mobilizon.Conversations.Comment
alias Mobilizon.Events.{Event, Participant}
alias Mobilizon.Users.User
alias Mobilizon.GraphQL.AbsintheHelpers
@@ -1424,7 +1425,7 @@ defmodule Mobilizon.GraphQL.Resolvers.UserTest do
end
assert_raise Ecto.NoResultsError, fn ->
Events.get_comment!(comment_id)
Conversations.get_comment!(comment_id)
end
# Actors are not deleted but emptied (to keep the username reserved)

View File

@@ -5,9 +5,10 @@ defmodule Mobilizon.ActorsTest do
import Mobilizon.Factory
alias Mobilizon.{Actors, Config, Events, Tombstone, Users}
alias Mobilizon.{Actors, Config, Conversations, Events, Tombstone, Users}
alias Mobilizon.Actors.{Actor, Bot, Follower, Member}
alias Mobilizon.Events.{Comment, Event}
alias Mobilizon.Conversations.Comment
alias Mobilizon.Events.Event
alias Mobilizon.Media.File, as: FileModel
alias Mobilizon.Service.Workers
alias Mobilizon.Storage.Page
@@ -331,7 +332,7 @@ defmodule Mobilizon.ActorsTest do
assert {:error, :event_not_found} = Events.get_event(event1.id)
assert %Tombstone{} = Tombstone.find_tombstone(event1_url)
assert %Comment{deleted_at: deleted_at} = Events.get_comment(comment1.id)
assert %Comment{deleted_at: deleted_at} = Conversations.get_comment(comment1.id)
refute is_nil(deleted_at)
assert %Tombstone{} = Tombstone.find_tombstone(comment1_url)
@@ -363,7 +364,11 @@ defmodule Mobilizon.ActorsTest do
@invalid_attrs %{summary: nil, suspended: nil, preferred_username: nil, name: nil}
test "create_group/1 with valid data creates a group" do
assert {:ok, %Actor{} = group} = Actors.create_group(@valid_attrs)
%Actor{id: actor_id} = insert(:actor)
assert {:ok, %Actor{} = group} =
Actors.create_group(Map.put(@valid_attrs, :creator_actor_id, actor_id))
assert group.summary == "some description"
refute group.suspended
assert group.preferred_username == "some-title"
@@ -372,21 +377,23 @@ defmodule Mobilizon.ActorsTest do
test "create_group/1 with an existing profile username fails" do
_actor = insert(:actor, preferred_username: @valid_attrs.preferred_username)
assert {:error,
%Ecto.Changeset{errors: [preferred_username: {"Username is already taken", []}]}} =
Actors.create_group(@valid_attrs)
assert {:error, :insert_group,
%Ecto.Changeset{errors: [preferred_username: {"Username is already taken", []}]},
%{}} = Actors.create_group(@valid_attrs)
end
test "create_group/1 with an existing group username fails" do
assert {:ok, %Actor{} = group} = Actors.create_group(@valid_attrs)
%Actor{id: actor_id} = insert(:actor)
attrs = Map.put(@valid_attrs, :creator_actor_id, actor_id)
assert {:ok, %Actor{} = group} = Actors.create_group(attrs)
assert {:error,
%Ecto.Changeset{errors: [preferred_username: {"Username is already taken", []}]}} =
Actors.create_group(@valid_attrs)
assert {:error, :insert_group,
%Ecto.Changeset{errors: [preferred_username: {"Username is already taken", []}]},
%{}} = Actors.create_group(attrs)
end
test "create_group/1 with invalid data returns error changeset" do
assert {:error, %Ecto.Changeset{}} = Actors.create_group(@invalid_attrs)
assert {:error, :insert_group, %Ecto.Changeset{}, %{}} = Actors.create_group(@invalid_attrs)
end
end
@@ -588,7 +595,7 @@ defmodule Mobilizon.ActorsTest do
assert member.role == :member
assert [group] = Actors.list_groups_member_of(actor)
assert [actor] = Actors.list_members_for_group(group)
assert %Page{elements: [actor], total: 1} = Actors.list_members_for_group(group)
end
test "create_member/1 with valid data but same actors fails to create a member", %{

View File

@@ -0,0 +1,72 @@
defmodule Mobilizon.ConversationsTest do
use Mobilizon.DataCase
import Mobilizon.Factory
alias Mobilizon.Actors.Actor
alias Mobilizon.Conversations
alias Mobilizon.Conversations.Comment
alias Mobilizon.Service.Workers
alias Mobilizon.Storage.Page
describe "comments" do
@valid_attrs %{text: "some text"}
@update_attrs %{text: "some updated text"}
@invalid_attrs %{text: nil, url: nil}
test "list_comments/0 returns all comments" do
%Comment{id: comment_id} = insert(:comment)
comment_ids = Conversations.list_comments() |> Enum.map(& &1.id)
assert comment_ids == [comment_id]
end
test "get_comment!/1 returns the comment with given id" do
%Comment{id: comment_id} = insert(:comment)
comment_fetched = Conversations.get_comment!(comment_id)
assert comment_fetched.id == comment_id
end
test "create_comment/1 with valid data creates a comment" do
%Actor{} = actor = insert(:actor)
comment_data = Map.merge(@valid_attrs, %{actor_id: actor.id})
case Conversations.create_comment(comment_data) do
{:ok, %Comment{} = comment} ->
assert comment.text == "some text"
assert comment.actor_id == actor.id
err ->
flunk("Failed to create a comment #{inspect(err)}")
end
end
test "create_comment/1 with invalid data returns error changeset" do
assert {:error, %Ecto.Changeset{}} = Conversations.create_comment(@invalid_attrs)
end
test "update_comment/2 with valid data updates the comment" do
%Comment{} = comment = insert(:comment)
case Conversations.update_comment(comment, @update_attrs) do
{:ok, %Comment{} = comment} ->
assert comment.text == "some updated text"
err ->
flunk("Failed to update a comment #{inspect(err)}")
end
end
test "update_comment/2 with invalid data returns error changeset" do
%Comment{} = comment = insert(:comment)
assert {:error, %Ecto.Changeset{}} = Conversations.update_comment(comment, @invalid_attrs)
%Comment{} = comment_fetched = Conversations.get_comment!(comment.id)
assert comment = comment_fetched
end
test "delete_comment/1 deletes the comment" do
%Comment{} = comment = insert(:comment)
assert {:ok, %Comment{}} = Conversations.delete_comment(comment)
refute is_nil(Conversations.get_comment!(comment.id).deleted_at)
end
end
end

View File

@@ -4,8 +4,9 @@ defmodule Mobilizon.EventsTest do
import Mobilizon.Factory
alias Mobilizon.Actors.Actor
alias Mobilizon.Events
alias Mobilizon.Events.{Comment, Event, Participant, Session, Tag, TagRelation, Track}
alias Mobilizon.{Conversations, Events}
alias Mobilizon.Conversations.Comment
alias Mobilizon.Events.{Event, Participant, Session, Tag, TagRelation, Track}
alias Mobilizon.Service.Workers
alias Mobilizon.Storage.Page
@@ -530,65 +531,4 @@ defmodule Mobilizon.EventsTest do
assert_raise Ecto.NoResultsError, fn -> Events.get_track!(track.id) end
end
end
describe "comments" do
@valid_attrs %{text: "some text"}
@update_attrs %{text: "some updated text"}
@invalid_attrs %{text: nil, url: nil}
test "list_comments/0 returns all comments" do
%Comment{id: comment_id} = insert(:comment)
comment_ids = Events.list_comments() |> Enum.map(& &1.id)
assert comment_ids == [comment_id]
end
test "get_comment!/1 returns the comment with given id" do
%Comment{id: comment_id} = insert(:comment)
comment_fetched = Events.get_comment!(comment_id)
assert comment_fetched.id == comment_id
end
test "create_comment/1 with valid data creates a comment" do
actor = insert(:actor)
comment_data = Map.merge(@valid_attrs, %{actor_id: actor.id})
case Events.create_comment(comment_data) do
{:ok, %Comment{} = comment} ->
assert comment.text == "some text"
assert comment.actor_id == actor.id
err ->
flunk("Failed to create a comment #{inspect(err)}")
end
end
test "create_comment/1 with invalid data returns error changeset" do
assert {:error, %Ecto.Changeset{}} = Events.create_comment(@invalid_attrs)
end
test "update_comment/2 with valid data updates the comment" do
comment = insert(:comment)
case Events.update_comment(comment, @update_attrs) do
{:ok, %Comment{} = comment} ->
assert comment.text == "some updated text"
err ->
flunk("Failed to update a comment #{inspect(err)}")
end
end
test "update_comment/2 with invalid data returns error changeset" do
comment = insert(:comment)
assert {:error, %Ecto.Changeset{}} = Events.update_comment(comment, @invalid_attrs)
comment_fetched = Events.get_comment!(comment.id)
assert comment = comment_fetched
end
test "delete_comment/1 deletes the comment" do
comment = insert(:comment)
assert {:ok, %Comment{}} = Events.delete_comment(comment)
refute is_nil(Events.get_comment!(comment.id).deleted_at)
end
end
end

View File

@@ -2,7 +2,7 @@ defmodule Mobilizon.UsersTest do
use Mobilizon.DataCase
alias Mobilizon.Users
alias Mobilizon.Users.User
alias Mobilizon.Users.{Setting, User}
import Mobilizon.Factory
use ExVCR.Mock, adapter: ExVCR.Adapter.Hackney
@@ -101,4 +101,60 @@ defmodule Mobilizon.UsersTest do
assert id == user.id
end
end
describe "user_settings" do
@valid_attrs %{timezone: "Europe/Paris", notification_each_week: true}
@update_attrs %{timezone: "Atlantic/Cape_Verde", notification_each_week: false}
@invalid_attrs %{timezone: nil, notification_each_week: nil}
def setting_fixture(attrs \\ %{}) do
{:ok, setting} =
attrs
|> Enum.into(@valid_attrs)
|> Users.create_setting()
setting
end
test "get_setting!/1 returns the setting with given id" do
%User{id: user_id} = insert(:user)
setting = setting_fixture(user_id: user_id)
assert Users.get_setting!(setting.user_id) == setting
end
test "create_setting/1 with valid data creates a setting" do
%User{id: user_id} = insert(:user)
assert {:ok, %Setting{} = setting} =
Users.create_setting(Map.put(@valid_attrs, :user_id, user_id))
assert setting.timezone == "Europe/Paris"
assert setting.notification_each_week == true
end
test "create_setting/1 with invalid data returns error changeset" do
assert {:error, %Ecto.Changeset{}} = Users.create_setting(@invalid_attrs)
end
test "update_setting/2 with valid data updates the setting" do
%User{id: user_id} = insert(:user)
setting = setting_fixture(user_id: user_id)
assert {:ok, %Setting{} = setting} = Users.update_setting(setting, @update_attrs)
assert setting.timezone == "Atlantic/Cape_Verde"
assert setting.notification_each_week == false
end
test "delete_setting/1 deletes the setting" do
%User{id: user_id} = insert(:user)
setting = setting_fixture(user_id: user_id)
assert {:ok, %Setting{}} = Users.delete_setting(setting)
assert_raise Ecto.NoResultsError, fn -> Users.get_setting!(setting.user_id) end
end
test "change_setting/1 returns a setting changeset" do
%User{id: user_id} = insert(:user)
setting = setting_fixture(user_id: user_id)
assert %Ecto.Changeset{} = Users.change_setting(setting)
end
end
end

View File

@@ -9,6 +9,11 @@ defmodule Mobilizon.Service.Geospatial.AddokTest do
alias Mobilizon.Config
alias Mobilizon.Service.Geospatial.Addok
@http_options [
follow_redirect: true,
ssl: [{:versions, [:"tlsv1.2"]}]
]
setup do
# Config.instance_user_agent/0 makes database calls so because of ownership connection
# we need to define it like this instead of a constant
@@ -24,17 +29,21 @@ defmodule Mobilizon.Service.Geospatial.AddokTest do
describe "search address" do
test "produces a valid search address", %{httpoison_headers: httpoison_headers} do
with_mock HTTPoison, get: fn _url, _headers -> "{}" end do
with_mock HTTPoison, get: fn _url, _headers, _options -> "{}" end do
Addok.search("10 Rue Jangot")
assert_called(
HTTPoison.get("#{@endpoint}/search/?q=10%20Rue%20Jangot&limit=10", httpoison_headers)
HTTPoison.get(
"#{@endpoint}/search/?q=10%20Rue%20Jangot&limit=10",
httpoison_headers,
@http_options
)
)
end
end
test "produces a valid search address with options", %{httpoison_headers: httpoison_headers} do
with_mock HTTPoison, get: fn _url, _headers -> "{}" end do
with_mock HTTPoison, get: fn _url, _headers, _options -> "{}" end do
Addok.search("10 Rue Jangot",
endpoint: @fake_endpoint,
limit: 5,
@@ -44,7 +53,8 @@ defmodule Mobilizon.Service.Geospatial.AddokTest do
assert_called(
HTTPoison.get(
"#{@fake_endpoint}/search/?q=10%20Rue%20Jangot&limit=5&lat=49&lon=12",
httpoison_headers
httpoison_headers,
@http_options
)
)
end

View File

@@ -8,6 +8,11 @@ defmodule Mobilizon.Service.Geospatial.GoogleMapsTest do
alias Mobilizon.Addresses.Address
alias Mobilizon.Service.Geospatial.GoogleMaps
@http_options [
follow_redirect: true,
ssl: [{:versions, [:"tlsv1.2"]}]
]
describe "search address" do
test "without API Key triggers an error" do
assert_raise ArgumentError, "API Key required to use Google Maps", fn ->
@@ -17,7 +22,7 @@ defmodule Mobilizon.Service.Geospatial.GoogleMapsTest do
test "produces a valid search address with options" do
with_mock HTTPoison,
get: fn _url ->
get: fn _url, _headers, _options ->
{:ok,
%HTTPoison.Response{status_code: 200, body: "{\"status\": \"OK\", \"results\": []}"}}
end do
@@ -29,7 +34,9 @@ defmodule Mobilizon.Service.Geospatial.GoogleMapsTest do
assert_called(
HTTPoison.get(
"https://maps.googleapis.com/maps/api/geocode/json?limit=5&key=toto&language=fr&address=10%20Rue%20Jangot"
"https://maps.googleapis.com/maps/api/geocode/json?limit=5&key=toto&language=fr&address=10%20Rue%20Jangot",
[],
@http_options
)
)
end

View File

@@ -9,6 +9,11 @@ defmodule Mobilizon.Service.Geospatial.MapQuestTest do
alias Mobilizon.Config
alias Mobilizon.Service.Geospatial.MapQuest
@http_options [
follow_redirect: true,
ssl: [{:versions, [:"tlsv1.2"]}]
]
setup do
# Config.instance_user_agent/0 makes database calls so because of ownership connection
# we need to define it like this instead of a constant
@@ -28,7 +33,7 @@ defmodule Mobilizon.Service.Geospatial.MapQuestTest do
test "produces a valid search address with options", %{httpoison_headers: httpoison_headers} do
with_mock HTTPoison,
get: fn _url, _headers ->
get: fn _url, _headers, _options ->
{:ok,
%HTTPoison.Response{
status_code: 200,
@@ -44,7 +49,8 @@ defmodule Mobilizon.Service.Geospatial.MapQuestTest do
assert_called(
HTTPoison.get(
"https://open.mapquestapi.com/geocoding/v1/address?key=toto&location=10%20Rue%20Jangot&maxResults=5",
httpoison_headers
httpoison_headers,
@http_options
)
)
end

View File

@@ -7,6 +7,11 @@ defmodule Mobilizon.Service.Geospatial.NominatimTest do
alias Mobilizon.Config
alias Mobilizon.Service.Geospatial.Nominatim
@http_options [
follow_redirect: true,
ssl: [{:versions, [:"tlsv1.2"]}]
]
setup do
# Config.instance_user_agent/0 makes database calls so because of ownership connection
# we need to define it like this instead of a constant
@@ -20,7 +25,7 @@ defmodule Mobilizon.Service.Geospatial.NominatimTest do
describe "search address" do
test "produces a valid search address with options", %{httpoison_headers: httpoison_headers} do
with_mock HTTPoison,
get: fn _url, _headers ->
get: fn _url, _headers, _options ->
{:ok, %HTTPoison.Response{status_code: 200, body: "[]"}}
end do
Nominatim.search("10 Rue Jangot",
@@ -31,7 +36,8 @@ defmodule Mobilizon.Service.Geospatial.NominatimTest do
assert_called(
HTTPoison.get(
"https://nominatim.openstreetmap.org/search?format=geocodejson&q=10%20Rue%20Jangot&limit=5&accept-language=fr&addressdetails=1&namedetails=1",
httpoison_headers
httpoison_headers,
@http_options
)
)
end

View File

@@ -9,6 +9,11 @@ defmodule Mobilizon.Service.Geospatial.PhotonTest do
alias Mobilizon.Config
alias Mobilizon.Service.Geospatial.Photon
@http_options [
follow_redirect: true,
ssl: [{:versions, [:"tlsv1.2"]}]
]
setup do
# Config.instance_user_agent/0 makes database calls so because of ownership connection
# we need to define it like this instead of a constant
@@ -22,7 +27,7 @@ defmodule Mobilizon.Service.Geospatial.PhotonTest do
describe "search address" do
test "produces a valid search address with options", %{httpoison_headers: httpoison_headers} do
with_mock HTTPoison,
get: fn _url, _headers ->
get: fn _url, _headers, _options ->
{:ok, %HTTPoison.Response{status_code: 200, body: "{\"features\": []"}}
end do
Photon.search("10 Rue Jangot",
@@ -33,7 +38,8 @@ defmodule Mobilizon.Service.Geospatial.PhotonTest do
assert_called(
HTTPoison.get(
"https://photon.komoot.de/api/?q=10%20Rue%20Jangot&lang=fr&limit=5",
httpoison_headers
httpoison_headers,
@http_options
)
)
end

View File

@@ -0,0 +1,147 @@
defmodule Mobilizon.Service.Notifications.SchedulerTest do
@moduledoc """
Test the scheduler module
"""
alias Mobilizon.Events.{Event, Participant}
alias Mobilizon.Service.Notifications.Scheduler
alias Mobilizon.Service.Workers.Notification
alias Mobilizon.Users.User
use Mobilizon.DataCase
import Mobilizon.Factory
use Oban.Testing, repo: Mobilizon.Storage.Repo
describe "Joining an event registers a job for notification before event" do
test "if the user has allowed it" do
%User{id: user_id} = user = insert(:user)
settings = insert(:settings, user_id: user_id, notification_before_event: true)
user = Map.put(user, :settings, settings)
actor = insert(:actor, user: user)
%Participant{id: participant_id, event: %Event{begins_on: begins_on}} =
participant = insert(:participant, actor: actor)
Scheduler.before_event_notification(participant)
scheduled_at = DateTime.add(begins_on, -3600, :second)
assert_enqueued(
worker: Notification,
args: %{participant_id: participant_id, op: :before_event_notification},
scheduled_at: scheduled_at
)
end
test "not if the user hasn't allowed it" do
%User{} = user = insert(:user)
actor = insert(:actor, user: user)
%Participant{id: participant_id} = participant = insert(:participant, actor: actor)
Scheduler.before_event_notification(participant)
refute_enqueued(
worker: Notification,
args: %{participant_id: participant_id, op: :before_event_notification}
)
end
end
describe "Joining an event registers a job for notification on the day of the event" do
test "if the user has allowed it" do
%User{id: user_id} = user = insert(:user)
settings =
insert(:settings, user_id: user_id, notification_on_day: true, timezone: "Europe/Paris")
user = Map.put(user, :settings, settings)
actor = insert(:actor, user: user)
%DateTime{} = tomorrow = DateTime.utc_now() |> DateTime.add(3600 * 24)
begins_on = %{tomorrow | hour: 16, minute: 0, second: 0, microsecond: {0, 0}}
%Event{begins_on: begins_on} = event = insert(:event, begins_on: begins_on)
%Participant{} = participant = insert(:participant, actor: actor, event: event)
Scheduler.on_day_notification(participant)
assert_enqueued(
worker: Notification,
args: %{user_id: user_id, op: :on_day_notification},
scheduled_at: %{DateTime.shift_zone!(begins_on, settings.timezone) | hour: 8}
)
end
test "not if the user hasn't allowed it" do
%User{id: user_id} = user = insert(:user)
actor = insert(:actor, user: user)
%Participant{} = participant = insert(:participant, actor: actor)
Scheduler.on_day_notification(participant)
refute_enqueued(
worker: Notification,
args: %{user_id: user_id, op: :on_day_notification}
)
end
test "not if it's too late" do
%User{id: user_id} = user = insert(:user)
settings =
insert(:settings, user_id: user_id, notification_on_day: true, timezone: "Europe/Paris")
user = Map.put(user, :settings, settings)
actor = insert(:actor, user: user)
%Event{} = event = insert(:event, begins_on: DateTime.add(DateTime.utc_now(), -3600))
%Participant{} = participant = insert(:participant, actor: actor, event: event)
Scheduler.on_day_notification(participant)
refute_enqueued(
worker: Notification,
args: %{user_id: user_id, op: :on_day_notification}
)
end
test "only once" do
%User{id: user_id} = user = insert(:user)
settings =
insert(:settings, user_id: user_id, notification_on_day: true, timezone: "Europe/Paris")
user = Map.put(user, :settings, settings)
actor = insert(:actor, user: user)
%DateTime{} = tomorrow = DateTime.utc_now() |> DateTime.add(3600 * 24)
begins_on = %{tomorrow | hour: 16, minute: 0, second: 0, microsecond: {0, 0}}
%Event{begins_on: begins_on} = event = insert(:event, begins_on: begins_on)
%Participant{} = participant = insert(:participant, actor: actor, event: event)
Scheduler.on_day_notification(participant)
assert_enqueued(
worker: Notification,
args: %{user_id: user_id, op: :on_day_notification},
scheduled_at: %{DateTime.shift_zone!(begins_on, settings.timezone) | hour: 8}
)
%DateTime{} = tomorrow = DateTime.utc_now() |> DateTime.add(3600 * 24)
begins_on = %{tomorrow | hour: 19, minute: 0, second: 0, microsecond: {0, 0}}
%Event{} = event = insert(:event, begins_on: begins_on)
%Participant{} = participant = insert(:participant, actor: actor, event: event)
Scheduler.on_day_notification(participant)
end
end
end

View File

@@ -0,0 +1,210 @@
defmodule Mobilizon.Service.Workers.NotificationTest do
@moduledoc """
Test the scheduler module
"""
alias Mobilizon.Actors.Actor
alias Mobilizon.Events
alias Mobilizon.Events.{Event, Participant}
alias Mobilizon.Service.Workers.Notification
alias Mobilizon.Users.User
alias Mobilizon.Web.Email.Notification, as: NotificationMailer
use Mobilizon.DataCase
use Bamboo.Test
import Mobilizon.Factory
describe "A before_event_notification job sends an email" do
test "if the user is still participating" do
%User{id: user_id} = user = insert(:user)
settings =
insert(:settings,
user_id: user_id,
notification_before_event: true
)
user = Map.put(user, :settings, settings)
%Actor{} = actor = insert(:actor, user: user)
%Participant{id: participant_id} =
participant = insert(:participant, role: :participant, actor: actor)
Notification.perform(
%{"op" => "before_event_notification", "participant_id" => participant_id},
nil
)
assert_delivered_email(
NotificationMailer.before_event_notification(
participant.actor.user.email,
participant
)
)
end
test "unless the person is no longer participating" do
%Event{id: event_id} = insert(:event)
%User{} = user = insert(:user)
%Actor{id: actor_id} = insert(:actor, user: user)
{:ok, %Participant{id: participant_id} = participant} =
Events.create_participant(%{actor_id: actor_id, event_id: event_id, role: :participant})
actor = Map.put(participant.actor, :user, user)
participant = Map.put(participant, :actor, actor)
assert {:ok, %Participant{}} = Events.delete_participant(participant)
Notification.perform(
%{"op" => "before_event_notification", "participant_id" => participant_id},
nil
)
refute_delivered_email(
NotificationMailer.before_event_notification(
participant.actor.user.email,
participant
)
)
end
test "unless the event has been cancelled" do
%Event{} = event = insert(:event, status: :cancelled)
%Participant{id: participant_id} =
participant = insert(:participant, role: :participant, event: event)
Notification.perform(
%{"op" => "before_event_notification", "participant_id" => participant_id},
nil
)
refute_delivered_email(
NotificationMailer.before_event_notification(
participant.actor.user.email,
participant
)
)
end
end
describe "A on_day_notification job sends an email" do
test "if the user is still participating" do
%User{id: user_id} = user = insert(:user)
settings =
insert(:settings, user_id: user_id, notification_on_day: true, timezone: "Europe/Paris")
user = Map.put(user, :settings, settings)
%Actor{} = actor = insert(:actor, user: user)
%Participant{} = participant = insert(:participant, role: :participant, actor: actor)
Notification.perform(
%{"op" => "on_day_notification", "user_id" => user_id},
nil
)
assert_delivered_email(
NotificationMailer.on_day_notification(
user,
[participant],
1
)
)
end
test "unless the person is no longer participating" do
%Event{id: event_id} = insert(:event)
%User{id: user_id} = user = insert(:user)
settings =
insert(:settings, user_id: user_id, notification_on_day: true, timezone: "Europe/Paris")
user = Map.put(user, :settings, settings)
%Actor{} = actor = insert(:actor, user: user)
{:ok, %Participant{} = participant} =
Events.create_participant(%{actor_id: actor.id, event_id: event_id, role: :participant})
actor = Map.put(participant.actor, :user, user)
participant = Map.put(participant, :actor, actor)
assert {:ok, %Participant{}} = Events.delete_participant(participant)
Notification.perform(
%{"op" => "on_day_notification", "user_id" => user_id},
nil
)
refute_delivered_email(
NotificationMailer.on_day_notification(
user,
[participant],
1
)
)
end
test "unless the event has been cancelled" do
%User{id: user_id} = user = insert(:user)
settings =
insert(:settings, user_id: user_id, notification_on_day: true, timezone: "Europe/Paris")
user = Map.put(user, :settings, settings)
%Actor{} = actor = insert(:actor, user: user)
%Event{} = event = insert(:event, status: :cancelled)
%Participant{} =
participant = insert(:participant, role: :participant, event: event, actor: actor)
Notification.perform(
%{"op" => "on_day_notification", "user_id" => user_id},
nil
)
refute_delivered_email(
NotificationMailer.on_day_notification(
user,
[participant],
1
)
)
end
test "with a lot of events" do
%User{id: user_id} = user = insert(:user)
settings =
insert(:settings, user_id: user_id, notification_on_day: true, timezone: "Europe/Paris")
user = Map.put(user, :settings, settings)
%Actor{} = actor = insert(:actor, user: user)
participants =
Enum.reduce(0..10, [], fn _i, acc ->
%Participant{} = participant = insert(:participant, role: :participant, actor: actor)
acc ++ [participant]
end)
Notification.perform(
%{"op" => "on_day_notification", "user_id" => user_id},
nil
)
refute_delivered_email(
NotificationMailer.on_day_notification(
user,
participants,
3
)
)
end
end
end

View File

@@ -3,7 +3,10 @@ defmodule Mobilizon.GraphQL.AbsintheHelpers do
Absinthe helpers for tests
"""
use Phoenix.ConnTest
import Plug.Conn
import Phoenix.ConnTest
alias Plug.Conn
@endpoint Mobilizon.Web.Endpoint
@@ -23,6 +26,7 @@ defmodule Mobilizon.GraphQL.AbsintheHelpers do
}
end
@spec graphql_query(Conn.t(), Keyword.t()) :: map | no_return
def graphql_query(conn, options) do
conn
|> post("/api", build_query(options[:query], Keyword.get(options, :variables, %{})))

View File

@@ -25,7 +25,9 @@ defmodule Mobilizon.Web.ConnCase do
using do
quote do
# Import conveniences for testing with connections
use Phoenix.ConnTest
import Plug.Conn
import Phoenix.ConnTest
import Mobilizon.Web.Router.Helpers
# The default endpoint for testing

View File

@@ -22,6 +22,16 @@ defmodule Mobilizon.Factory do
}
end
def settings_factory do
%Mobilizon.Users.Setting{
timezone: nil,
notification_on_day: false,
notification_each_week: false,
notification_before_event: false,
user_id: nil
}
end
def actor_factory do
preferred_username = sequence("thomas")
@@ -39,16 +49,28 @@ defmodule Mobilizon.Factory do
following_url: Actor.build_url(preferred_username, :following),
inbox_url: Actor.build_url(preferred_username, :inbox),
outbox_url: Actor.build_url(preferred_username, :outbox),
shared_inbox_url: "#{Endpoint.url()}/inbox",
last_refreshed_at: DateTime.utc_now(),
user: build(:user)
}
end
def group_factory do
preferred_username = sequence("myGroup")
struct!(
actor_factory(),
%{
type: :Group
preferred_username: preferred_username,
type: :Group,
url: Actor.build_url(preferred_username, :page),
followers_url: Actor.build_url(preferred_username, :followers),
following_url: Actor.build_url(preferred_username, :following),
members_url: Actor.build_url(preferred_username, :members),
resources_url: Actor.build_url(preferred_username, :resources),
inbox_url: Actor.build_url(preferred_username, :inbox),
outbox_url: Actor.build_url(preferred_username, :outbox),
user: nil
}
)
end
@@ -94,7 +116,7 @@ defmodule Mobilizon.Factory do
def comment_factory do
uuid = Ecto.UUID.generate()
%Mobilizon.Events.Comment{
%Mobilizon.Conversations.Comment{
text: "My Comment",
actor: build(:actor),
event: build(:event),
@@ -130,7 +152,8 @@ defmodule Mobilizon.Factory do
uuid: uuid,
join_options: :free,
options: %{},
participant_stats: %{}
participant_stats: %{},
status: :confirmed
}
end
@@ -175,10 +198,14 @@ defmodule Mobilizon.Factory do
end
def member_factory do
uuid = Ecto.UUID.generate()
%Mobilizon.Actors.Member{
parent: build(:actor),
actor: build(:actor),
role: :not_approved
role: :not_approved,
id: uuid,
url: "#{Endpoint.url()}/member/#{uuid}"
}
end
@@ -244,4 +271,47 @@ defmodule Mobilizon.Factory do
report: build(:report)
}
end
def todo_list_factory do
uuid = Ecto.UUID.generate()
%Mobilizon.Todos.TodoList{
title: sequence("todo list"),
actor: build(:group),
id: uuid,
url: Routes.todo_list_url(Endpoint, :todo_list, uuid)
}
end
def todo_factory do
uuid = Ecto.UUID.generate()
%Mobilizon.Todos.Todo{
id: uuid,
title: sequence("my todo"),
todo_list: build(:todo_list),
status: false,
due_date: Timex.shift(DateTime.utc_now(), hours: 2),
assigned_to: build(:actor),
url: Routes.todo_url(Endpoint, :todo, uuid),
creator: build(:actor)
}
end
def resource_factory do
uuid = Ecto.UUID.generate()
title = sequence("my resource")
%Mobilizon.Resources.Resource{
id: uuid,
title: title,
type: :link,
resource_url: "https://somewebsite.com/path",
actor: build(:group),
creator: build(:actor),
parent: nil,
url: Routes.resource_url(Endpoint, :resource, uuid),
path: "/#{title}"
}
end
end

View File

@@ -336,46 +336,96 @@ defmodule Mobilizon.Web.ActivityPubControllerTest do
end
end
#
# describe "/@:preferred_username/following" do
# test "it returns the following in a collection", %{conn: conn} do
# actor = insert(:actor)
# actor2 = insert(:actor)
# Mobilizon.Federation.ActivityPub.follow(actor, actor2)
describe "/@actor/members for a group" do
test "it returns the members in a group", %{conn: conn} do
actor = insert(:actor)
# result =
# conn
# |> get("/@#{actor.preferred_username}/following")
# |> json_response(200)
assert {:ok, %Actor{} = group} =
Actors.create_group(%{
creator_actor_id: actor.id,
preferred_username: "my_group",
visibility: :public
})
# assert result["first"]["orderedItems"] == [actor2.url]
# end
result =
conn
|> get(Actor.build_url(group.preferred_username, :members))
|> json_response(200)
# test "it works for more than 10 actors", %{conn: conn} do
# actor = insert(:actor)
assert hd(result["first"]["orderedItems"])["actor"] == actor.url
assert hd(result["first"]["orderedItems"])["object"] == group.url
assert hd(result["first"]["orderedItems"])["role"] == "administrator"
assert hd(result["first"]["orderedItems"])["type"] == "Member"
end
# Enum.each(1..15, fn _ ->
# actor = Repo.get(Actor, actor.id)
# other_actor = insert(:actor)
# Actors.follow(actor, other_actor)
# end)
test "it returns no members for a private group", %{conn: conn} do
actor = insert(:actor)
# result =
# conn
# |> get("/@#{actor.preferred_username}/following")
# |> json_response(200)
assert {:ok, %Actor{} = group} =
Actors.create_group(%{creator_actor_id: actor.id, preferred_username: "my_group"})
# assert length(result["first"]["orderedItems"]) == 10
# assert result["first"]["totalItems"] == 15
# assert result["totalItems"] == 15
result =
conn
|> get(Actor.build_url(actor.preferred_username, :members))
|> json_response(200)
# result =
# conn
# |> get("/@#{actor.preferred_username}/following?page=2")
# |> json_response(200)
assert result["first"]["orderedItems"] == []
end
# assert length(result["orderedItems"]) == 5
# assert result["totalItems"] == 15
# end
# end
test "it works for more than 10 actors", %{conn: conn} do
actor = insert(:actor, preferred_username: "my_admin")
assert {:ok, %Actor{} = group} =
Actors.create_group(%{
creator_actor_id: actor.id,
preferred_username: "my_group",
visibility: :public
})
Enum.each(1..15, fn _ ->
other_actor = insert(:actor)
insert(:member, actor: other_actor, parent: group, role: :member)
end)
result =
conn
|> get(Actor.build_url(group.preferred_username, :members))
|> json_response(200)
assert length(result["first"]["orderedItems"]) == 10
# 15 members + 1 admin
assert result["totalItems"] == 16
result =
conn
|> get(Actor.build_url(group.preferred_username, :members, page: 2))
|> json_response(200)
assert length(result["orderedItems"]) == 6
end
test "it returns members for a private group but request is signed by an actor", %{conn: conn} do
actor_group_admin = insert(:actor)
actor_applicant = insert(:actor)
assert {:ok, %Actor{} = group} =
Actors.create_group(%{
creator_actor_id: actor_group_admin.id,
preferred_username: "my_group"
})
insert(:member, actor: actor_applicant, parent: group, role: :member)
result =
conn
|> assign(:actor, actor_applicant)
|> get(Actor.build_url(group.preferred_username, :members))
|> json_response(200)
assert [admin_member | [member]] = result["first"]["orderedItems"]
assert admin_member["role"] == "administrator"
assert member["role"] == "member"
assert result["totalItems"] == 2
end
end
end

View File

@@ -7,7 +7,8 @@ defmodule Mobilizon.Web.ErrorViewTest do
alias Mobilizon.Web.ErrorView
test "renders 404.html" do
assert render_to_string(ErrorView, "404.html", []) =~
# Produced HTML might have new lines inside
assert Regex.replace(~r/(\r\n|\n|\r) +/, render_to_string(ErrorView, "404.html", []), " ") =~
"We're sorry but mobilizon doesn't work properly without JavaScript enabled. Please enable it to continue."
end