Fix tests

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
Thomas Citharel 2018-11-12 18:17:53 +01:00
parent c9c55b4080
commit d9f29e7d7b
29 changed files with 645 additions and 508 deletions

View File

@ -3,5 +3,5 @@ defmodule Mobilizon.Activity do
Represents an activity Represents an activity
""" """
defstruct [:id, :data, :local, :actor, :recipients, :notifications, :type] defstruct [:data, :local, :actor, :recipients, :notifications]
end end

View File

@ -131,7 +131,6 @@ defmodule Mobilizon.Actors.Actor do
:outbox_url, :outbox_url,
:inbox_url, :inbox_url,
:type, :type,
:name,
:domain, :domain,
:preferred_username, :preferred_username,
:keys :keys
@ -179,17 +178,38 @@ defmodule Mobilizon.Actors.Actor do
|> put_change(:local, true) |> put_change(:local, true)
end end
@doc """
Get a public key for a given ActivityPub actor ID (url)
"""
@spec get_public_key_for_url(String.t()) :: {:ok, String.t()} @spec get_public_key_for_url(String.t()) :: {:ok, String.t()}
def get_public_key_for_url(url) do def get_public_key_for_url(url) do
with {:ok, %Actor{} = actor} <- Actors.get_or_fetch_by_url(url) do with {:ok, %Actor{keys: keys}} <- Actors.get_or_fetch_by_url(url),
{:ok, actor.keys} {:ok, public_key} <- prepare_public_key(keys) do
{:ok, public_key}
else else
{:error, :pem_decode_error} ->
Logger.error("Error while decoding PEM")
{:error, :pem_decode_error}
_ -> _ ->
Logger.error("Unable to fetch actor, so no keys for you") Logger.error("Unable to fetch actor, so no keys for you")
{:error, :actor_fetch_error} {:error, :actor_fetch_error}
end end
end end
@doc """
Convert internal PEM encoded keys to public key format
"""
@spec prepare_public_key(String.t()) :: {:ok, tuple()} | {:error, :pem_decode_error}
def prepare_public_key(public_key_code) do
with [public_key_entry] <- :public_key.pem_decode(public_key_code) do
{:ok, :public_key.pem_entry_decode(public_key_entry)}
else
_err ->
{:error, :pem_decode_error}
end
end
@doc """ @doc """
Get followers from an actor Get followers from an actor

View File

@ -6,7 +6,7 @@ defmodule Mobilizon.Actors do
import Ecto.Query, warn: false import Ecto.Query, warn: false
alias Mobilizon.Repo alias Mobilizon.Repo
alias Mobilizon.Actors.Actor alias Mobilizon.Actors.{Actor, Bot, Member, Follower, User}
alias Mobilizon.Actors alias Mobilizon.Actors
alias Mobilizon.Service.ActivityPub alias Mobilizon.Service.ActivityPub
@ -24,10 +24,11 @@ defmodule Mobilizon.Actors do
## Examples ## Examples
iex> list_actors() iex> Mobilizon.Actors.list_actors()
[%Actor{}, ...] [%Mobilizon.Actors.Actor{}]
""" """
@spec list_actors() :: list()
def list_actors do def list_actors do
Repo.all(Actor) Repo.all(Actor)
end end
@ -40,12 +41,13 @@ defmodule Mobilizon.Actors do
## Examples ## Examples
iex> get_actor!(123) iex> get_actor!(123)
%Actor{} %Mobilizon.Actors.Actor{}
iex> get_actor!(456) iex> get_actor!(456)
** (Ecto.NoResultsError) ** (Ecto.NoResultsError)
""" """
@spec get_actor!(integer()) :: Actor.t()
def get_actor!(id) do def get_actor!(id) do
Repo.get!(Actor, id) Repo.get!(Actor, id)
end end
@ -53,7 +55,7 @@ defmodule Mobilizon.Actors do
@doc """ @doc """
Returns the associated actor for an user, either the default set one or the first found Returns the associated actor for an user, either the default set one or the first found
""" """
@spec get_actor_for_user(%Mobilizon.Actors.User{}) :: %Mobilizon.Actors.Actor{} @spec get_actor_for_user(Mobilizon.Actors.User.t()) :: Mobilizon.Actors.Actor.t()
def get_actor_for_user(%Mobilizon.Actors.User{} = user) do def get_actor_for_user(%Mobilizon.Actors.User{} = user) do
case user.default_actor_id do case user.default_actor_id do
nil -> get_first_actor_for_user(user) nil -> get_first_actor_for_user(user)
@ -82,10 +84,10 @@ defmodule Mobilizon.Actors do
## Examples ## Examples
iex> create_actor(%{field: value}) iex> create_actor(%{preferred_username: "test"})
{:ok, %Actor{}} {:ok, %Mobilizon.Actors.Actor{preferred_username: "test"}}
iex> create_actor(%{field: bad_value}) iex> create_actor(%{preferred_username: nil})
{:error, %Ecto.Changeset{}} {:error, %Ecto.Changeset{}}
""" """
@ -100,10 +102,10 @@ defmodule Mobilizon.Actors do
## Examples ## Examples
iex> update_actor(actor, %{field: new_value}) iex> update_actor(%Actor{preferred_username: "toto"}, %{preferred_username: "tata"})
{:ok, %Actor{}} {:ok, %Mobilizon.Actors.Actor{preferred_username: "tata"}}
iex> update_actor(actor, %{field: bad_value}) iex> update_actor(%Actor{preferred_username: "toto"}, %{preferred_username: nil})
{:error, %Ecto.Changeset{}} {:error, %Ecto.Changeset{}}
""" """
@ -118,13 +120,14 @@ defmodule Mobilizon.Actors do
## Examples ## Examples
iex> delete_actor(actor) iex> delete_actor(%Actor{})
{:ok, %Actor{}} {:ok, %Mobilizon.Actors.Actor{}}
iex> delete_actor(actor) iex> delete_actor(nil)
{:error, %Ecto.Changeset{}} {:error, %Ecto.Changeset{}}
""" """
@spec delete_actor(Actor.t()) :: {:ok, Actor.t()} | {:error, Ecto.Changeset.t()}
def delete_actor(%Actor{} = actor) do def delete_actor(%Actor{} = actor) do
Repo.delete(actor) Repo.delete(actor)
end end
@ -134,8 +137,8 @@ defmodule Mobilizon.Actors do
## Examples ## Examples
iex> change_actor(actor) iex> change_actor(%Actor{})
%Ecto.Changeset{source: %Actor{}} %Ecto.Changeset{data: %Mobilizon.Actors.Actor{}}
""" """
def change_actor(%Actor{} = actor) do def change_actor(%Actor{} = actor) do
@ -164,10 +167,10 @@ defmodule Mobilizon.Actors do
## Examples ## Examples
iex> create_group(%{field: value}) iex> create_group(%{name: "group name"})
{:ok, %Actor{}} {:ok, %Mobilizon.Actors.Actor{}}
iex> create_group(%{field: bad_value}) iex> create_group(%{name: nil})
{:error, %Ecto.Changeset{}} {:error, %Ecto.Changeset{}}
""" """
@ -185,28 +188,20 @@ defmodule Mobilizon.Actors do
## Examples ## Examples
iex> list_users() iex> list_users()
[%User{}, ...] [%Mobilizon.Actors.User{}]
""" """
def list_users do def list_users do
Repo.all(User) Repo.all(User)
end end
@doc """
List users with their associated actors. No reason for that, so removed
"""
# def list_users_with_actors do
# users = Repo.all(User)
# Repo.preload(users, :actors)
# end
defp blank?(""), do: nil defp blank?(""), do: nil
defp blank?(n), do: n defp blank?(n), do: n
def insert_or_update_actor(data, preload \\ false) do def insert_or_update_actor(data, preload \\ false) do
cs = Actor.remote_actor_creation(data) cs = Actor.remote_actor_creation(data)
actor = {:ok, actor} =
Repo.insert( Repo.insert(
cs, cs,
on_conflict: [ on_conflict: [
@ -249,7 +244,7 @@ defmodule Mobilizon.Actors do
## Examples ## Examples
iex> get_user!(123) iex> get_user!(123)
%User{} %Mobilizon.Actors.User{}
iex> get_user!(456) iex> get_user!(456)
** (Ecto.NoResultsError) ** (Ecto.NoResultsError)
@ -257,13 +252,19 @@ defmodule Mobilizon.Actors do
""" """
def get_user!(id), do: Repo.get!(User, id) def get_user!(id), do: Repo.get!(User, id)
def get_user_with_actor!(id) do @doc """
Get an user with it's actors
Raises `Ecto.NoResultsError` if the User does not exist.
"""
@spec get_user_with_actors!(integer()) :: User.t()
def get_user_with_actors!(id) do
user = Repo.get!(User, id) user = Repo.get!(User, id)
Repo.preload(user, :actors) Repo.preload(user, :actors)
end end
@spec get_user_with_actor(integer()) :: %User{} @spec get_user_with_actors(integer()) :: User.t()
def get_user_with_actor(id) do def get_user_with_actors(id) do
case Repo.get(User, id) do case Repo.get(User, id) do
nil -> {:error, "User with ID #{id} not found"} nil -> {:error, "User with ID #{id} not found"}
user -> {:ok, Repo.preload(user, :actors)} user -> {:ok, Repo.preload(user, :actors)}
@ -271,9 +272,22 @@ defmodule Mobilizon.Actors do
end end
@doc """ @doc """
Get an actor by it's URL (ActivityPub ID) Get an actor by it's URL (ActivityPub ID). The `:preload` option allows preloading the Followers relation.
Raises `Ecto.NoResultsError` if the Actor does not exist.
## Examples
iex> get_actor_by_url("https://mastodon.server.tld/users/user")
{:ok, %Mobilizon.Actors.Actor{preferred_username: "user"}}
iex> get_actor_by_url("https://mastodon.server.tld/users/user", true)
{:ok, %Mobilizon.Actors.Actor{preferred_username: "user", followers: []}}
iex> get_actor_by_url("non existent")
{:error, :actor_not_found}
""" """
@spec get_actor_by_url(String.t(), boolean()) :: {:ok, struct()} | {:error, :actor_not_found} @spec get_actor_by_url(String.t(), boolean()) :: {:ok, Actor.t()} | {:error, :actor_not_found}
def get_actor_by_url(url, preload \\ false) do def get_actor_by_url(url, preload \\ false) do
case Repo.get_by(Actor, url: url) do case Repo.get_by(Actor, url: url) do
nil -> nil ->
@ -284,6 +298,22 @@ defmodule Mobilizon.Actors do
end end
end end
@doc """
Get an actor by it's URL (ActivityPub ID). The `:preload` option allows preloading the Followers relation.
Raises `Ecto.NoResultsError` if the Actor does not exist.
## Examples
iex> get_actor_by_url!("https://mastodon.server.tld/users/user")
%Mobilizon.Actors.Actor{}
iex> get_actor_by_url!("https://mastodon.server.tld/users/user", true)
{:ok, %Mobilizon.Actors.Actor{preferred_username: "user", followers: []}}
iex> get_actor_by_url!("non existent")
** (Ecto.NoResultsError)
"""
@spec get_actor_by_url!(String.t(), boolean()) :: struct() @spec get_actor_by_url!(String.t(), boolean()) :: struct()
def get_actor_by_url!(url, preload \\ false) do def get_actor_by_url!(url, preload \\ false) do
actor = Repo.get_by!(Actor, url: url) actor = Repo.get_by!(Actor, url: url)
@ -324,16 +354,32 @@ defmodule Mobilizon.Actors do
end end
def get_or_fetch_by_url(url, preload \\ false) do def get_or_fetch_by_url(url, preload \\ false) do
if {:ok, actor} = get_actor_by_url(url, preload) do with {:ok, actor} <- get_actor_by_url(url, preload) do
{:ok, actor} {:ok, actor}
else else
case ActivityPub.make_actor_from_url(url, preload) do _ ->
{:ok, actor} -> case ActivityPub.make_actor_from_url(url, preload) do
{:ok, actor} {:ok, actor} ->
{:ok, actor}
_ -> _ ->
{:error, "Could not fetch by AP id"} {:error, "Could not fetch by AP id"}
end end
end
end
def get_or_fetch_by_url!(url, preload \\ false) do
with {:ok, actor} <- get_actor_by_url(url, preload) do
actor
else
_ ->
case ActivityPub.make_actor_from_url(url, preload) do
{:ok, actor} ->
actor
_ ->
raise "Could not fetch by AP id"
end
end end
end end
@ -503,10 +549,10 @@ defmodule Mobilizon.Actors do
## Examples ## Examples
iex> create_user(%{field: value}) iex> create_user(%{email: "test@test.tld"})
{:ok, %User{}} {:ok, %Mobilizon.Actors.User{}}
iex> create_user(%{field: bad_value}) iex> create_user(%{email: "not an email"})
{:error, %Ecto.Changeset{}} {:error, %Ecto.Changeset{}}
""" """
@ -521,11 +567,11 @@ defmodule Mobilizon.Actors do
## Examples ## Examples
iex> get_user_by_email(user, email) iex> get_user_by_email("test@test.tld", true)
{:ok, %User{}} {:ok, %Mobilizon.Actors.User{}}
iex> get_user_by_email(user, wrong_email) iex> get_user_by_email("test@notfound.tld", false)
{:error, nil} {:error, :user_not_found}
""" """
def get_user_by_email(email, activated \\ nil) do def get_user_by_email(email, activated \\ nil) do
query = query =
@ -546,10 +592,10 @@ defmodule Mobilizon.Actors do
## Examples ## Examples
iex> update_user(user, %{field: new_value}) iex> update_user(User{}, %{password: "coucou"})
{:ok, %User{}} {:ok, %Mobilizon.Actors.User{}}
iex> update_user(user, %{field: bad_value}) iex> update_user(User{}, %{password: nil})
{:error, %Ecto.Changeset{}} {:error, %Ecto.Changeset{}}
""" """
@ -564,10 +610,10 @@ defmodule Mobilizon.Actors do
## Examples ## Examples
iex> delete_user(user) iex> delete_user(%User{email: "test@test.tld"})
{:ok, %User{}} {:ok, %Mobilizon.Actors.User{}}
iex> delete_user(user) iex> delete_user(%User{})
{:error, %Ecto.Changeset{}} {:error, %Ecto.Changeset{}}
""" """
@ -580,8 +626,8 @@ defmodule Mobilizon.Actors do
## Examples ## Examples
iex> change_user(user) iex> change_user(%Mobilizon.Actors.User{})
%Ecto.Changeset{source: %User{}} %Ecto.Changeset{data: %Mobilizon.Actors.User{}}
""" """
def change_user(%User{} = user) do def change_user(%User{} = user) do
@ -598,7 +644,7 @@ defmodule Mobilizon.Actors do
## Examples ## Examples
iex> get_member!(123) iex> get_member!(123)
%Member{} %Mobilizon.Actors.Member{}
iex> get_member!(456) iex> get_member!(456)
** (Ecto.NoResultsError) ** (Ecto.NoResultsError)
@ -611,10 +657,10 @@ defmodule Mobilizon.Actors do
## Examples ## Examples
iex> create_member(%{field: value}) iex> create_member(%{actor: %Actor{}})
{:ok, %Member{}} {:ok, %Mobilizon.Actors.Member{}}
iex> create_member(%{field: bad_value}) iex> create_member(%{actor: nil})
{:error, %Ecto.Changeset{}} {:error, %Ecto.Changeset{}}
""" """
@ -632,10 +678,10 @@ defmodule Mobilizon.Actors do
## Examples ## Examples
iex> update_member(member, %{field: new_value}) iex> update_member(%Member{}, %{role: 3})
{:ok, %Member{}} {:ok, %Mobilizon.Actors.Member{}}
iex> update_member(member, %{field: bad_value}) iex> update_member(%Member{}, %{role: nil})
{:error, %Ecto.Changeset{}} {:error, %Ecto.Changeset{}}
""" """
@ -650,10 +696,10 @@ defmodule Mobilizon.Actors do
## Examples ## Examples
iex> delete_member(member) iex> delete_member(%Member{})
{:ok, %Member{}} {:ok, %Mobilizon.Actors.Member{}}
iex> delete_member(member) iex> delete_member(%Member{})
{:error, %Ecto.Changeset{}} {:error, %Ecto.Changeset{}}
""" """
@ -666,8 +712,8 @@ defmodule Mobilizon.Actors do
## Examples ## Examples
iex> change_member(member) iex> change_member(%Member{})
%Ecto.Changeset{source: %Member{}} %Ecto.Changeset{data: %Mobilizon.Actors.Member{}}
""" """
def change_member(%Member{} = member) do def change_member(%Member{} = member) do
@ -702,7 +748,7 @@ defmodule Mobilizon.Actors do
## Examples ## Examples
iex> list_bots() iex> list_bots()
[%Bot{}, ...] [%Mobilizon.Actors.Bot{}]
""" """
def list_bots do def list_bots do
@ -717,7 +763,7 @@ defmodule Mobilizon.Actors do
## Examples ## Examples
iex> get_bot!(123) iex> get_bot!(123)
%Bot{} %Mobilizon.Actors.Bot{}
iex> get_bot!(456) iex> get_bot!(456)
** (Ecto.NoResultsError) ** (Ecto.NoResultsError)
@ -735,10 +781,10 @@ defmodule Mobilizon.Actors do
## Examples ## Examples
iex> create_bot(%{field: value}) iex> create_bot(%{source: "toto"})
{:ok, %Bot{}} {:ok, %Mobilizon.Actors.Bot{}}
iex> create_bot(%{field: bad_value}) iex> create_bot(%{source: nil})
{:error, %Ecto.Changeset{}} {:error, %Ecto.Changeset{}}
""" """
@ -753,10 +799,10 @@ defmodule Mobilizon.Actors do
## Examples ## Examples
iex> update_bot(bot, %{field: new_value}) iex> update_bot(%Bot{}, %{source: "new"})
{:ok, %Bot{}} {:ok, %Mobilizon.Actors.Bot{}}
iex> update_bot(bot, %{field: bad_value}) iex> update_bot(%Bot{}, %{source: nil})
{:error, %Ecto.Changeset{}} {:error, %Ecto.Changeset{}}
""" """
@ -771,10 +817,10 @@ defmodule Mobilizon.Actors do
## Examples ## Examples
iex> delete_bot(bot) iex> delete_bot(%Bot{})
{:ok, %Bot{}} {:ok, %Mobilizon.Actors.Bot{}}
iex> delete_bot(bot) iex> delete_bot(%Bot{})
{:error, %Ecto.Changeset{}} {:error, %Ecto.Changeset{}}
""" """
@ -787,8 +833,8 @@ defmodule Mobilizon.Actors do
## Examples ## Examples
iex> change_bot(bot) iex> change_bot(%Bot{})
%Ecto.Changeset{source: %Bot{}} %Ecto.Changeset{data: %Mobilizon.Actors.Bot{}}
""" """
def change_bot(%Bot{} = bot) do def change_bot(%Bot{} = bot) do
@ -805,7 +851,7 @@ defmodule Mobilizon.Actors do
## Examples ## Examples
iex> get_follower!(123) iex> get_follower!(123)
%Follower{} %Mobilizon.Actors.Follower{}
iex> get_follower!(456) iex> get_follower!(456)
** (Ecto.NoResultsError) ** (Ecto.NoResultsError)
@ -821,10 +867,10 @@ defmodule Mobilizon.Actors do
## Examples ## Examples
iex> create_follower(%{field: value}) iex> create_follower(%{actor: %Actor{}})
{:ok, %Follower{}} {:ok, %Mobilizon.Actors.Follower{}}
iex> create_follower(%{field: bad_value}) iex> create_follower(%{actor: nil})
{:error, %Ecto.Changeset{}} {:error, %Ecto.Changeset{}}
""" """
@ -839,10 +885,10 @@ defmodule Mobilizon.Actors do
## Examples ## Examples
iex> update_follower(follower, %{field: new_value}) iex> update_follower(Follower{}, %{approved: true})
{:ok, %Follower{}} {:ok, %Mobilizon.Actors.Follower{}}
iex> update_follower(follower, %{field: bad_value}) iex> update_follower(Follower{}, %{approved: nil})
{:error, %Ecto.Changeset{}} {:error, %Ecto.Changeset{}}
""" """
@ -857,10 +903,10 @@ defmodule Mobilizon.Actors do
## Examples ## Examples
iex> delete_follower(follower) iex> delete_follower(Follower{})
{:ok, %Follower{}} {:ok, %Mobilizon.Actors.Follower{}}
iex> delete_follower(follower) iex> delete_follower(Follower{})
{:error, %Ecto.Changeset{}} {:error, %Ecto.Changeset{}}
""" """
@ -873,8 +919,8 @@ defmodule Mobilizon.Actors do
## Examples ## Examples
iex> change_follower(follower) iex> change_follower(Follower{})
%Ecto.Changeset{source: %Follower{}} %Ecto.Changeset{data: %Mobilizon.Actors.Follower{}}
""" """
def change_follower(%Follower{} = follower) do def change_follower(%Follower{} = follower) do

View File

@ -1,7 +1,7 @@
defmodule Mobilizon.Actors.Service.Tools do defmodule Mobilizon.Actors.Service.Tools do
alias Mobilizon.Actors.User alias Mobilizon.Actors.User
@spec we_can_send_email(User.t()) :: boolean @spec we_can_send_email(User.t(), atom()) :: :ok | {:error, :email_too_soon}
def we_can_send_email(%User{} = user, key \\ :reset_password_sent_at) do def we_can_send_email(%User{} = user, key \\ :reset_password_sent_at) do
case Map.get(user, key) do case Map.get(user, key) do
nil -> nil ->

View File

@ -142,7 +142,7 @@ defmodule Mobilizon.Events do
Gets an event by it's URL Gets an event by it's URL
""" """
def get_event_full_by_url!(url) do def get_event_full_by_url!(url) do
event = Repo.get_by(Event, url: url) event = Repo.get_by!(Event, url: url)
Repo.preload(event, [ Repo.preload(event, [
:organizer_actor, :organizer_actor,
@ -326,7 +326,7 @@ defmodule Mobilizon.Events do
""" """
def get_category!(id), do: Repo.get!(Category, id) def get_category!(id), do: Repo.get!(Category, id)
@spec get_category_by_title(String.t()) :: tuple() @spec get_category_by_title(String.t()) :: Category.t() | nil
def get_category_by_title(title) when is_binary(title) do def get_category_by_title(title) when is_binary(title) do
Repo.get_by(Category, title: title) Repo.get_by(Category, title: title)
end end

View File

@ -4,6 +4,7 @@ defmodule MobilizonWeb.ActivityPubController do
alias Mobilizon.Events.{Event, Comment} alias Mobilizon.Events.{Event, Comment}
alias MobilizonWeb.ActivityPub.{ObjectView, ActorView} alias MobilizonWeb.ActivityPub.{ObjectView, ActorView}
alias Mobilizon.Service.ActivityPub alias Mobilizon.Service.ActivityPub
alias Mobilizon.Service.ActivityPub.Utils
alias Mobilizon.Service.Federator alias Mobilizon.Service.Federator
require Logger require Logger
@ -46,7 +47,7 @@ defmodule MobilizonWeb.ActivityPubController do
true <- event.public do true <- event.public do
conn conn
|> put_resp_header("content-type", "application/activity+json") |> put_resp_header("content-type", "application/activity+json")
|> json(ObjectView.render("event.json", %{event: event})) |> json(ObjectView.render("event.json", %{event: event |> Utils.make_event_data()}))
else else
_ -> _ ->
{:error, :not_found} {:error, :not_found}
@ -60,7 +61,7 @@ defmodule MobilizonWeb.ActivityPubController do
# true <- comment.public do # true <- comment.public do
conn conn
|> put_resp_header("content-type", "application/activity+json") |> put_resp_header("content-type", "application/activity+json")
|> json(ObjectView.render("comment.json", %{comment: comment})) |> json(ObjectView.render("comment.json", %{comment: comment |> Utils.make_comment_data()}))
else else
_ -> _ ->
{:error, :not_found} {:error, :not_found}
@ -137,11 +138,11 @@ defmodule MobilizonWeb.ActivityPubController do
headers = Enum.into(conn.req_headers, %{}) headers = Enum.into(conn.req_headers, %{})
if String.contains?(headers["signature"], params["actor"]) do if String.contains?(headers["signature"], params["actor"]) do
Logger.info( Logger.error(
"Signature validation error for: #{params["actor"]}, make sure you are forwarding the HTTP Host header!" "Signature validation error for: #{params["actor"]}, make sure you are forwarding the HTTP Host header!"
) )
Logger.info(inspect(conn.req_headers)) Logger.error(inspect(conn.req_headers))
end end
json(conn, "error") json(conn, "error")

View File

@ -24,7 +24,7 @@ defmodule MobilizonWeb.Guardian do
try do try do
case Integer.parse(uid_str) do case Integer.parse(uid_str) do
{uid, ""} -> {uid, ""} ->
{:ok, Actors.get_user_with_actor!(uid)} {:ok, Actors.get_user_with_actors!(uid)}
_ -> _ ->
{:error, :invalid_id} {:error, :invalid_id}

View File

@ -18,34 +18,31 @@ defmodule MobilizonWeb.HTTPSignaturePlug do
end end
def call(conn, _opts) do def call(conn, _opts) do
user = conn.params["actor"] actor = conn.params["actor"]
Logger.debug(fn -> Logger.debug(fn ->
"Checking sig for #{user}" "Checking sig for #{actor}"
end) end)
with [signature | _] <- get_req_header(conn, "signature") do [signature | _] = get_req_header(conn, "signature")
cond do
signature && String.contains?(signature, user) ->
conn =
conn
|> put_req_header(
"(request-target)",
String.downcase("#{conn.method}") <> " #{conn.request_path}"
)
assign(conn, :valid_signature, HTTPSignatures.validate_conn(conn)) cond do
# Dialyzer doesn't like this line
signature -> signature && String.contains?(signature, actor) ->
Logger.debug("Signature not from actor") conn =
assign(conn, :valid_signature, false)
true ->
Logger.debug("No signature header!")
conn conn
end |> put_req_header(
else "(request-target)",
_ -> String.downcase("#{conn.method}") <> " #{conn.request_path}"
)
assign(conn, :valid_signature, HTTPSignatures.validate_conn(conn))
signature ->
Logger.debug("Signature not from actor")
assign(conn, :valid_signature, false)
true ->
Logger.debug("No signature header!") Logger.debug("No signature header!")
conn conn
end end

View File

@ -6,7 +6,7 @@ defmodule MobilizonWeb.Resolvers.User do
Find an user by it's ID Find an user by it's ID
""" """
def find_user(_parent, %{id: id}, _resolution) do def find_user(_parent, %{id: id}, _resolution) do
Actors.get_user_with_actor(id) Actors.get_user_with_actors(id)
end end
@doc """ @doc """

View File

@ -13,11 +13,15 @@ defmodule MobilizonWeb.Router do
plug(:accepts, ["json", "jrd-json"]) plug(:accepts, ["json", "jrd-json"])
end end
pipeline :activity_pub do pipeline :activity_pub_signature do
plug(:accepts, ["activity-json", "html"]) plug(:accepts, ["activity-json", "html"])
plug(MobilizonWeb.HTTPSignaturePlug) plug(MobilizonWeb.HTTPSignaturePlug)
end end
pipeline :activity_pub do
plug(:accepts, ["activity-json", "html"])
end
pipeline :browser do pipeline :browser do
plug(:accepts, ["html"]) plug(:accepts, ["html"])
plug(:fetch_session) plug(:fetch_session)
@ -56,6 +60,10 @@ defmodule MobilizonWeb.Router do
get("/@:name/followers", ActivityPubController, :followers) get("/@:name/followers", ActivityPubController, :followers)
get("/events/:uuid", ActivityPubController, :event) get("/events/:uuid", ActivityPubController, :event)
get("/comments/:uuid", ActivityPubController, :comment) get("/comments/:uuid", ActivityPubController, :comment)
end
scope "/", MobilizonWeb do
pipe_through(:activity_pub_signature)
post("/@:name/inbox", ActivityPubController, :inbox) post("/@:name/inbox", ActivityPubController, :inbox)
post("/inbox", ActivityPubController, :inbox) post("/inbox", ActivityPubController, :inbox)
end end

View File

@ -309,10 +309,10 @@ defmodule MobilizonWeb.Schema do
resolve(&Resolvers.User.change_default_actor/3) resolve(&Resolvers.User.change_default_actor/3)
end end
@desc "Upload a picture" # @desc "Upload a picture"
field :upload_picture, :picture do # field :upload_picture, :picture do
arg(:file, non_null(:upload)) # arg(:file, non_null(:upload))
resolve(&Resolvers.Upload.upload_picture/3) # resolve(&Resolvers.Upload.upload_picture/3)
end # end
end end
end end

View File

@ -97,11 +97,11 @@ defmodule MobilizonWeb.ActivityPub.ActorView do
{activities, total} = ActivityPub.fetch_public_activities_for_actor(actor, page) {activities, total} = ActivityPub.fetch_public_activities_for_actor(actor, page)
collection = # collection =
Enum.map(activities, fn act -> # Enum.map(activities, fn act ->
{:ok, data} = Transmogrifier.prepare_outgoing(act.data) # {:ok, data} = Transmogrifier.prepare_outgoing(act.data)
data # data
end) # end)
iri = "#{actor.url}/outbox" iri = "#{actor.url}/outbox"
@ -127,9 +127,9 @@ defmodule MobilizonWeb.ActivityPub.ActorView do
end end
end end
def render("activity.json", %{activity: %Activity{local: local} = activity}) do def render("activity.json", %{activity: %Activity{local: local, data: data} = activity}) do
%{ %{
"id" => activity.data.url <> "/activity", "id" => data["id"],
"type" => "type" =>
if local do if local do
"Create" "Create"
@ -139,14 +139,14 @@ defmodule MobilizonWeb.ActivityPub.ActorView do
"actor" => activity.actor, "actor" => activity.actor,
# Not sure if needed since this is used into outbox # Not sure if needed since this is used into outbox
"published" => Timex.now(), "published" => Timex.now(),
"to" => ["https://www.w3.org/ns/activitystreams#Public"], "to" => activity.recipients,
"object" => "object" =>
case activity.type do case data["type"] do
:Event -> "Event" ->
render_one(activity.data, ObjectView, "event.json", as: :event) render_one(data, ObjectView, "event.json", as: :event)
:Comment -> "Note" ->
render_one(activity.data, ObjectView, "comment.json", as: :comment) render_one(data, ObjectView, "comment.json", as: :comment)
end end
} }
|> Map.merge(Utils.make_json_ld_header()) |> Map.merge(Utils.make_json_ld_header())

View File

@ -7,13 +7,14 @@ defmodule MobilizonWeb.ActivityPub.ObjectView do
def render("event.json", %{event: event}) do def render("event.json", %{event: event}) do
event = %{ event = %{
"type" => "Event", "type" => "Event",
"id" => event.url, "actor" => event["actor"],
"name" => event.title, "id" => event["id"],
"category" => render_one(event.category, ObjectView, "category.json", as: :category), "name" => event["title"],
"content" => event.description, "category" => render_one(event["category"], ObjectView, "category.json", as: :category),
"mediaType" => "text/html", "content" => event["summary"],
"published" => Timex.format!(event.inserted_at, "{ISO:Extended}"), "mediaType" => "text/html"
"updated" => Timex.format!(event.updated_at, "{ISO:Extended}") # "published" => Timex.format!(event.inserted_at, "{ISO:Extended}"),
# "updated" => Timex.format!(event.updated_at, "{ISO:Extended}")
} }
Map.merge(event, Utils.make_json_ld_header()) Map.merge(event, Utils.make_json_ld_header())
@ -21,16 +22,16 @@ defmodule MobilizonWeb.ActivityPub.ObjectView do
def render("comment.json", %{comment: comment}) do def render("comment.json", %{comment: comment}) do
comment = %{ comment = %{
"actor" => comment.actor.url, "actor" => comment["actor"],
"uuid" => comment.uuid, "uuid" => comment["uuid"],
# The activity should have attributedTo, not the comment itself # The activity should have attributedTo, not the comment itself
# "attributedTo" => comment.attributed_to, # "attributedTo" => comment.attributed_to,
"type" => "Note", "type" => "Note",
"id" => comment.url, "id" => comment["id"],
"content" => comment.text, "content" => comment["content"],
"mediaType" => "text/html", "mediaType" => "text/html"
"published" => Timex.format!(comment.inserted_at, "{ISO:Extended}"), # "published" => Timex.format!(comment.inserted_at, "{ISO:Extended}"),
"updated" => Timex.format!(comment.updated_at, "{ISO:Extended}") # "updated" => Timex.format!(comment.updated_at, "{ISO:Extended}")
} }
Map.merge(comment, Utils.make_json_ld_header()) Map.merge(comment, Utils.make_json_ld_header())

View File

@ -19,14 +19,21 @@ defmodule Mobilizon.Service.ActivityPub do
require Logger require Logger
import Mobilizon.Service.ActivityPub.Utils import Mobilizon.Service.ActivityPub.Utils
@doc """
Get recipients for an activity or object
"""
@spec get_recipients(map()) :: list()
def get_recipients(data) do def get_recipients(data) do
(data["to"] || []) ++ (data["cc"] || []) (data["to"] || []) ++ (data["cc"] || [])
end end
def insert(map, local \\ true) when is_map(map) do @doc """
Logger.debug("preparing an activity") Wraps an object into an activity
Logger.debug(inspect(map))
TODO: Rename me
"""
@spec insert(map(), boolean()) :: {:ok, %Activity{}} | {:error, any()}
def insert(map, local \\ true) when is_map(map) do
with map <- lazy_put_activity_defaults(map), with map <- lazy_put_activity_defaults(map),
:ok <- insert_full_object(map, local) do :ok <- insert_full_object(map, local) do
object_id = object_id =
@ -56,10 +63,10 @@ defmodule Mobilizon.Service.ActivityPub do
end end
end end
def fetch_object_from_url(url, :event), do: fetch_event_from_url(url) @doc """
def fetch_object_from_url(url, :note), do: fetch_note_from_url(url) Fetch an object from an URL, from our local database of events and comments, then eventually remote
"""
@spec fetch_object_from_url(String.t()) :: tuple() @spec fetch_object_from_url(String.t()) :: {:ok, %Event{}} | {:ok, %Comment{}} | {:error, any()}
def fetch_object_from_url(url) do def fetch_object_from_url(url) do
with true <- String.starts_with?(url, "http"), with true <- String.starts_with?(url, "http"),
nil <- Events.get_event_by_url(url), nil <- Events.get_event_by_url(url),
@ -95,29 +102,6 @@ defmodule Mobilizon.Service.ActivityPub do
end end
end end
@spec fetch_object_from_url(String.t()) :: tuple()
def fetch_event_from_url(url) do
with nil <- Events.get_event_by_url(url) do
Logger.info("Fetching #{url} via AP")
fetch_object_from_url(url)
else
%Event{} = comment ->
{:ok, comment}
end
end
@spec fetch_object_from_url(String.t()) :: tuple()
def fetch_note_from_url(url) do
with nil <- Events.get_comment_from_url(url) do
Logger.info("Fetching #{url} via AP")
fetch_object_from_url(url)
else
%Comment{} = comment ->
{:ok, comment}
end
end
def create(%{to: to, actor: actor, object: object} = params) do def create(%{to: to, actor: actor, object: object} = params) do
Logger.debug("creating an activity") Logger.debug("creating an activity")
additional = params[:additional] || %{} additional = params[:additional] || %{}
@ -136,8 +120,8 @@ defmodule Mobilizon.Service.ActivityPub do
{:ok, activity} {:ok, activity}
else else
err -> err ->
Logger.debug("Something went wrong") Logger.error("Something went wrong")
Logger.debug(inspect(err)) Logger.error(inspect(err))
end end
end end
@ -216,6 +200,10 @@ defmodule Mobilizon.Service.ActivityPub do
def create_public_activities(%Actor{} = actor) do def create_public_activities(%Actor{} = actor) do
end end
@doc """
Create an actor locally by it's URL (AP ID)
"""
@spec make_actor_from_url(String.t(), boolean()) :: {:ok, %Actor{}} | {:error, any()}
def make_actor_from_url(url, preload \\ false) do def make_actor_from_url(url, preload \\ false) do
with {:ok, data} <- fetch_and_prepare_actor_from_url(url) do with {:ok, data} <- fetch_and_prepare_actor_from_url(url) do
Actors.insert_or_update_actor(data, preload) Actors.insert_or_update_actor(data, preload)
@ -231,6 +219,9 @@ defmodule Mobilizon.Service.ActivityPub do
end end
end end
@doc """
Find an actor in our local database or call Webfinger to find what's its AP ID is and then fetch it
"""
@spec find_or_make_actor_from_nickname(String.t()) :: tuple() @spec find_or_make_actor_from_nickname(String.t()) :: tuple()
def find_or_make_actor_from_nickname(nickname) do def find_or_make_actor_from_nickname(nickname) do
with %Actor{} = actor <- Actors.get_actor_by_name(nickname) do with %Actor{} = actor <- Actors.get_actor_by_name(nickname) do
@ -240,6 +231,10 @@ defmodule Mobilizon.Service.ActivityPub do
end end
end end
@doc """
Create an actor inside our database from username, using Webfinger to find out it's AP ID and then fetch it
"""
@spec make_actor_from_nickname(String.t()) :: {:ok, %Actor{}} | {:error, any()}
def make_actor_from_nickname(nickname) do def make_actor_from_nickname(nickname) do
with {:ok, %{"url" => url}} when not is_nil(url) <- WebFinger.finger(nickname) do with {:ok, %{"url" => url}} when not is_nil(url) <- WebFinger.finger(nickname) do
make_actor_from_url(url) make_actor_from_url(url)
@ -288,12 +283,6 @@ defmodule Mobilizon.Service.ActivityPub do
"content-length": byte_size(json) "content-length": byte_size(json)
}) })
Logger.debug("signature")
Logger.debug(inspect(signature))
Logger.debug("body json")
Logger.debug(inspect(json))
{:ok, response} = {:ok, response} =
HTTPoison.post( HTTPoison.post(
inbox, inbox,
@ -301,19 +290,21 @@ defmodule Mobilizon.Service.ActivityPub do
[{"Content-Type", "application/activity+json"}, {"signature", signature}], [{"Content-Type", "application/activity+json"}, {"signature", signature}],
hackney: [pool: :default] hackney: [pool: :default]
) )
Logger.debug(inspect(response))
end end
def fetch_and_prepare_actor_from_url(url) do @doc """
Fetching a remote actor's informations through it's AP ID
"""
@spec fetch_and_prepare_actor_from_url(String.t()) :: {:ok, struct()} | {:error, atom()} | any()
defp fetch_and_prepare_actor_from_url(url) do
Logger.debug("Fetching and preparing actor from url") Logger.debug("Fetching and preparing actor from url")
with {:ok, %HTTPoison.Response{status_code: 200, body: body}} <- with {:ok, %HTTPoison.Response{status_code: 200, body: body}} <-
HTTPoison.get(url, [Accept: "application/activity+json"], follow_redirect: true), HTTPoison.get(url, [Accept: "application/activity+json"], follow_redirect: true),
{:ok, data} <- Jason.decode(body) do {:ok, data} <- Jason.decode(body) do
user_data_from_user_object(data) actor_data_from_actor_object(data)
else else
# User is gone, probably deleted # Actor is gone, probably deleted
{:ok, %HTTPoison.Response{status_code: 410}} -> {:ok, %HTTPoison.Response{status_code: 410}} ->
{:error, :actor_deleted} {:error, :actor_deleted}
@ -323,8 +314,12 @@ defmodule Mobilizon.Service.ActivityPub do
end end
end end
def user_data_from_user_object(data) do @doc """
user_data = %{ Creating proper actor data struct from AP data
"""
@spec actor_data_from_actor_object(map()) :: {:ok, map()}
def actor_data_from_actor_object(data) when is_map(data) do
actor_data = %{
url: data["id"], url: data["id"],
info: %{ info: %{
"ap_enabled" => true, "ap_enabled" => true,
@ -347,30 +342,22 @@ defmodule Mobilizon.Service.ActivityPub do
type: data["type"] type: data["type"]
} }
Logger.debug("user_data_from_user_object") {:ok, actor_data}
Logger.debug(inspect(user_data))
{:ok, user_data}
end end
@spec fetch_public_activities_for_actor(Actor.t(), integer(), integer()) :: list() @doc """
Return all public activities (events & comments) for an actor
"""
@spec fetch_public_activities_for_actor(Actor.t(), integer(), integer()) :: {list(), integer()}
def fetch_public_activities_for_actor(%Actor{} = actor, page \\ 1, limit \\ 10) do def fetch_public_activities_for_actor(%Actor{} = actor, page \\ 1, limit \\ 10) do
case actor.type do case actor.type do
:Person -> :Person ->
{:ok, events, total} = Events.get_events_for_actor(actor, page, limit) {:ok, events, total} = Events.get_events_for_actor(actor, page, limit)
{:ok, comments, total} = Events.get_comments_for_actor(actor, page, limit) {:ok, comments, total} = Events.get_comments_for_actor(actor, page, limit)
event_activities = event_activities = Enum.map(events, &event_to_activity/1)
Enum.map(events, fn event ->
{:ok, activity} = event_to_activity(event)
activity
end)
comment_activities = comment_activities = Enum.map(comments, &comment_to_activity/1)
Enum.map(comments, fn comment ->
{:ok, activity} = comment_to_activity(comment)
activity
end)
activities = event_activities ++ comment_activities activities = event_activities ++ comment_activities
@ -402,37 +389,36 @@ defmodule Mobilizon.Service.ActivityPub do
end end
end end
@doc """
Create an activity from an event
"""
@spec event_to_activity(%Event{}, boolean()) :: Activity.t()
defp event_to_activity(%Event{} = event, local \\ true) do defp event_to_activity(%Event{} = event, local \\ true) do
activity = %Activity{ %Activity{
type: :Event, recipients: ["https://www.w3.org/ns/activitystreams#Public"],
data: event,
local: local,
actor: event.organizer_actor.url, actor: event.organizer_actor.url,
recipients: ["https://www.w3.org/ns/activitystreams#Public"] data: event |> make_event_data,
local: local
} }
# Notification.create_notifications(activity)
# stream_out(activity)
{:ok, activity}
end end
@doc """
Create an activity from a comment
"""
@spec comment_to_activity(%Comment{}, boolean()) :: Activity.t()
defp comment_to_activity(%Comment{} = comment, local \\ true) do defp comment_to_activity(%Comment{} = comment, local \\ true) do
activity = %Activity{ %Activity{
type: :Comment, recipients: ["https://www.w3.org/ns/activitystreams#Public"],
data: comment,
local: local,
actor: comment.actor.url, actor: comment.actor.url,
recipients: ["https://www.w3.org/ns/activitystreams#Public"] data: comment |> make_comment_data,
local: local
} }
# Notification.create_notifications(activity)
# stream_out(activity)
{:ok, activity}
end end
defp ical_event_to_activity(%ExIcal.Event{} = ical_event, %Actor{} = actor, source) do defp ical_event_to_activity(%ExIcal.Event{} = ical_event, %Actor{} = actor, source) do
# Logger.debug(inspect ical_event) # Logger.debug(inspect ical_event)
# TODO : refactor me ! # TODO : refactor me !
# TODO : also, there should be a form of cache that allows this to be more efficient
category = category =
if is_nil(ical_event.categories) do if is_nil(ical_event.categories) do
nil nil

View File

@ -26,13 +26,16 @@ defmodule Mobilizon.Service.ActivityPub.Transmogrifier do
when not is_nil(in_reply_to) do when not is_nil(in_reply_to) do
in_reply_to_id = in_reply_to_id =
cond do cond do
is_bitstring(in_reply_to) -> # If the inReplyTo is just an AP ID # If the inReplyTo is just an AP ID
is_bitstring(in_reply_to) ->
in_reply_to in_reply_to
is_map(in_reply_to) && is_bitstring(in_reply_to["id"]) -> # If the inReplyTo is a object itself # If the inReplyTo is a object itself
is_map(in_reply_to) && is_bitstring(in_reply_to["id"]) ->
in_reply_to["id"] in_reply_to["id"]
is_list(in_reply_to) && is_bitstring(Enum.at(in_reply_to, 0)) -> # If the inReplyTo is an array # If the inReplyTo is an array
is_list(in_reply_to) && is_bitstring(Enum.at(in_reply_to, 0)) ->
Enum.at(in_reply_to, 0) Enum.at(in_reply_to, 0)
true -> true ->
@ -44,7 +47,7 @@ defmodule Mobilizon.Service.ActivityPub.Transmogrifier do
case fetch_obj_helper(in_reply_to_id) do case fetch_obj_helper(in_reply_to_id) do
{:ok, replied_object} -> {:ok, replied_object} ->
object object
|> Map.put("inReplyTo", replied_object.data["id"]) |> Map.put("inReplyTo", replied_object.url)
e -> e ->
Logger.error("Couldn't fetch #{in_reply_to_id} #{inspect(e)}") Logger.error("Couldn't fetch #{in_reply_to_id} #{inspect(e)}")
@ -128,7 +131,7 @@ defmodule Mobilizon.Service.ActivityPub.Transmogrifier do
# ) do # ) do
# with %User{} = actor <- User.get_or_fetch_by_ap_id(actor), # with %User{} = actor <- User.get_or_fetch_by_ap_id(actor),
# {:ok, object} <- # {:ok, object} <-
# get_obj_helper(object_id) || ActivityPub.fetch_object_from_id(object_id), # fetch_obj_helper(object_id) || ActivityPub.fetch_object_from_id(object_id),
# {:ok, activity, object} <- ActivityPub.like(actor, object, id, false) do # {:ok, activity, object} <- ActivityPub.like(actor, object, id, false) do
# {:ok, activity} # {:ok, activity}
# else # else
@ -136,18 +139,18 @@ defmodule Mobilizon.Service.ActivityPub.Transmogrifier do
# end # end
# end # end
# #
def handle_incoming( # def handle_incoming(
%{"type" => "Announce", "object" => object_id, "actor" => actor, "id" => id} = data # %{"type" => "Announce", "object" => object_id, "actor" => actor, "id" => id} = data
) do # ) do
with {:ok, %Actor{} = actor} <- Actors.get_or_fetch_by_url(actor), # with {:ok, %Actor{} = actor} <- Actors.get_or_fetch_by_url(actor),
{:ok, object} <- # {:ok, object} <-
get_obj_helper(object_id) || ActivityPub.fetch_event_from_url(object_id), # fetch_obj_helper(object_id) || ActivityPub.fetch_object_from_url(object_id),
{:ok, activity, object} <- ActivityPub.announce(actor, object, id, false) do # {:ok, activity, object} <- ActivityPub.announce(actor, object, id, false) do
{:ok, activity} # {:ok, activity}
else # else
_e -> :error # _e -> :error
end # end
end # end
# #
# def handle_incoming( # def handle_incoming(
@ -155,7 +158,7 @@ defmodule Mobilizon.Service.ActivityPub.Transmogrifier do
# data # data
# ) do # ) do
# with %User{ap_id: ^actor_id} = actor <- User.get_by_ap_id(object["id"]) do # with %User{ap_id: ^actor_id} = actor <- User.get_by_ap_id(object["id"]) do
# {:ok, new_user_data} = ActivityPub.user_data_from_user_object(object) # {:ok, new_user_data} = ActivityPub.actor_data_from_actor_object(object)
# #
# banner = new_user_data[:info]["banner"] # banner = new_user_data[:info]["banner"]
# #
@ -194,7 +197,7 @@ defmodule Mobilizon.Service.ActivityPub.Transmogrifier do
# #
# with %User{} = actor <- User.get_or_fetch_by_ap_id(actor), # with %User{} = actor <- User.get_or_fetch_by_ap_id(actor),
# {:ok, object} <- # {:ok, object} <-
# get_obj_helper(object_id) || ActivityPub.fetch_object_from_id(object_id), # fetch_obj_helper(object_id) || ActivityPub.fetch_object_from_id(object_id),
# {:ok, activity} <- ActivityPub.delete(object, false) do # {:ok, activity} <- ActivityPub.delete(object, false) do
# {:ok, activity} # {:ok, activity}
# else # else
@ -208,13 +211,9 @@ defmodule Mobilizon.Service.ActivityPub.Transmogrifier do
# #
def handle_incoming(_), do: :error def handle_incoming(_), do: :error
def get_obj_helper(id) do
if object = Object.get_by_ap_id(id), do: {:ok, object}, else: nil
end
def set_reply_to_uri(%{"inReplyTo" => in_reply_to} = object) do def set_reply_to_uri(%{"inReplyTo" => in_reply_to} = object) do
with false <- String.starts_with?(in_reply_to, "http"), with false <- String.starts_with?(in_reply_to, "http"),
{:ok, %{data: replied_to_object}} <- get_obj_helper(in_reply_to) do {:ok, replied_to_object} <- fetch_obj_helper(in_reply_to) do
Map.put(object, "inReplyTo", replied_to_object["external_url"] || in_reply_to) Map.put(object, "inReplyTo", replied_to_object["external_url"] || in_reply_to)
else else
_e -> object _e -> object
@ -327,7 +326,8 @@ defmodule Mobilizon.Service.ActivityPub.Transmogrifier do
end end
def add_mention_tags(object) do def add_mention_tags(object) do
recipients = object["to"] ++ (object["cc"] || []) recipients =
(object["to"] ++ (object["cc"] || [])) -- ["https://www.w3.org/ns/activitystreams#Public"]
mentions = mentions =
recipients recipients
@ -391,6 +391,9 @@ defmodule Mobilizon.Service.ActivityPub.Transmogrifier do
# |> Map.put("attachment", attachments) # |> Map.put("attachment", attachments)
# end # end
@spec fetch_obj_helper(String.t()) :: {:ok, %Event{}} | {:ok, %Comment{}} | {:error, any()}
def fetch_obj_helper(url) when is_bitstring(url), do: ActivityPub.fetch_object_from_url(url) def fetch_obj_helper(url) when is_bitstring(url), do: ActivityPub.fetch_object_from_url(url)
@spec fetch_obj_helper(map()) :: {:ok, %Event{}} | {:ok, %Comment{}} | {:error, any()}
def fetch_obj_helper(obj) when is_map(obj), do: ActivityPub.fetch_object_from_url(obj["id"]) def fetch_obj_helper(obj) when is_map(obj), do: ActivityPub.fetch_object_from_url(obj["id"])
end end

View File

@ -77,7 +77,17 @@ defmodule Mobilizon.Service.ActivityPub.Utils do
to = to ++ (data["cc"] || []) to = to ++ (data["cc"] || [])
to to
|> Enum.map(fn url -> Actors.get_actor_by_url!(url) end) |> Enum.map(fn url -> Actors.get_actor_by_url(url) end)
|> Enum.map(fn {status, actor} ->
case status do
:ok ->
actor
_ ->
nil
end
end)
|> Enum.map(& &1)
|> Enum.filter(fn actor -> actor && !is_nil(actor.domain) end) |> Enum.filter(fn actor -> actor && !is_nil(actor.domain) end)
end end
@ -110,8 +120,8 @@ defmodule Mobilizon.Service.ActivityPub.Utils do
@doc """ @doc """
Inserts a full object if it is contained in an activity. Inserts a full object if it is contained in an activity.
""" """
def insert_full_object(%{"object" => %{"type" => type} = object_data}, _local) def insert_full_object(%{"object" => %{"type" => type} = object_data}, local)
when is_map(object_data) and type == "Event" do when is_map(object_data) and type == "Event" and not local do
with {:ok, _} <- Events.create_event(object_data) do with {:ok, _} <- Events.create_event(object_data) do
:ok :ok
end end
@ -121,7 +131,7 @@ defmodule Mobilizon.Service.ActivityPub.Utils do
Inserts a full object if it is contained in an activity. Inserts a full object if it is contained in an activity.
""" """
def insert_full_object(%{"object" => %{"type" => type} = object_data}, local) def insert_full_object(%{"object" => %{"type" => type} = object_data}, local)
when is_map(object_data) and type == "Note" do when is_map(object_data) and type == "Note" and not local do
with {:ok, %Actor{id: actor_id}} <- Actors.get_or_fetch_by_url(object_data["actor"]) do with {:ok, %Actor{id: actor_id}} <- Actors.get_or_fetch_by_url(object_data["actor"]) do
data = %{ data = %{
"text" => object_data["content"], "text" => object_data["content"],
@ -164,12 +174,7 @@ defmodule Mobilizon.Service.ActivityPub.Utils do
data data
end end
Logger.info("comment data ready to be inserted")
Logger.info(inspect(data))
with {:ok, comm} <- Events.create_comment(data) do with {:ok, comm} <- Events.create_comment(data) do
Logger.info("comment inserted")
Logger.info(inspect(comm))
:ok :ok
else else
err -> err ->
@ -206,6 +211,49 @@ defmodule Mobilizon.Service.ActivityPub.Utils do
# Repo.one(query) # Repo.one(query)
# end # end
def make_event_data(
%Event{title: title, organizer_actor: actor, uuid: uuid},
to \\ ["https://www.w3.org/ns/activitystreams#Public"]
) do
%{
"type" => "Event",
"to" => to,
"title" => title,
"actor" => actor.url,
"uuid" => uuid,
"id" => "#{MobilizonWeb.Endpoint.url()}/events/#{uuid}"
}
end
@doc """
Make an AP comment object from an existing `Comment` structure.
"""
def make_comment_data(
%Comment{
text: text,
actor: actor,
uuid: uuid,
in_reply_to_comment: reply_to,
event: event
},
to \\ ["https://www.w3.org/ns/activitystreams#Public"]
) do
object = %{
"type" => "Note",
"to" => to,
"content" => text,
"actor" => actor.url,
"uuid" => uuid,
"id" => "#{MobilizonWeb.Endpoint.url()}/comments/#{uuid}"
}
if reply_to do
object |> Map.put("inReplyTo", reply_to.url || event.url)
else
object
end
end
def make_comment_data( def make_comment_data(
actor, actor,
to, to,
@ -344,7 +392,7 @@ defmodule Mobilizon.Service.ActivityPub.Utils do
#### Create-related helpers #### Create-related helpers
def make_create_data(params, additional) do def make_create_data(params, additional \\ %{}) do
published = params.published || make_date() published = params.published || make_date()
%{ %{

View File

@ -44,7 +44,7 @@ defmodule Mobilizon.Service.Federator do
def handle(:incoming_ap_doc, params) do def handle(:incoming_ap_doc, params) do
Logger.info("Handling incoming AP activity") Logger.info("Handling incoming AP activity")
Logger.info(inspect(params)) Logger.debug(inspect(params))
with {:ok, _activity} <- Transmogrifier.handle_incoming(params) do with {:ok, _activity} <- Transmogrifier.handle_incoming(params) do
else else
@ -53,8 +53,8 @@ defmodule Mobilizon.Service.Federator do
_e -> _e ->
# Just drop those for now # Just drop those for now
Logger.info("Unhandled activity") Logger.error("Unhandled activity")
Logger.info(Poison.encode!(params, pretty: 2)) Logger.error(Poison.encode!(params, pretty: 2))
end end
end end

View File

@ -41,20 +41,10 @@ defmodule Mobilizon.Service.HTTPSignatures do
:public_key.verify(sigstring, :sha256, sig, public_key) :public_key.verify(sigstring, :sha256, sig, public_key)
end end
defp prepare_public_key(public_key_code) do
with [public_key_entry] <- :public_key.pem_decode(public_key_code) do
{:ok, :public_key.pem_entry_decode(public_key_entry)}
else
_err ->
{:error, :pem_decode_error}
end
end
def validate_conn(conn) do def validate_conn(conn) do
# TODO: How to get the right key and see if it is actually valid for that request. # TODO: How to get the right key and see if it is actually valid for that request.
# For now, fetch the key for the actor. # For now, fetch the key for the actor.
with {:ok, public_key} <- conn.params["actor"] |> Actor.get_public_key_for_url(), with {:ok, public_key} <- conn.params["actor"] |> Actor.get_public_key_for_url() do
{:ok, public_key} <- prepare_public_key(public_key) do
if validate_conn(conn, public_key) do if validate_conn(conn, public_key) do
true true
else else
@ -62,8 +52,7 @@ defmodule Mobilizon.Service.HTTPSignatures do
# Fetch user anew and try one more time # Fetch user anew and try one more time
with actor_id <- conn.params["actor"], with actor_id <- conn.params["actor"],
{:ok, _actor} <- ActivityPub.make_actor_from_url(actor_id), {:ok, _actor} <- ActivityPub.make_actor_from_url(actor_id),
{:ok, public_key} <- actor_id |> Actor.get_public_key_for_url(), {:ok, public_key} <- actor_id |> Actor.get_public_key_for_url() do
{:ok, public_key} <- prepare_public_key(public_key) do
validate_conn(conn, public_key) validate_conn(conn, public_key)
end end
end end
@ -91,7 +80,7 @@ defmodule Mobilizon.Service.HTTPSignatures do
def sign(%Actor{} = actor, headers) do def sign(%Actor{} = actor, headers) do
with sigstring <- build_signing_string(headers, Map.keys(headers)), with sigstring <- build_signing_string(headers, Map.keys(headers)),
{:ok, key} <- actor.keys |> prepare_public_key(), {:ok, key} <- actor.keys |> Actor.prepare_public_key(),
signature <- sigstring |> :public_key.sign(:sha256, key) |> Base.encode64() do signature <- sigstring |> :public_key.sign(:sha256, key) |> Base.encode64() do
[ [
keyId: actor.url <> "#main-key", keyId: actor.url <> "#main-key",

View File

@ -90,7 +90,8 @@ defmodule Mobilizon.Mixfile do
{:excoveralls, "~> 0.8", only: :test}, {:excoveralls, "~> 0.8", only: :test},
{:ex_doc, "~> 0.16", only: :dev, runtime: false}, {:ex_doc, "~> 0.16", only: :dev, runtime: false},
{:mix_test_watch, "~> 0.5", only: :dev, runtime: false}, {:mix_test_watch, "~> 0.5", only: :dev, runtime: false},
{:ex_unit_notifier, "~> 0.1", only: :test} {:ex_unit_notifier, "~> 0.1", only: :test},
{:dialyxir, "~> 1.0.0-rc.4", only: [:dev], runtime: false}
] ]
end end

View File

@ -2,7 +2,7 @@
"absinthe": {:hex, :absinthe, "1.4.13", "81eb2ff41f1b62cd6e992955f62c22c042d1079b7936c27f5f7c2c806b8fc436", [:mix], [{:dataloader, "~> 1.0.0", [hex: :dataloader, repo: "hexpm", optional: true]}, {:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm"}, "absinthe": {:hex, :absinthe, "1.4.13", "81eb2ff41f1b62cd6e992955f62c22c042d1079b7936c27f5f7c2c806b8fc436", [:mix], [{:dataloader, "~> 1.0.0", [hex: :dataloader, repo: "hexpm", optional: true]}, {:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm"},
"absinthe_ecto": {:hex, :absinthe_ecto, "0.1.3", "420b68129e79fe4571a4838904ba03e282330d335da47729ad52ffd7b8c5fcb1", [:mix], [{:absinthe, "~> 1.3.0 or ~> 1.4.0", [hex: :absinthe, repo: "hexpm", optional: false]}, {:ecto, ">= 0.0.0", [hex: :ecto, repo: "hexpm", optional: false]}], "hexpm"}, "absinthe_ecto": {:hex, :absinthe_ecto, "0.1.3", "420b68129e79fe4571a4838904ba03e282330d335da47729ad52ffd7b8c5fcb1", [:mix], [{:absinthe, "~> 1.3.0 or ~> 1.4.0", [hex: :absinthe, repo: "hexpm", optional: false]}, {:ecto, ">= 0.0.0", [hex: :ecto, repo: "hexpm", optional: false]}], "hexpm"},
"absinthe_phoenix": {:hex, :absinthe_phoenix, "1.4.3", "cea34e7ebbc9a252038c1f1164878ee86bcb108905fe462be77efacda15c1e70", [:mix], [{:absinthe, "~> 1.4.0", [hex: :absinthe, repo: "hexpm", optional: false]}, {:absinthe_plug, "~> 1.4.0", [hex: :absinthe_plug, repo: "hexpm", optional: false]}, {:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.2", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.10.5 or ~> 2.11", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 1.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:poison, "~> 2.0 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm"}, "absinthe_phoenix": {:hex, :absinthe_phoenix, "1.4.3", "cea34e7ebbc9a252038c1f1164878ee86bcb108905fe462be77efacda15c1e70", [:mix], [{:absinthe, "~> 1.4.0", [hex: :absinthe, repo: "hexpm", optional: false]}, {:absinthe_plug, "~> 1.4.0", [hex: :absinthe_plug, repo: "hexpm", optional: false]}, {:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.2", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.10.5 or ~> 2.11", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 1.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:poison, "~> 2.0 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm"},
"absinthe_plug": {:hex, :absinthe_plug, "1.4.5", "f63d52a76c870cd5f11d4bed8f61351ab5c5f572c5eb0479a0137f9f730ba33d", [:mix], [{:absinthe, "~> 1.4.11", [hex: :absinthe, repo: "hexpm", optional: false]}, {:plug, "~> 1.3.2 or ~> 1.4", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, "absinthe_plug": {:hex, :absinthe_plug, "1.4.6", "ac5d2d3d02acf52fda0f151b294017ab06e2ed1c6c15334e06aac82c94e36e08", [:mix], [{:absinthe, "~> 1.4.11", [hex: :absinthe, repo: "hexpm", optional: false]}, {:plug, "~> 1.3.2 or ~> 1.4", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
"arc": {:hex, :arc, "0.11.0", "ac7a0cc03035317b6fef9fe94c97d7d9bd183a3e7ce1606aa0c175cfa8d1ba6d", [:mix], [{:ex_aws, "~> 2.0", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:ex_aws_s3, "~> 2.0", [hex: :ex_aws_s3, repo: "hexpm", optional: true]}, {:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}, {:poison, "~> 2.2 or ~> 3.1", [hex: :poison, repo: "hexpm", optional: true]}, {:sweet_xml, "~> 0.6", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm"}, "arc": {:hex, :arc, "0.11.0", "ac7a0cc03035317b6fef9fe94c97d7d9bd183a3e7ce1606aa0c175cfa8d1ba6d", [:mix], [{:ex_aws, "~> 2.0", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:ex_aws_s3, "~> 2.0", [hex: :ex_aws_s3, repo: "hexpm", optional: true]}, {:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}, {:poison, "~> 2.2 or ~> 3.1", [hex: :poison, repo: "hexpm", optional: true]}, {:sweet_xml, "~> 0.6", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm"},
"arc_ecto": {:hex, :arc_ecto, "0.11.0", "41f19944df3804b49c7bf511dfbeffe09b5b500892ed70d062d891bc891de589", [:mix], [{:arc, "~> 0.11.0", [hex: :arc, repo: "hexpm", optional: false]}, {:ecto, "~> 2.1", [hex: :ecto, repo: "hexpm", optional: false]}], "hexpm"}, "arc_ecto": {:hex, :arc_ecto, "0.11.0", "41f19944df3804b49c7bf511dfbeffe09b5b500892ed70d062d891bc891de589", [:mix], [{:arc, "~> 0.11.0", [hex: :arc, repo: "hexpm", optional: false]}, {:ecto, "~> 2.1", [hex: :ecto, repo: "hexpm", optional: false]}], "hexpm"},
"argon2_elixir": {:hex, :argon2_elixir, "1.3.1", "02a3d55a2670d25df25d75adcef2d74662c72bbc85aba17ca0ea585764b59ef4", [:make, :mix], [{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm"}, "argon2_elixir": {:hex, :argon2_elixir, "1.3.1", "02a3d55a2670d25df25d75adcef2d74662c72bbc85aba17ca0ea585764b59ef4", [:make, :mix], [{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm"},
@ -21,16 +21,18 @@
"dataloader": {:hex, :dataloader, "1.0.4", "7c2345c53c9e5b61420013fc53c8463ba347a938b61f66677eb47d9c4a53ac5d", [:mix], [{:ecto, ">= 0.0.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm"}, "dataloader": {:hex, :dataloader, "1.0.4", "7c2345c53c9e5b61420013fc53c8463ba347a938b61f66677eb47d9c4a53ac5d", [:mix], [{:ecto, ">= 0.0.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm"},
"db_connection": {:hex, :db_connection, "1.1.3", "89b30ca1ef0a3b469b1c779579590688561d586694a3ce8792985d4d7e575a61", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}, {:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, repo: "hexpm", optional: true]}], "hexpm"}, "db_connection": {:hex, :db_connection, "1.1.3", "89b30ca1ef0a3b469b1c779579590688561d586694a3ce8792985d4d7e575a61", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}, {:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, repo: "hexpm", optional: true]}], "hexpm"},
"decimal": {:hex, :decimal, "1.5.0", "b0433a36d0e2430e3d50291b1c65f53c37d56f83665b43d79963684865beab68", [:mix], [], "hexpm"}, "decimal": {:hex, :decimal, "1.5.0", "b0433a36d0e2430e3d50291b1c65f53c37d56f83665b43d79963684865beab68", [:mix], [], "hexpm"},
"dialyxir": {:hex, :dialyxir, "1.0.0-rc.4", "71b42f5ee1b7628f3e3a6565f4617dfb02d127a0499ab3e72750455e986df001", [:mix], [{:erlex, "~> 0.1", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm"},
"earmark": {:hex, :earmark, "1.2.6", "b6da42b3831458d3ecc57314dff3051b080b9b2be88c2e5aa41cd642a5b044ed", [:mix], [], "hexpm"}, "earmark": {:hex, :earmark, "1.2.6", "b6da42b3831458d3ecc57314dff3051b080b9b2be88c2e5aa41cd642a5b044ed", [:mix], [], "hexpm"},
"ecto": {:hex, :ecto, "2.2.11", "4bb8f11718b72ba97a2696f65d247a379e739a0ecabf6a13ad1face79844791c", [:mix], [{:db_connection, "~> 1.1", [hex: :db_connection, repo: "hexpm", optional: true]}, {:decimal, "~> 1.2", [hex: :decimal, repo: "hexpm", optional: false]}, {:mariaex, "~> 0.8.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: true]}, {:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.13.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, repo: "hexpm", optional: true]}], "hexpm"}, "ecto": {:hex, :ecto, "2.2.11", "4bb8f11718b72ba97a2696f65d247a379e739a0ecabf6a13ad1face79844791c", [:mix], [{:db_connection, "~> 1.1", [hex: :db_connection, repo: "hexpm", optional: true]}, {:decimal, "~> 1.2", [hex: :decimal, repo: "hexpm", optional: false]}, {:mariaex, "~> 0.8.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: true]}, {:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.13.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, repo: "hexpm", optional: true]}], "hexpm"},
"ecto_autoslug_field": {:hex, :ecto_autoslug_field, "0.5.1", "c8a160fa6e5e0002740fe1c500bcc27d10bdb073a93715ce8a01b7af8a290777", [:mix], [{:ecto, ">= 2.1.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:slugger, ">= 0.2.0", [hex: :slugger, repo: "hexpm", optional: false]}], "hexpm"}, "ecto_autoslug_field": {:hex, :ecto_autoslug_field, "0.5.1", "c8a160fa6e5e0002740fe1c500bcc27d10bdb073a93715ce8a01b7af8a290777", [:mix], [{:ecto, ">= 2.1.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:slugger, ">= 0.2.0", [hex: :slugger, repo: "hexpm", optional: false]}], "hexpm"},
"ecto_enum": {:hex, :ecto_enum, "1.1.0", "d44fe2ce6e1c0e907e7c3b6456a69e0f1d662348d8b4e2a662ba312223d8ff62", [:mix], [{:ecto, ">= 2.0.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:mariaex, ">= 0.0.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:postgrex, ">= 0.0.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm"}, "ecto_enum": {:hex, :ecto_enum, "1.1.0", "d44fe2ce6e1c0e907e7c3b6456a69e0f1d662348d8b4e2a662ba312223d8ff62", [:mix], [{:ecto, ">= 2.0.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:mariaex, ">= 0.0.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:postgrex, ">= 0.0.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm"},
"elixir_make": {:hex, :elixir_make, "0.4.2", "332c649d08c18bc1ecc73b1befc68c647136de4f340b548844efc796405743bf", [:mix], [], "hexpm"}, "elixir_make": {:hex, :elixir_make, "0.4.2", "332c649d08c18bc1ecc73b1befc68c647136de4f340b548844efc796405743bf", [:mix], [], "hexpm"},
"email_checker": {:hex, :email_checker, "0.1.2", "05b3121c71b69f1ab5df7d8b4844046898bf218031998ef53f20c6b8bfd219e9", [:mix], [{:socket, "~> 0.3.1", [hex: :socket, repo: "hexpm", optional: false]}], "hexpm"}, "email_checker": {:hex, :email_checker, "0.1.2", "05b3121c71b69f1ab5df7d8b4844046898bf218031998ef53f20c6b8bfd219e9", [:mix], [{:socket, "~> 0.3.1", [hex: :socket, repo: "hexpm", optional: false]}], "hexpm"},
"erlex": {:hex, :erlex, "0.1.6", "c01c889363168d3fdd23f4211647d8a34c0f9a21ec726762312e08e083f3d47e", [:mix], [], "hexpm"},
"ex_crypto": {:hex, :ex_crypto, "0.9.0", "e04a831034c4d0a43fb2858f696d6b5ae0f87f07dedca3452912fd3cb5ee3ca2", [:mix], [{:poison, ">= 2.0.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm"}, "ex_crypto": {:hex, :ex_crypto, "0.9.0", "e04a831034c4d0a43fb2858f696d6b5ae0f87f07dedca3452912fd3cb5ee3ca2", [:mix], [{:poison, ">= 2.0.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm"},
"ex_doc": {:hex, :ex_doc, "0.19.1", "519bb9c19526ca51d326c060cb1778d4a9056b190086a8c6c115828eaccea6cf", [:mix], [{:earmark, "~> 1.1", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.7", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm"}, "ex_doc": {:hex, :ex_doc, "0.19.1", "519bb9c19526ca51d326c060cb1778d4a9056b190086a8c6c115828eaccea6cf", [:mix], [{:earmark, "~> 1.1", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.7", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm"},
"ex_ical": {:hex, :ex_ical, "0.2.0", "4b928b554614704016cc0c9ee226eb854da9327a1cc460457621ceacb1ac29a6", [:mix], [{:timex, "~> 3.1", [hex: :timex, repo: "hexpm", optional: false]}], "hexpm"}, "ex_ical": {:hex, :ex_ical, "0.2.0", "4b928b554614704016cc0c9ee226eb854da9327a1cc460457621ceacb1ac29a6", [:mix], [{:timex, "~> 3.1", [hex: :timex, repo: "hexpm", optional: false]}], "hexpm"},
"ex_machina": {:hex, :ex_machina, "2.2.0", "fec496331e04fc2db2a1a24fe317c12c0c4a50d2beb8ebb3531ed1f0d84be0ed", [:mix], [{:ecto, "~> 2.1", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm"}, "ex_machina": {:hex, :ex_machina, "2.2.2", "d84217a6fb7840ff771d2561b8aa6d74a0d8968e4b10ecc0d7e9890dc8fb1c6a", [:mix], [{:ecto, "~> 2.2 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_sql, "~> 3.0", [hex: :ecto_sql, repo: "hexpm", optional: true]}], "hexpm"},
"ex_unit_notifier": {:hex, :ex_unit_notifier, "0.1.4", "36a2dcab829f506e01bf17816590680dd1474407926d43e64c1263e627c364b8", [:mix], [], "hexpm"}, "ex_unit_notifier": {:hex, :ex_unit_notifier, "0.1.4", "36a2dcab829f506e01bf17816590680dd1474407926d43e64c1263e627c364b8", [:mix], [], "hexpm"},
"excoveralls": {:hex, :excoveralls, "0.9.2", "299ea4903be7cb2959af0f919d258af116736ca8d507f86c12ef2184698e21a0", [:mix], [{:hackney, ">= 0.12.0", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm"}, "excoveralls": {:hex, :excoveralls, "0.9.2", "299ea4903be7cb2959af0f919d258af116736ca8d507f86c12ef2184698e21a0", [:mix], [{:hackney, ">= 0.12.0", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm"},
"exgravatar": {:hex, :exgravatar, "2.0.1", "66d595c7d63dd6bbac442c5542a724375ae29144059c6fe093e61553850aace4", [:mix], [], "hexpm"}, "exgravatar": {:hex, :exgravatar, "2.0.1", "66d595c7d63dd6bbac442c5542a724375ae29144059c6fe093e61553850aace4", [:mix], [], "hexpm"},
@ -45,10 +47,10 @@
"guardian_db": {:hex, :guardian_db, "1.1.0", "45ab94206cce38f7443dc27de6dc52966ccbdeff65ca1b1f11a6d8f3daceb556", [:mix], [{:ecto, "~> 2.2", [hex: :ecto, repo: "hexpm", optional: false]}, {:guardian, "~> 1.0", [hex: :guardian, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.13", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm"}, "guardian_db": {:hex, :guardian_db, "1.1.0", "45ab94206cce38f7443dc27de6dc52966ccbdeff65ca1b1f11a6d8f3daceb556", [:mix], [{:ecto, "~> 2.2", [hex: :ecto, repo: "hexpm", optional: false]}, {:guardian, "~> 1.0", [hex: :guardian, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.13", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm"},
"hackney": {:hex, :hackney, "1.12.1", "8bf2d0e11e722e533903fe126e14d6e7e94d9b7983ced595b75f532e04b7fdc7", [:rebar3], [{:certifi, "2.3.1", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "5.1.1", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "1.0.2", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.1", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm"}, "hackney": {:hex, :hackney, "1.12.1", "8bf2d0e11e722e533903fe126e14d6e7e94d9b7983ced595b75f532e04b7fdc7", [:rebar3], [{:certifi, "2.3.1", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "5.1.1", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "1.0.2", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.1", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm"},
"http_sign": {:hex, :http_sign, "0.1.1", "b16edb83aa282892f3271f9a048c155e772bf36e15700ab93901484c55f8dd10", [:mix], [{:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, "http_sign": {:hex, :http_sign, "0.1.1", "b16edb83aa282892f3271f9a048c155e772bf36e15700ab93901484c55f8dd10", [:mix], [{:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
"httpoison": {:hex, :httpoison, "1.3.1", "7ac607311f5f706b44e8b3fab736d0737f2f62a31910ccd9afe7227b43edb7f0", [:mix], [{:hackney, "~> 1.8", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"}, "httpoison": {:hex, :httpoison, "1.4.0", "e0b3c2ad6fa573134e42194d13e925acfa8f89d138bc621ffb7b1989e6d22e73", [:mix], [{:hackney, "~> 1.8", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"},
"icalendar": {:hex, :icalendar, "0.7.0", "6acf28c7e38ad1c4515c59e336878fb78bb646c8aa70d2ee3786ea194711a7b7", [:mix], [{:timex, "~> 3.0", [hex: :timex, repo: "hexpm", optional: false]}], "hexpm"}, "icalendar": {:hex, :icalendar, "0.7.0", "6acf28c7e38ad1c4515c59e336878fb78bb646c8aa70d2ee3786ea194711a7b7", [:mix], [{:timex, "~> 3.0", [hex: :timex, repo: "hexpm", optional: false]}], "hexpm"},
"idna": {:hex, :idna, "5.1.1", "cbc3b2fa1645113267cc59c760bafa64b2ea0334635ef06dbac8801e42f7279c", [:rebar3], [{:unicode_util_compat, "0.3.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm"}, "idna": {:hex, :idna, "5.1.1", "cbc3b2fa1645113267cc59c760bafa64b2ea0334635ef06dbac8801e42f7279c", [:rebar3], [{:unicode_util_compat, "0.3.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm"},
"jason": {:hex, :jason, "1.1.1", "d3ccb840dfb06f2f90a6d335b536dd074db748b3e7f5b11ab61d239506585eb2", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm"}, "jason": {:hex, :jason, "1.1.2", "b03dedea67a99223a2eaf9f1264ce37154564de899fd3d8b9a21b1a6fd64afe7", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm"},
"jose": {:hex, :jose, "1.8.4", "7946d1e5c03a76ac9ef42a6e6a20001d35987afd68c2107bcd8f01a84e75aa73", [:mix, :rebar3], [{:base64url, "~> 0.0.1", [hex: :base64url, repo: "hexpm", optional: false]}], "hexpm"}, "jose": {:hex, :jose, "1.8.4", "7946d1e5c03a76ac9ef42a6e6a20001d35987afd68c2107bcd8f01a84e75aa73", [:mix, :rebar3], [{:base64url, "~> 0.0.1", [hex: :base64url, repo: "hexpm", optional: false]}], "hexpm"},
"json_ld": {:hex, :json_ld, "0.3.0", "92f508ca831b9e4530e3e6c950976fdafcf26323e6817c325b3e1ee78affc4bd", [:mix], [{:jason, "~> 1.1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:rdf, "~> 0.5", [hex: :rdf, repo: "hexpm", optional: false]}], "hexpm"}, "json_ld": {:hex, :json_ld, "0.3.0", "92f508ca831b9e4530e3e6c950976fdafcf26323e6817c325b3e1ee78affc4bd", [:mix], [{:jason, "~> 1.1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:rdf, "~> 0.5", [hex: :rdf, repo: "hexpm", optional: false]}], "hexpm"},
"jsx": {:hex, :jsx, "2.8.3", "a05252d381885240744d955fbe3cf810504eb2567164824e19303ea59eef62cf", [:mix, :rebar3], [], "hexpm"}, "jsx": {:hex, :jsx, "2.8.3", "a05252d381885240744d955fbe3cf810504eb2567164824e19303ea59eef62cf", [:mix, :rebar3], [], "hexpm"},
@ -64,21 +66,22 @@
"nimble_parsec": {:hex, :nimble_parsec, "0.4.0", "ee261bb53214943679422be70f1658fff573c5d0b0a1ecd0f18738944f818efe", [:mix], [], "hexpm"}, "nimble_parsec": {:hex, :nimble_parsec, "0.4.0", "ee261bb53214943679422be70f1658fff573c5d0b0a1ecd0f18738944f818efe", [:mix], [], "hexpm"},
"parse_trans": {:hex, :parse_trans, "3.2.0", "2adfa4daf80c14dc36f522cf190eb5c4ee3e28008fc6394397c16f62a26258c2", [:rebar3], [], "hexpm"}, "parse_trans": {:hex, :parse_trans, "3.2.0", "2adfa4daf80c14dc36f522cf190eb5c4ee3e28008fc6394397c16f62a26258c2", [:rebar3], [], "hexpm"},
"phoenix": {:hex, :phoenix, "1.3.4", "aaa1b55e5523083a877bcbe9886d9ee180bf2c8754905323493c2ac325903dc5", [:mix], [{:cowboy, "~> 1.0", [hex: :cowboy, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 1.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.3.3 or ~> 1.4", [hex: :plug, repo: "hexpm", optional: false]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm"}, "phoenix": {:hex, :phoenix, "1.3.4", "aaa1b55e5523083a877bcbe9886d9ee180bf2c8754905323493c2ac325903dc5", [:mix], [{:cowboy, "~> 1.0", [hex: :cowboy, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 1.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.3.3 or ~> 1.4", [hex: :plug, repo: "hexpm", optional: false]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm"},
"phoenix_ecto": {:hex, :phoenix_ecto, "3.4.0", "91cd39427006fe4b5588d69f0941b9c3d3d8f5e6477c563a08379de7de2b0c58", [:mix], [{:ecto, "~> 2.1", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.9", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, "phoenix_ecto": {:hex, :phoenix_ecto, "3.6.0", "d65dbcedd6af568d8582dcd7da516c3051016bad51f9953e5337fea40bcd8a9d", [:mix], [{:ecto, "~> 2.2", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.9", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
"phoenix_html": {:hex, :phoenix_html, "2.12.0", "1fb3c2e48b4b66d75564d8d63df6d53655469216d6b553e7e14ced2b46f97622", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, "phoenix_html": {:hex, :phoenix_html, "2.12.0", "1fb3c2e48b4b66d75564d8d63df6d53655469216d6b553e7e14ced2b46f97622", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
"phoenix_live_reload": {:hex, :phoenix_live_reload, "1.1.6", "7280f4dd88d38ee07ca70a2974ca12b9bfdbb9fa8137e4692889cf097c1bb232", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.0 or ~> 1.2 or ~> 1.3", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm"}, "phoenix_live_reload": {:hex, :phoenix_live_reload, "1.1.7", "425fff579085f7eacaf009e71940be07338c8d8b78d16e307c50c7d82a381497", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.0 or ~> 1.2 or ~> 1.3 or ~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm"},
"phoenix_pubsub": {:hex, :phoenix_pubsub, "1.1.0", "d55e25ff1ff8ea2f9964638366dfd6e361c52dedfd50019353598d11d4441d14", [:mix], [], "hexpm"}, "phoenix_pubsub": {:hex, :phoenix_pubsub, "1.1.1", "6668d787e602981f24f17a5fbb69cc98f8ab085114ebfac6cc36e10a90c8e93c", [:mix], [], "hexpm"},
"plug": {:hex, :plug, "1.6.4", "35618dd2cc009b69b000f785452f6b370f76d099ece199733fea27bc473f809d", [:mix], [{:cowboy, "~> 1.0.1 or ~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}], "hexpm"}, "plug": {:hex, :plug, "1.7.1", "8516d565fb84a6a8b2ca722e74e2cd25ca0fc9d64f364ec9dbec09d33eb78ccd", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}], "hexpm"},
"plug_crypto": {:hex, :plug_crypto, "1.0.0", "18e49317d3fa343f24620ed22795ec29d4a5e602d52d1513ccea0b07d8ea7d4d", [:mix], [], "hexpm"},
"poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], [], "hexpm"}, "poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], [], "hexpm"},
"poolboy": {:hex, :poolboy, "1.5.1", "6b46163901cfd0a1b43d692657ed9d7e599853b3b21b95ae5ae0a777cf9b6ca8", [:rebar], [], "hexpm"}, "poolboy": {:hex, :poolboy, "1.5.1", "6b46163901cfd0a1b43d692657ed9d7e599853b3b21b95ae5ae0a777cf9b6ca8", [:rebar], [], "hexpm"},
"postgrex": {:hex, :postgrex, "0.13.5", "3d931aba29363e1443da167a4b12f06dcd171103c424de15e5f3fc2ba3e6d9c5", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 1.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: false]}], "hexpm"}, "postgrex": {:hex, :postgrex, "0.13.5", "3d931aba29363e1443da167a4b12f06dcd171103c424de15e5f3fc2ba3e6d9c5", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 1.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: false]}], "hexpm"},
"ranch": {:hex, :ranch, "1.3.2", "e4965a144dc9fbe70e5c077c65e73c57165416a901bd02ea899cfd95aa890986", [:rebar3], [], "hexpm"}, "ranch": {:hex, :ranch, "1.3.2", "e4965a144dc9fbe70e5c077c65e73c57165416a901bd02ea899cfd95aa890986", [:rebar3], [], "hexpm"},
"rdf": {:hex, :rdf, "0.5.1", "b59eaf5df3d77c6c3bb35efdb61f30ba8a1321c03206449ea71fb58670e94f1d", [:mix], [{:decimal, "~> 1.5", [hex: :decimal, repo: "hexpm", optional: false]}], "hexpm"}, "rdf": {:hex, :rdf, "0.5.3", "2990ce6ca55602db9c170e6258bf3fa39b0e4be3d49b1c09c00a740bc387029f", [:mix], [{:decimal, "~> 1.5", [hex: :decimal, repo: "hexpm", optional: false]}], "hexpm"},
"rsa_ex": {:hex, :rsa_ex, "0.4.0", "e28dd7dc5236e156df434af0e4aa822384c8866c928e17b785d4edb7c253b558", [:mix], [], "hexpm"}, "rsa_ex": {:hex, :rsa_ex, "0.4.0", "e28dd7dc5236e156df434af0e4aa822384c8866c928e17b785d4edb7c253b558", [:mix], [], "hexpm"},
"slugger": {:hex, :slugger, "0.3.0", "efc667ab99eee19a48913ccf3d038b1fb9f165fa4fbf093be898b8099e61b6ed", [:mix], [], "hexpm"}, "slugger": {:hex, :slugger, "0.3.0", "efc667ab99eee19a48913ccf3d038b1fb9f165fa4fbf093be898b8099e61b6ed", [:mix], [], "hexpm"},
"socket": {:hex, :socket, "0.3.13", "98a2ab20ce17f95fb512c5cadddba32b57273e0d2dba2d2e5f976c5969d0c632", [:mix], [], "hexpm"}, "socket": {:hex, :socket, "0.3.13", "98a2ab20ce17f95fb512c5cadddba32b57273e0d2dba2d2e5f976c5969d0c632", [:mix], [], "hexpm"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.1", "28a4d65b7f59893bc2c7de786dec1e1555bd742d336043fe644ae956c3497fbe", [:make, :rebar], [], "hexpm"}, "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.1", "28a4d65b7f59893bc2c7de786dec1e1555bd742d336043fe644ae956c3497fbe", [:make, :rebar], [], "hexpm"},
"timex": {:hex, :timex, "3.4.1", "e63fc1a37453035e534c3febfe9b6b9e18583ec7b37fd9c390efdef97397d70b", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 0.1.8 or ~> 0.5", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm"}, "timex": {:hex, :timex, "3.4.2", "d74649c93ad0e12ce5b17cf5e11fbd1fb1b24a3d114643e86dba194b64439547", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 0.1.8 or ~> 0.5", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm"},
"timex_ecto": {:hex, :timex_ecto, "3.3.0", "d5bdef09928e7a60f10a0baa47ce653f29b43d6fee87b30b236b216d0e36b98d", [:mix], [{:ecto, "~> 2.2", [hex: :ecto, repo: "hexpm", optional: false]}, {:timex, "~> 3.1", [hex: :timex, repo: "hexpm", optional: false]}], "hexpm"}, "timex_ecto": {:hex, :timex_ecto, "3.3.0", "d5bdef09928e7a60f10a0baa47ce653f29b43d6fee87b30b236b216d0e36b98d", [:mix], [{:ecto, "~> 2.2", [hex: :ecto, repo: "hexpm", optional: false]}, {:timex, "~> 3.1", [hex: :timex, repo: "hexpm", optional: false]}], "hexpm"},
"tzdata": {:hex, :tzdata, "0.5.19", "7962a3997bf06303b7d1772988ede22260f3dae1bf897408ebdac2b4435f4e6a", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"}, "tzdata": {:hex, :tzdata, "0.5.19", "7962a3997bf06303b7d1772988ede22260f3dae1bf897408ebdac2b4435f4e6a", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"},
"unicode_util_compat": {:hex, :unicode_util_compat, "0.3.1", "a1f612a7b512638634a603c8f401892afbf99b8ce93a45041f8aaca99cadb85e", [:rebar3], [], "hexpm"}, "unicode_util_compat": {:hex, :unicode_util_compat, "0.3.1", "a1f612a7b512638634a603c8f401892afbf99b8ce93a45041f8aaca99cadb85e", [:rebar3], [], "hexpm"},

View File

@ -1,12 +1,11 @@
defmodule Mobilizon.ActorsTest do defmodule Mobilizon.ActorsTest do
use Mobilizon.DataCase use Mobilizon.DataCase
import Mobilizon.Factory
alias Mobilizon.Actors alias Mobilizon.Actors
alias Mobilizon.Actors.{Actor, Member, Follower, User, Bot}
import Mobilizon.Factory
describe "actors" do describe "actors" do
alias Mobilizon.Actors.Actor
@valid_attrs %{ @valid_attrs %{
summary: "some description", summary: "some description",
name: "Bobby Blank", name: "Bobby Blank",
@ -49,24 +48,24 @@ defmodule Mobilizon.ActorsTest do
{:ok, actor: actor} {:ok, actor: actor}
end end
test "list_actors/0 returns all actors", %{actor: actor} do test "list_actors/0 returns all actors", %{actor: %Actor{id: actor_id}} do
actors = Actors.list_actors() assert actor_id == hd(Actors.list_actors()).id
assert actors = [actor]
end end
test "get_actor!/1 returns the actor with given id", %{actor: actor} do test "get_actor!/1 returns the actor with given id", %{actor: %Actor{id: actor_id} = actor} do
actor_fetched = Actors.get_actor!(actor.id) assert actor_id == Actors.get_actor!(actor.id).id
assert actor_fetched = actor
end end
test "get_actor_for_user/1 returns the actor for an user", %{actor: %{user: user} = actor} do test "get_actor_for_user/1 returns the actor for an user", %{
assert actor = Actors.get_actor_for_user(user) actor: %{user: user, id: actor_id} = _actor
} do
assert actor_id == Actors.get_actor_for_user(user).id
end end
test "get_actor_for_user/1 returns the actor for an user with no default actor defined" do test "get_actor_for_user/1 returns the actor for an user with no default actor defined" do
user = insert(:user) user = insert(:user)
actor = insert(:actor, user: user) actor_id = insert(:actor, user: user).id
assert actor = Actors.get_actor_for_user(user) assert actor_id == Actors.get_actor_for_user(user).id
end end
test "get_actor_with_everything!/1 returns the actor with it's organized events", %{ test "get_actor_with_everything!/1 returns the actor with it's organized events", %{
@ -74,19 +73,28 @@ defmodule Mobilizon.ActorsTest do
} do } do
assert Actors.get_actor_with_everything!(actor.id).organized_events == [] assert Actors.get_actor_with_everything!(actor.id).organized_events == []
event = insert(:event, organizer_actor: actor) event = insert(:event, organizer_actor: actor)
events = Actors.get_actor_with_everything!(actor.id).organized_events
assert events = [event] event_found_id =
Actors.get_actor_with_everything!(actor.id).organized_events |> hd |> Map.get(:id)
assert event_found_id == event.id
end end
test "get_actor_by_name/1 returns a local actor", %{actor: actor} do test "get_actor_by_name/1 returns a local actor", %{
actor_found = Actors.get_actor_by_name(actor.preferred_username) actor: %Actor{id: actor_id, preferred_username: preferred_username}
assert actor_found = actor } do
actor_found_id = Actors.get_actor_by_name(preferred_username).id
assert actor_found_id == actor_id
end end
test "get_actor_by_name/1 returns a remote actor" do test "get_actor_by_name/1 returns a remote actor" do
assert {:ok, %Actor{} = actor} = Actors.get_or_fetch_by_url(@remote_account_url) with {:ok,
actor_found = Actors.get_actor_by_name("#{actor.preferred_username}@#{actor.domain}") %Actor{id: actor_id, preferred_username: preferred_username, domain: domain} = _actor} <-
assert actor_found = actor Actors.get_or_fetch_by_url(@remote_account_url),
%Actor{id: actor_found_id} <-
Actors.get_actor_by_name("#{preferred_username}@#{domain}").id do
assert actor_found_id == actor_id
end
end end
test "get_local_actor_by_name_with_everything!/1 returns the local actor with it's organized events", test "get_local_actor_by_name_with_everything!/1 returns the local actor with it's organized events",
@ -98,10 +106,12 @@ defmodule Mobilizon.ActorsTest do
event = insert(:event, organizer_actor: actor) event = insert(:event, organizer_actor: actor)
events = event_found_id =
Actors.get_local_actor_by_name_with_everything(actor.preferred_username).organized_events Actors.get_local_actor_by_name_with_everything(actor.preferred_username).organized_events
|> hd
|> Map.get(:id)
assert events = [event] assert event_found_id == event.id
end end
test "get_actor_by_name_with_everything!/1 returns the local actor with it's organized events", test "get_actor_by_name_with_everything!/1 returns the local actor with it's organized events",
@ -112,8 +122,13 @@ defmodule Mobilizon.ActorsTest do
[] []
event = insert(:event, organizer_actor: actor) event = insert(:event, organizer_actor: actor)
events = Actors.get_actor_by_name_with_everything(actor.preferred_username).organized_events
assert events = [event] event_found_id =
Actors.get_actor_by_name_with_everything(actor.preferred_username).organized_events
|> hd
|> Map.get(:id)
assert event_found_id == event.id
end end
test "get_actor_by_name_with_everything!/1 returns the remote actor with it's organized events" do test "get_actor_by_name_with_everything!/1 returns the remote actor with it's organized events" do
@ -125,75 +140,83 @@ defmodule Mobilizon.ActorsTest do
event = insert(:event, organizer_actor: actor) event = insert(:event, organizer_actor: actor)
events = event_found_id =
Actors.get_actor_by_name_with_everything("#{actor.preferred_username}@#{actor.domain}").organized_events Actors.get_actor_by_name_with_everything("#{actor.preferred_username}@#{actor.domain}").organized_events
|> hd
|> Map.get(:id)
assert events = [event] assert event_found_id == event.id
end end
test "get_or_fetch_by_url/1 returns the local actor for the url", %{ test "get_or_fetch_by_url/1 returns the local actor for the url", %{
actor: actor actor: %Actor{preferred_username: preferred_username} = actor
} do } do
preferred_username = actor.preferred_username with {:ok, %Actor{domain: domain} = actor} <- Actors.get_or_fetch_by_url(actor.url) do
assert preferred_username == actor.preferred_username
assert {:ok, %Actor{preferred_username: preferred_username, domain: nil} = actor_found} = assert is_nil(domain)
Actors.get_or_fetch_by_url(actor.url) end
end end
test "get_or_fetch_by_url/1 returns the remote actor for the url" do test "get_or_fetch_by_url/1 returns the remote actor for the url" do
assert {:ok, with {:ok, %Actor{preferred_username: preferred_username, domain: domain}} <-
%Actor{preferred_username: @remote_account_username, domain: @remote_account_domain}} = Actors.get_or_fetch_by_url!(@remote_account_url) do
Actors.get_or_fetch_by_url(@remote_account_url) assert preferred_username == @remote_account_username
assert domain == @remote_account_domain
end
end end
test "test find_local_by_username/1 returns local actors with similar usernames", %{ test "test find_local_by_username/1 returns local actors with similar usernames", %{
actor: actor actor: actor
} do } do
actor2 = insert(:actor) actor2 = insert(:actor)
actors = Actors.find_local_by_username("thomas") [%Actor{id: actor_found_id} | tail] = Actors.find_local_by_username("thomas")
assert actors = [actor, actor2] %Actor{id: actor2_found_id} = hd(tail)
assert actor_found_id == actor.id
assert actor2_found_id == actor2.id
end end
test "test find_actors_by_username_or_name/1 returns actors with similar usernames", %{ test "test find_actors_by_username_or_name/1 returns actors with similar usernames", %{
actor: actor actor: %Actor{id: actor_id}
} do } do
{:ok, %Actor{} = actor2} = Actors.get_or_fetch_by_url(@remote_account_url) {:ok, %Actor{id: actor2_id}} = Actors.get_or_fetch_by_url(@remote_account_url)
actors = Actors.find_actors_by_username_or_name("t") actors_ids = Actors.find_actors_by_username_or_name("t") |> Enum.map(& &1.id)
assert actors = [actor, actor2] assert MapSet.new(actors_ids) == MapSet.new([actor2_id, actor_id])
end end
test "test find_actors_by_username_or_name/1 returns actors with similar names", %{ test "test find_actors_by_username_or_name/1 returns actors with similar names" do
actor: actor
} do
actors = Actors.find_actors_by_username_or_name("ohno") actors = Actors.find_actors_by_username_or_name("ohno")
assert actors == [] assert actors == []
end end
test "test search/1 returns accounts for search with existing accounts", %{actor: actor} do test "test search/1 returns accounts for search with existing accounts", %{actor: actor} do
assert {:ok, [actor]} = Actors.search("t") with {:ok, [%Actor{id: actor_found_id}]} <- Actors.search("t") do
assert actor_found_id == actor.id
end
end end
test "test search/1 returns accounts for search with non existent accounts" do test "test search/1 returns accounts for search with non existent accounts" do
assert {:ok, []} = Actors.search("nonexistent") assert {:ok, []} == Actors.search("nonexistent")
end end
test "test search/1 returns accounts for search with existing remote accounts" do test "test search/1 returns accounts for search with existing remote accounts" do
assert {:ok, [%Actor{preferred_username: "tcit", domain: "framapiaf.org"}]} = with {:ok, [%Actor{preferred_username: username}]} <- Actors.search("tcit@framapiaf.org") do
Actors.search("tcit@framapiaf.org") assert username == "tcit"
end
end end
test "test search/1 returns accounts for search with non existent remote accounts" do test "test search/1 returns accounts for search with non existent remote accounts" do
assert {:error, _} = Actors.search("tcit@yolo.tld") assert {:error, "No ActivityPub URL found in WebFinger"} == Actors.search("tcit@yolo.tld")
end end
test "test get_public_key_for_url/1 with local actor", %{actor: actor} do test "test get_public_key_for_url/1 with local actor", %{actor: actor} do
assert Actor.get_public_key_for_url(actor.url) == assert Actor.get_public_key_for_url(actor.url) ==
actor.keys |> Mobilizon.Service.ActivityPub.Utils.pem_to_public_key() actor.keys |> Mobilizon.Actors.Actor.prepare_public_key()
end end
@remote_actor_key {:RSAPublicKey, @remote_actor_key {:ok,
20_890_513_599_005_517_665_557_846_902_571_022_168_782_075_040_010_449_365_706_450_877_170_130_373_892_202_874_869_873_999_284_399_697_282_332_064_948_148_602_583_340_776_692_090_472_558_740_998_357_203_838_580_321_412_679_020_304_645_826_371_196_718_081_108_049_114_160_630_664_514_340_729_769_453_281_682_773_898_619_827_376_232_969_899_348_462_205_389_310_883_299_183_817_817_999_273_916_446_620_095_414_233_374_619_948_098_516_821_650_069_821_783_810_210_582_035_456_563_335_930_330_252_551_528_035_801_173_640_288_329_718_719_895_926_309_416_142_129_926_226_047_930_429_802_084_560_488_897_717_417_403_272_782_469_039_131_379_953_278_833_320_195_233_761_955_815_307_522_871_787_339_192_744_439_894_317_730_207_141_881_699_363_391_788_150_650_217_284_777_541_358_381_165_360_697_136_307_663_640_904_621_178_632_289_787, {:RSAPublicKey,
65537} 20_890_513_599_005_517_665_557_846_902_571_022_168_782_075_040_010_449_365_706_450_877_170_130_373_892_202_874_869_873_999_284_399_697_282_332_064_948_148_602_583_340_776_692_090_472_558_740_998_357_203_838_580_321_412_679_020_304_645_826_371_196_718_081_108_049_114_160_630_664_514_340_729_769_453_281_682_773_898_619_827_376_232_969_899_348_462_205_389_310_883_299_183_817_817_999_273_916_446_620_095_414_233_374_619_948_098_516_821_650_069_821_783_810_210_582_035_456_563_335_930_330_252_551_528_035_801_173_640_288_329_718_719_895_926_309_416_142_129_926_226_047_930_429_802_084_560_488_897_717_417_403_272_782_469_039_131_379_953_278_833_320_195_233_761_955_815_307_522_871_787_339_192_744_439_894_317_730_207_141_881_699_363_391_788_150_650_217_284_777_541_358_381_165_360_697_136_307_663_640_904_621_178_632_289_787,
65537}}
test "test get_public_key_for_url/1 with remote actor" do test "test get_public_key_for_url/1 with remote actor" do
assert Actor.get_public_key_for_url(@remote_account_url) == @remote_actor_key assert Actor.get_public_key_for_url(@remote_account_url) == @remote_actor_key
end end
@ -260,18 +283,14 @@ defmodule Mobilizon.ActorsTest do
@update_attrs %{email: "foo@fighters.tld", password: "some updated password", role: 43} @update_attrs %{email: "foo@fighters.tld", password: "some updated password", role: 43}
@invalid_attrs %{email: nil, password_hash: nil, role: nil} @invalid_attrs %{email: nil, password_hash: nil, role: nil}
def user_fixture(attrs \\ %{}) do
insert(:user)
end
test "list_users/0 returns all users" do test "list_users/0 returns all users" do
user = user_fixture() user = insert(:user)
users = Actors.list_users() users = Actors.list_users()
assert users = [user] assert users == [user]
end end
test "get_user!/1 returns the user with given id" do test "get_user!/1 returns the user with given id" do
user = user_fixture() user = insert(:user)
assert user = Actors.get_user!(user.id) assert user = Actors.get_user!(user.id)
end end
@ -288,7 +307,7 @@ defmodule Mobilizon.ActorsTest do
end end
test "update_user/2 with valid data updates the user" do test "update_user/2 with valid data updates the user" do
user = user_fixture() user = insert(:user)
assert {:ok, user} = Actors.update_user(user, @update_attrs) assert {:ok, user} = Actors.update_user(user, @update_attrs)
assert %User{} = user assert %User{} = user
assert user.email == "foo@fighters.tld" assert user.email == "foo@fighters.tld"
@ -296,19 +315,19 @@ defmodule Mobilizon.ActorsTest do
end end
test "update_user/2 with invalid data returns error changeset" do test "update_user/2 with invalid data returns error changeset" do
user = user_fixture() user = insert(:user)
assert {:error, %Ecto.Changeset{}} = Actors.update_user(user, @invalid_attrs) assert {:error, %Ecto.Changeset{}} = Actors.update_user(user, @invalid_attrs)
assert user = Actors.get_user!(user.id) assert user = Actors.get_user!(user.id)
end end
test "delete_user/1 deletes the user" do test "delete_user/1 deletes the user" do
user = user_fixture() user = insert(:user)
assert {:ok, %User{}} = Actors.delete_user(user) assert {:ok, %User{}} = Actors.delete_user(user)
assert_raise Ecto.NoResultsError, fn -> Actors.get_user!(user.id) end assert_raise Ecto.NoResultsError, fn -> Actors.get_user!(user.id) end
end end
test "change_user/1 returns a user changeset" do test "change_user/1 returns a user changeset" do
user = user_fixture() user = insert(:user)
assert %Ecto.Changeset{} = Actors.change_user(user) assert %Ecto.Changeset{} = Actors.change_user(user)
end end
@ -335,7 +354,7 @@ defmodule Mobilizon.ActorsTest do
end end
test "get_user_by_email/1 finds an activated user by it's email" do test "get_user_by_email/1 finds an activated user by it's email" do
{:ok, %Actor{user: %User{email: email} = user} = _actor} = {:ok, %Actor{user: user}} =
Actors.register(%{email: @email, password: @password, username: "yolo"}) Actors.register(%{email: @email, password: @password, username: "yolo"})
{:ok, %User{id: id}} = Actors.get_user_by_email(@email, false) {:ok, %User{id: id}} = Actors.get_user_by_email(@email, false)
@ -393,19 +412,15 @@ defmodule Mobilizon.ActorsTest do
@update_attrs %{source: "some updated source", type: "some updated type"} @update_attrs %{source: "some updated source", type: "some updated type"}
@invalid_attrs %{source: nil, type: nil} @invalid_attrs %{source: nil, type: nil}
def bot_fixture(attrs \\ %{}) do
insert(:bot)
end
test "list_bots/0 returns all bots" do test "list_bots/0 returns all bots" do
bot = bot_fixture() bot = insert(:bot)
bots = Actors.list_bots() bot_found_id = Actors.list_bots() |> hd |> Map.get(:id)
assert bots = [bot] assert bot_found_id == bot.id
end end
test "get_bot!/1 returns the bot with given id" do test "get_bot!/1 returns the bot with given id" do
bot = bot_fixture() %Bot{id: bot_id} = bot = insert(:bot)
assert bot = Actors.get_bot!(bot.id) assert bot_id == Actors.get_bot!(bot.id).id
end end
test "create_bot/1 with valid data creates a bot" do test "create_bot/1 with valid data creates a bot" do
@ -420,31 +435,36 @@ defmodule Mobilizon.ActorsTest do
end end
test "create_bot/1 with invalid data returns error changeset" do test "create_bot/1 with invalid data returns error changeset" do
assert {:error, %Ecto.Changeset{}} = Actors.create_bot(@invalid_attrs) with {:error, %Ecto.Changeset{}} <- Actors.create_bot(@invalid_attrs) do
assert true
else
_ ->
assert false
end
end end
test "update_bot/2 with valid data updates the bot" do test "update_bot/2 with valid data updates the bot" do
bot = bot_fixture() with bot <- insert(:bot),
assert {:ok, bot} = Actors.update_bot(bot, @update_attrs) {:ok, %Bot{source: source, type: type}} <- Actors.update_bot(bot, @update_attrs) do
assert %Bot{} = bot assert source == "some updated source"
assert bot.source == "some updated source" assert type == "some updated type"
assert bot.type == "some updated type" end
end end
test "update_bot/2 with invalid data returns error changeset" do test "update_bot/2 with invalid data returns error changeset" do
bot = bot_fixture() bot = insert(:bot)
assert {:error, %Ecto.Changeset{}} = Actors.update_bot(bot, @invalid_attrs) assert {:error, %Ecto.Changeset{}} = Actors.update_bot(bot, @invalid_attrs)
assert bot = Actors.get_bot!(bot.id) assert bot = Actors.get_bot!(bot.id)
end end
test "delete_bot/1 deletes the bot" do test "delete_bot/1 deletes the bot" do
bot = bot_fixture() bot = insert(:bot)
assert {:ok, %Bot{}} = Actors.delete_bot(bot) assert {:ok, %Bot{}} = Actors.delete_bot(bot)
assert_raise Ecto.NoResultsError, fn -> Actors.get_bot!(bot.id) end assert_raise Ecto.NoResultsError, fn -> Actors.get_bot!(bot.id) end
end end
test "change_bot/1 returns a bot changeset" do test "change_bot/1 returns a bot changeset" do
bot = bot_fixture() bot = insert(:bot)
assert %Ecto.Changeset{} = Actors.change_bot(bot) assert %Ecto.Changeset{} = Actors.change_bot(bot)
end end
end end
@ -463,12 +483,12 @@ defmodule Mobilizon.ActorsTest do
{:ok, actor: actor, target_actor: target_actor} {:ok, actor: actor, target_actor: target_actor}
end end
defp create_follower(%{actor: actor, target_actor: target_actor}) do defp create_test_follower(%{actor: actor, target_actor: target_actor}) do
insert(:follower, actor: actor, target_actor: target_actor) insert(:follower, actor: actor, target_actor: target_actor)
end end
test "get_follower!/1 returns the follower with given id", context do test "get_follower!/1 returns the follower with given id", context do
follower = create_follower(context) follower = create_test_follower(context)
assert follower = Actors.get_follower!(follower.id) assert follower = Actors.get_follower!(follower.id)
end end
@ -493,7 +513,7 @@ defmodule Mobilizon.ActorsTest do
actor: actor, actor: actor,
target_actor: target_actor target_actor: target_actor
} do } do
create_follower(%{actor: actor, target_actor: target_actor}) create_test_follower(%{actor: actor, target_actor: target_actor})
valid_attrs = valid_attrs =
@valid_attrs @valid_attrs
@ -516,7 +536,7 @@ defmodule Mobilizon.ActorsTest do
end end
test "update_follower/2 with valid data updates the follower", context do test "update_follower/2 with valid data updates the follower", context do
follower = create_follower(context) follower = create_test_follower(context)
assert {:ok, follower} = Actors.update_follower(follower, @update_attrs) assert {:ok, follower} = Actors.update_follower(follower, @update_attrs)
assert %Follower{} = follower assert %Follower{} = follower
assert follower.approved == false assert follower.approved == false
@ -524,19 +544,19 @@ defmodule Mobilizon.ActorsTest do
end end
test "update_follower/2 with invalid data returns error changeset", context do test "update_follower/2 with invalid data returns error changeset", context do
follower = create_follower(context) follower = create_test_follower(context)
assert {:error, %Ecto.Changeset{}} = Actors.update_follower(follower, @invalid_attrs) assert {:error, %Ecto.Changeset{}} = Actors.update_follower(follower, @invalid_attrs)
assert follower = Actors.get_follower!(follower.id) assert follower = Actors.get_follower!(follower.id)
end end
test "delete_follower/1 deletes the follower", context do test "delete_follower/1 deletes the follower", context do
follower = create_follower(context) follower = create_test_follower(context)
assert {:ok, %Follower{}} = Actors.delete_follower(follower) assert {:ok, %Follower{}} = Actors.delete_follower(follower)
assert_raise Ecto.NoResultsError, fn -> Actors.get_follower!(follower.id) end assert_raise Ecto.NoResultsError, fn -> Actors.get_follower!(follower.id) end
end end
test "change_follower/1 returns a follower changeset", context do test "change_follower/1 returns a follower changeset", context do
follower = create_follower(context) follower = create_test_follower(context)
assert %Ecto.Changeset{} = Actors.change_follower(follower) assert %Ecto.Changeset{} = Actors.change_follower(follower)
end end
end end
@ -555,12 +575,12 @@ defmodule Mobilizon.ActorsTest do
{:ok, actor: actor, group: group} {:ok, actor: actor, group: group}
end end
defp create_member(%{actor: actor, group: group}) do defp create_test_member(%{actor: actor, group: group}) do
insert(:member, actor: actor, parent: group) insert(:member, actor: actor, parent: group)
end end
test "get_member!/1 returns the member with given id", context do test "get_member!/1 returns the member with given id", context do
member = create_member(context) member = create_test_member(context)
assert member = Actors.get_member!(member.id) assert member = Actors.get_member!(member.id)
end end
@ -585,7 +605,7 @@ defmodule Mobilizon.ActorsTest do
actor: actor, actor: actor,
group: group group: group
} do } do
create_member(%{actor: actor, group: group}) create_test_member(%{actor: actor, group: group})
valid_attrs = valid_attrs =
@valid_attrs @valid_attrs
@ -595,10 +615,7 @@ defmodule Mobilizon.ActorsTest do
assert {:error, _member} = Actors.create_member(valid_attrs) assert {:error, _member} = Actors.create_member(valid_attrs)
end end
test "create_member/1 with invalid data returns error changeset", %{ test "create_member/1 with invalid data returns error changeset" do
actor: actor,
group: group
} do
invalid_attrs = invalid_attrs =
@invalid_attrs @invalid_attrs
|> Map.put(:actor_id, nil) |> Map.put(:actor_id, nil)
@ -608,7 +625,7 @@ defmodule Mobilizon.ActorsTest do
end end
test "update_member/2 with valid data updates the member", context do test "update_member/2 with valid data updates the member", context do
member = create_member(context) member = create_test_member(context)
assert {:ok, member} = Actors.update_member(member, @update_attrs) assert {:ok, member} = Actors.update_member(member, @update_attrs)
assert %Member{} = member assert %Member{} = member
assert member.approved == false assert member.approved == false
@ -623,13 +640,13 @@ defmodule Mobilizon.ActorsTest do
# end # end
test "delete_member/1 deletes the member", context do test "delete_member/1 deletes the member", context do
member = create_member(context) member = create_test_member(context)
assert {:ok, %Member{}} = Actors.delete_member(member) assert {:ok, %Member{}} = Actors.delete_member(member)
assert_raise Ecto.NoResultsError, fn -> Actors.get_member!(member.id) end assert_raise Ecto.NoResultsError, fn -> Actors.get_member!(member.id) end
end end
test "change_member/1 returns a member changeset", context do test "change_member/1 returns a member changeset", context do
member = create_member(context) member = create_test_member(context)
assert %Ecto.Changeset{} = Actors.change_member(member) assert %Ecto.Changeset{} = Actors.change_member(member)
end end
end end

View File

@ -26,16 +26,16 @@ defmodule Mobilizon.AddressesTest do
streetAddress: "some updated streetAddress", streetAddress: "some updated streetAddress",
geom: %Geo.Point{coordinates: {20, -20}, srid: 4326} geom: %Geo.Point{coordinates: {20, -20}, srid: 4326}
} }
@invalid_attrs %{ # @invalid_attrs %{
addressCountry: nil, # addressCountry: nil,
addressLocality: nil, # addressLocality: nil,
addressRegion: nil, # addressRegion: nil,
description: nil, # description: nil,
floor: nil, # floor: nil,
postalCode: nil, # postalCode: nil,
streetAddress: nil, # streetAddress: nil,
geom: nil # geom: nil
} # }
def address_fixture(attrs \\ %{}) do def address_fixture(attrs \\ %{}) do
{:ok, address} = {:ok, address} =

View File

@ -4,7 +4,6 @@ defmodule Mobilizon.EventsTest do
import Mobilizon.Factory import Mobilizon.Factory
alias Mobilizon.Events alias Mobilizon.Events
alias Mobilizon.Actors
@event_valid_attrs %{ @event_valid_attrs %{
begins_on: "2010-04-17 14:00:00.000000Z", begins_on: "2010-04-17 14:00:00.000000Z",
@ -13,22 +12,6 @@ defmodule Mobilizon.EventsTest do
title: "some title" title: "some title"
} }
def actor_fixture do
insert(:actor)
end
def address_fixture do
insert(:address)
end
def event_fixture do
insert(:event)
end
def category_fixture do
insert(:category)
end
describe "events" do describe "events" do
alias Mobilizon.Events.Event alias Mobilizon.Events.Event
@ -78,14 +61,14 @@ defmodule Mobilizon.EventsTest do
assert event2.title == hd(Events.find_events_by_name(" Special ")).title assert event2.title == hd(Events.find_events_by_name(" Special ")).title
assert title = hd(Events.find_events_by_name("")).title assert title == hd(Events.find_events_by_name("")).title
assert title2 = hd(tl(Events.find_events_by_name(""))).title assert title2 == hd(tl(Events.find_events_by_name(""))).title
end end
test "create_event/1 with valid data creates a event" do test "create_event/1 with valid data creates a event" do
actor = actor_fixture() actor = insert(:actor)
category = category_fixture() category = insert(:category)
address = address_fixture() address = insert(:address)
valid_attrs = valid_attrs =
@event_valid_attrs @event_valid_attrs
@ -94,11 +77,15 @@ defmodule Mobilizon.EventsTest do
|> Map.put(:category_id, category.id) |> Map.put(:category_id, category.id)
|> Map.put(:address_id, address.id) |> Map.put(:address_id, address.id)
assert {:ok, %Event{} = event} = Events.create_event(valid_attrs) with {:ok, %Event{} = event} <- Events.create_event(valid_attrs) do
assert event.begins_on == DateTime.from_naive!(~N[2010-04-17 14:00:00.000000Z], "Etc/UTC") assert event.begins_on == DateTime.from_naive!(~N[2010-04-17 14:00:00.000000Z], "Etc/UTC")
assert event.description == "some description" assert event.description == "some description"
assert event.ends_on == DateTime.from_naive!(~N[2010-04-17 14:00:00.000000Z], "Etc/UTC") assert event.ends_on == DateTime.from_naive!(~N[2010-04-17 14:00:00.000000Z], "Etc/UTC")
assert event.title == "some title" assert event.title == "some title"
else
err ->
flunk("Failed to create an event #{inspect(err)}")
end
end end
test "create_event/1 with invalid data returns error changeset" do test "create_event/1 with invalid data returns error changeset" do
@ -135,27 +122,40 @@ defmodule Mobilizon.EventsTest do
test "get_events_for_actor/3", %{actor: actor, event: event} do test "get_events_for_actor/3", %{actor: actor, event: event} do
event1 = insert(:event, organizer_actor: actor) event1 = insert(:event, organizer_actor: actor)
assert {:ok, [event_found, event1_found], 2} = Events.get_events_for_actor(actor, 1, 10)
with {:ok, events_found, 2} <- Events.get_events_for_actor(actor, 1, 10) do
event_ids = MapSet.new(events_found |> Enum.map(& &1.id))
assert event_ids == MapSet.new([event.id, event1.id])
else
err ->
flunk("Failed to get events for an actor #{inspect(err)}")
end
end end
test "get_events_for_actor/3 with limited results", %{actor: actor, event: event} do test "get_events_for_actor/3 with limited results", %{actor: actor, event: event} do
event1 = insert(:event, organizer_actor: actor) event1 = insert(:event, organizer_actor: actor)
assert {:ok, [event_found], 2} = Events.get_events_for_actor(actor, 1, 1)
with {:ok, [%Event{id: event_found_id}], 2} <- Events.get_events_for_actor(actor, 1, 1) do
assert event_found_id in [event.id, event1.id]
else
err ->
flunk("Failed to get limited events for an actor #{inspect(err)}")
end
end end
test "get_event_by_url/1 with valid url", %{actor: actor, event: event} do test "get_event_by_url/1 with valid url", %{event: %Event{id: event_id, url: event_url}} do
assert event = Events.get_event_by_url(event.url) assert event_id == Events.get_event_by_url(event_url).id
end end
test "get_event_by_url/1 with bad url", %{actor: actor, event: event} do test "get_event_by_url/1 with bad url" do
refute event == Events.get_event_by_url("not valid") assert is_nil(Events.get_event_by_url("not valid"))
end end
test "get_event_by_url!/1 with valid url", %{actor: actor, event: event} do test "get_event_by_url!/1 with valid url", %{event: %Event{id: event_id, url: event_url}} do
assert event = Events.get_event_by_url!(event.url) assert event_id == Events.get_event_by_url!(event_url).id
end end
test "get_event_by_url!/1 with bad url", %{actor: actor, event: event} do test "get_event_by_url!/1 with bad url" do
assert_raise Ecto.NoResultsError, fn -> assert_raise Ecto.NoResultsError, fn ->
Events.get_event_by_url!("not valid") Events.get_event_by_url!("not valid")
end end
@ -309,25 +309,35 @@ defmodule Mobilizon.EventsTest do
{:ok, participant: participant, event: event, actor: actor} {:ok, participant: participant, event: event, actor: actor}
end end
test "list_participants/0 returns all participants", %{participant: participant} do test "list_participants/0 returns all participants", %{
assert [%Participant{} = participant] = Events.list_participants() participant: %Participant{event_id: participant_event_id, actor_id: participant_actor_id}
} do
assert [participant_event_id] == Events.list_participants() |> Enum.map(& &1.event_id)
assert [participant_actor_id] == Events.list_participants() |> Enum.map(& &1.actor_id)
end end
test "get_participant!/1 returns the participant for a given event and given actor", %{ test "get_participant!/1 returns the participant for a given event and given actor", %{
event: %Event{id: event_id} = _event, event: %Event{id: event_id},
actor: %Actor{id: actor_id} = _actor actor: %Actor{id: actor_id}
} do } do
assert %Participant{event_id: event_id, actor_id: actor_id} = assert event_id == Events.get_participant!(event_id, actor_id).event_id
_participant = Events.get_participant!(event_id, actor_id) assert actor_id == Events.get_participant!(event_id, actor_id).actor_id
end end
test "create_participant/1 with valid data creates a participant" do test "create_participant/1 with valid data creates a participant" do
actor = actor_fixture() actor = insert(:actor)
event = event_fixture() event = insert(:event)
valid_attrs = Map.put(@valid_attrs, :event_id, event.id) valid_attrs = Map.put(@valid_attrs, :event_id, event.id)
valid_attrs = Map.put(valid_attrs, :actor_id, actor.id) valid_attrs = Map.put(valid_attrs, :actor_id, actor.id)
assert {:ok, %Participant{} = participant} = Events.create_participant(valid_attrs)
assert participant.role == 42 with {:ok, %Participant{} = participant} <- Events.create_participant(valid_attrs) do
assert participant.event_id == event.id
assert participant.actor_id == actor.id
assert participant.role == 42
else
err ->
flunk("Failed to create a participant #{inspect(err)}")
end
end end
test "create_participant/1 with invalid data returns error changeset" do test "create_participant/1 with invalid data returns error changeset" do
@ -337,9 +347,13 @@ defmodule Mobilizon.EventsTest do
test "update_participant/2 with valid data updates the participant", %{ test "update_participant/2 with valid data updates the participant", %{
participant: participant participant: participant
} do } do
assert {:ok, participant} = Events.update_participant(participant, @update_attrs) with {:ok, %Participant{} = participant} <-
assert %Participant{} = participant Events.update_participant(participant, @update_attrs) do
assert participant.role == 43 assert participant.role == 43
else
err ->
flunk("Failed to update a participant #{inspect(err)}")
end
end end
test "update_participant/2 with invalid data returns error changeset", %{ test "update_participant/2 with invalid data returns error changeset", %{
@ -392,7 +406,7 @@ defmodule Mobilizon.EventsTest do
} }
def session_fixture(attrs \\ %{}) do def session_fixture(attrs \\ %{}) do
event = event_fixture() event = insert(:event)
valid_attrs = Map.put(@valid_attrs, :event_id, event.id) valid_attrs = Map.put(@valid_attrs, :event_id, event.id)
{:ok, session} = {:ok, session} =
@ -414,7 +428,7 @@ defmodule Mobilizon.EventsTest do
end end
test "create_session/1 with valid data creates a session" do test "create_session/1 with valid data creates a session" do
event = event_fixture() event = insert(:event)
valid_attrs = Map.put(@valid_attrs, :event_id, event.id) valid_attrs = Map.put(@valid_attrs, :event_id, event.id)
assert {:ok, %Session{} = session} = Events.create_session(valid_attrs) assert {:ok, %Session{} = session} = Events.create_session(valid_attrs)
assert session.audios_urls == "some audios_urls" assert session.audios_urls == "some audios_urls"
@ -475,7 +489,7 @@ defmodule Mobilizon.EventsTest do
@invalid_attrs %{color: nil, description: nil, name: nil} @invalid_attrs %{color: nil, description: nil, name: nil}
def track_fixture(attrs \\ %{}) do def track_fixture(attrs \\ %{}) do
event = event_fixture() event = insert(:event)
valid_attrs = Map.put(@valid_attrs, :event_id, event.id) valid_attrs = Map.put(@valid_attrs, :event_id, event.id)
{:ok, track} = {:ok, track} =
@ -497,7 +511,7 @@ defmodule Mobilizon.EventsTest do
end end
test "create_track/1 with valid data creates a track" do test "create_track/1 with valid data creates a track" do
event = event_fixture() event = insert(:event)
valid_attrs = Map.put(@valid_attrs, :event_id, event.id) valid_attrs = Map.put(@valid_attrs, :event_id, event.id)
assert {:ok, %Track{} = track} = Events.create_track(valid_attrs) assert {:ok, %Track{} = track} = Events.create_track(valid_attrs)
assert track.color == "some color" assert track.color == "some color"
@ -543,28 +557,29 @@ defmodule Mobilizon.EventsTest do
@update_attrs %{text: "some updated text"} @update_attrs %{text: "some updated text"}
@invalid_attrs %{text: nil, url: nil} @invalid_attrs %{text: nil, url: nil}
def comment_fixture() do
insert(:comment)
end
test "list_comments/0 returns all comments" do test "list_comments/0 returns all comments" do
comment = comment_fixture() %Comment{id: comment_id} = insert(:comment)
comments = Events.list_comments() comment_ids = Events.list_comments() |> Enum.map(& &1.id)
assert comments = [comment] assert comment_ids == [comment_id]
end end
test "get_comment!/1 returns the comment with given id" do test "get_comment!/1 returns the comment with given id" do
comment = comment_fixture() %Comment{id: comment_id} = insert(:comment)
comment_fetched = Events.get_comment!(comment.id) comment_fetched = Events.get_comment!(comment_id)
assert comment_fetched = comment assert comment_fetched.id == comment_id
end end
test "create_comment/1 with valid data creates a comment" do test "create_comment/1 with valid data creates a comment" do
actor = actor_fixture() actor = insert(:actor)
comment_data = Map.merge(@valid_attrs, %{actor_id: actor.id}) comment_data = Map.merge(@valid_attrs, %{actor_id: actor.id})
assert {:ok, %Comment{} = comment} = Events.create_comment(comment_data)
assert comment.text == "some text" with {:ok, %Comment{} = comment} <- Events.create_comment(comment_data) do
assert comment.actor_id == actor.id assert comment.text == "some text"
assert comment.actor_id == actor.id
else
err ->
flunk("Failed to create a comment #{inspect(err)}")
end
end end
test "create_comment/1 with invalid data returns error changeset" do test "create_comment/1 with invalid data returns error changeset" do
@ -572,27 +587,31 @@ defmodule Mobilizon.EventsTest do
end end
test "update_comment/2 with valid data updates the comment" do test "update_comment/2 with valid data updates the comment" do
comment = comment_fixture() comment = insert(:comment)
assert {:ok, comment} = Events.update_comment(comment, @update_attrs)
assert %Comment{} = comment with {:ok, %Comment{} = comment} <- Events.update_comment(comment, @update_attrs) do
assert comment.text == "some updated text" assert comment.text == "some updated text"
else
err ->
flunk("Failed to update a comment #{inspect(err)}")
end
end end
test "update_comment/2 with invalid data returns error changeset" do test "update_comment/2 with invalid data returns error changeset" do
comment = comment_fixture() comment = insert(:comment)
assert {:error, %Ecto.Changeset{}} = Events.update_comment(comment, @invalid_attrs) assert {:error, %Ecto.Changeset{}} = Events.update_comment(comment, @invalid_attrs)
comment_fetched = Events.get_comment!(comment.id) comment_fetched = Events.get_comment!(comment.id)
assert comment = comment_fetched assert comment = comment_fetched
end end
test "delete_comment/1 deletes the comment" do test "delete_comment/1 deletes the comment" do
comment = comment_fixture() comment = insert(:comment)
assert {:ok, %Comment{}} = Events.delete_comment(comment) assert {:ok, %Comment{}} = Events.delete_comment(comment)
assert_raise Ecto.NoResultsError, fn -> Events.get_comment!(comment.id) end assert_raise Ecto.NoResultsError, fn -> Events.get_comment!(comment.id) end
end end
test "change_comment/1 returns a comment changeset" do test "change_comment/1 returns a comment changeset" do
comment = comment_fixture() comment = insert(:comment)
assert %Ecto.Changeset{} = Events.change_comment(comment) assert %Ecto.Changeset{} = Events.change_comment(comment)
end end
end end

View File

@ -7,7 +7,6 @@ defmodule Mobilizon.Service.Activitypub.ActivitypubTest do
alias Mobilizon.Actors.Actor alias Mobilizon.Actors.Actor
alias Mobilizon.Actors alias Mobilizon.Actors
alias Mobilizon.Service.ActivityPub alias Mobilizon.Service.ActivityPub
alias Mobilizon.Activity
describe "fetching actor from it's url" do describe "fetching actor from it's url" do
test "returns an actor from nickname" do test "returns an actor from nickname" do
@ -40,12 +39,16 @@ defmodule Mobilizon.Service.Activitypub.ActivitypubTest do
end end
describe "fetching an" do describe "fetching an" do
test "event by url" do test "object by url" do
{:ok, object} = {:ok, object} =
ActivityPub.fetch_event_from_url("https://social.tcit.fr/@tcit/99908779444618462") ActivityPub.fetch_object_from_url(
"https://social.tcit.fr/users/tcit/statuses/99908779444618462"
)
{:ok, object_again} = {:ok, object_again} =
ActivityPub.fetch_event_from_url("https://social.tcit.fr/@tcit/99908779444618462") ActivityPub.fetch_object_from_url(
"https://social.tcit.fr/users/tcit/statuses/99908779444618462"
)
assert object == object_again assert object == object_again
end end

View File

@ -2,10 +2,9 @@ defmodule MobilizonWeb.ActivityPubControllerTest do
use MobilizonWeb.ConnCase use MobilizonWeb.ConnCase
import Mobilizon.Factory import Mobilizon.Factory
alias MobilizonWeb.ActivityPub.{ActorView, ObjectView} alias MobilizonWeb.ActivityPub.{ActorView, ObjectView}
alias Mobilizon.{Repo, Actors, Actors.Actor} alias Mobilizon.Actors
alias Mobilizon.Service.ActivityPub alias Mobilizon.Service.ActivityPub
alias Mobilizon.Activity alias Mobilizon.Service.ActivityPub.Utils
import Logger
describe "/@:preferred_username" do describe "/@:preferred_username" do
test "it returns a json representation of the actor", %{conn: conn} do test "it returns a json representation of the actor", %{conn: conn} do
@ -19,7 +18,6 @@ defmodule MobilizonWeb.ActivityPubControllerTest do
actor = Actors.get_actor!(actor.id) actor = Actors.get_actor!(actor.id)
assert json_response(conn, 200) == ActorView.render("actor.json", %{actor: actor}) assert json_response(conn, 200) == ActorView.render("actor.json", %{actor: actor})
Logger.error(inspect(ActorView.render("actor.json", %{actor: actor})))
end end
end end
@ -32,8 +30,8 @@ defmodule MobilizonWeb.ActivityPubControllerTest do
|> put_req_header("accept", "application/activity+json") |> put_req_header("accept", "application/activity+json")
|> get("/events/#{event.uuid}") |> get("/events/#{event.uuid}")
assert json_response(conn, 200) == ObjectView.render("event.json", %{event: event}) assert json_response(conn, 200) ==
Logger.error(inspect(ObjectView.render("event.json", %{event: event}))) ObjectView.render("event.json", %{event: event |> Utils.make_event_data()})
end end
test "it returns 404 for non-public events", %{conn: conn} do test "it returns 404 for non-public events", %{conn: conn} do
@ -60,7 +58,7 @@ defmodule MobilizonWeb.ActivityPubControllerTest do
assert "ok" == json_response(conn, 200) assert "ok" == json_response(conn, 200)
:timer.sleep(500) :timer.sleep(500)
assert ActivityPub.fetch_object_from_url(data["object"]["id"], :note) assert ActivityPub.fetch_object_from_url(data["object"]["id"])
end end
end end

View File

@ -26,12 +26,13 @@ defmodule MobilizonWeb.NodeInfoControllerTest do
resp = json_response(conn, 200) resp = json_response(conn, 200)
assert resp = %{ assert resp == %{
"metadata" => %{"nodeName" => Keyword.get(@instance, :name)}, "metadata" => %{"nodeName" => Keyword.get(@instance, :name)},
"openRegistrations" => Keyword.get(@instance, :registrations_open), "openRegistrations" => Keyword.get(@instance, :registrations_open),
"protocols" => ["activitypub"], "protocols" => ["activitypub"],
"services" => %{"inbound" => [], "outbound" => []}, "services" => %{"inbound" => [], "outbound" => []},
"software" => %{"name" => "mobilizon", "version" => Keyword.get(@instance, :version)}, "software" => %{"name" => "mobilizon", "version" => Keyword.get(@instance, :version)},
"usage" => %{"localComments" => 0, "localPosts" => 0, "users" => %{"total" => 0}},
"version" => "2.0" "version" => "2.0"
} }
end end

View File

@ -1,9 +1,7 @@
defmodule MobilizonWeb.Resolvers.ActorResolverTest do defmodule MobilizonWeb.Resolvers.ActorResolverTest do
use MobilizonWeb.ConnCase use MobilizonWeb.ConnCase
alias Mobilizon.{Events, Actors} alias Mobilizon.Actors
alias Mobilizon.Actors.Actor
alias MobilizonWeb.AbsintheHelpers alias MobilizonWeb.AbsintheHelpers
import Mobilizon.Factory
@valid_actor_params %{email: "test@test.tld", password: "testest", username: "test"} @valid_actor_params %{email: "test@test.tld", password: "testest", username: "test"}
@non_existent_username "nonexistent" @non_existent_username "nonexistent"

View File

@ -52,7 +52,7 @@ defmodule MobilizonWeb.Resolvers.EventResolverTest do
|> get("/api", AbsintheHelpers.query_skeleton(query, "event")) |> get("/api", AbsintheHelpers.query_skeleton(query, "event"))
assert [%{"message" => "Argument \"uuid\" has invalid value \"bad uuid\"."}] = assert [%{"message" => "Argument \"uuid\" has invalid value \"bad uuid\"."}] =
json_response(res, 400)["errors"] json_response(res, 200)["errors"]
end end
test "list_participants_for_event/3 returns participants for an event", context do test "list_participants_for_event/3 returns participants for an event", context do

View File

@ -1,13 +1,11 @@
defmodule MobilizonWeb.Resolvers.UserResolverTest do defmodule MobilizonWeb.Resolvers.UserResolverTest do
use MobilizonWeb.ConnCase use MobilizonWeb.ConnCase
alias Mobilizon.{Events, Actors} alias Mobilizon.Actors
alias Mobilizon.Actors.{Actor, User}
alias MobilizonWeb.AbsintheHelpers alias MobilizonWeb.AbsintheHelpers
import Mobilizon.Factory import Mobilizon.Factory
use Bamboo.Test use Bamboo.Test
@valid_actor_params %{email: "test@test.tld", password: "testest", username: "test"} @valid_actor_params %{email: "test@test.tld", password: "testest", username: "test"}
@non_existent_username "nonexistent"
describe "User Resolver" do describe "User Resolver" do
test "find_user/3 returns an user by it's id", context do test "find_user/3 returns an user by it's id", context do
@ -161,7 +159,7 @@ defmodule MobilizonWeb.Resolvers.UserResolverTest do
end end
test "test validate_user/3 with invalid token doesn't validate an user", context do test "test validate_user/3 with invalid token doesn't validate an user", context do
{:ok, actor} = Actors.register(@valid_actor_params) {:ok, _actor} = Actors.register(@valid_actor_params)
mutation = """ mutation = """
mutation { mutation {
@ -219,7 +217,7 @@ defmodule MobilizonWeb.Resolvers.UserResolverTest do
test "test resend_confirmation_email/3 with invalid email resends an validation email", test "test resend_confirmation_email/3 with invalid email resends an validation email",
context do context do
{:ok, actor} = Actors.register(@valid_actor_params) {:ok, _actor} = Actors.register(@valid_actor_params)
mutation = """ mutation = """
mutation { mutation {