diff options
| -rw-r--r-- | lib/pleroma/web/activity_pub/relay.ex | 17 | ||||
| -rw-r--r-- | lib/pleroma/web/mastodon_api/mastodon_api.ex | 24 | ||||
| -rw-r--r-- | lib/pleroma/web/mastodon_api/mastodon_api_controller.ex | 44 | ||||
| -rw-r--r-- | lib/pleroma/web/web.ex | 4 | ||||
| -rw-r--r-- | test/web/activity_pub/relay_test.exs | 62 | ||||
| -rw-r--r-- | test/web/mastodon_api/mastodon_api_controller_test.exs | 137 | ||||
| -rw-r--r-- | test/web/mastodon_api/mastodon_api_test.exs | 103 | 
7 files changed, 321 insertions, 70 deletions
diff --git a/lib/pleroma/web/activity_pub/relay.ex b/lib/pleroma/web/activity_pub/relay.ex index 1ebfcdd86..5f18cc64a 100644 --- a/lib/pleroma/web/activity_pub/relay.ex +++ b/lib/pleroma/web/activity_pub/relay.ex @@ -14,6 +14,7 @@ defmodule Pleroma.Web.ActivityPub.Relay do      |> User.get_or_create_service_actor_by_ap_id()    end +  @spec follow(String.t()) :: {:ok, Activity.t()} | {:error, any()}    def follow(target_instance) do      with %User{} = local_user <- get_actor(),           {:ok, %User{} = target_user} <- User.get_or_fetch_by_ap_id(target_instance), @@ -21,12 +22,17 @@ defmodule Pleroma.Web.ActivityPub.Relay do        Logger.info("relay: followed instance: #{target_instance}; id=#{activity.data["id"]}")        {:ok, activity}      else +      {:error, _} = error -> +        Logger.error("error: #{inspect(error)}") +        error +        e ->          Logger.error("error: #{inspect(e)}")          {:error, e}      end    end +  @spec unfollow(String.t()) :: {:ok, Activity.t()} | {:error, any()}    def unfollow(target_instance) do      with %User{} = local_user <- get_actor(),           {:ok, %User{} = target_user} <- User.get_or_fetch_by_ap_id(target_instance), @@ -34,20 +40,27 @@ defmodule Pleroma.Web.ActivityPub.Relay do        Logger.info("relay: unfollowed instance: #{target_instance}: id=#{activity.data["id"]}")        {:ok, activity}      else +      {:error, _} = error -> +        Logger.error("error: #{inspect(error)}") +        error +        e ->          Logger.error("error: #{inspect(e)}")          {:error, e}      end    end +  @spec publish(any()) :: {:ok, Activity.t(), Object.t()} | {:error, any()}    def publish(%Activity{data: %{"type" => "Create"}} = activity) do      with %User{} = user <- get_actor(),           %Object{} = object <- Object.normalize(activity) do        ActivityPub.announce(user, object, nil, true, false)      else -      e -> Logger.error("error: #{inspect(e)}") +      e -> +        Logger.error("error: #{inspect(e)}") +        {:error, inspect(e)}      end    end -  def publish(_), do: nil +  def publish(_), do: {:error, "Not implemented"}  end diff --git a/lib/pleroma/web/mastodon_api/mastodon_api.ex b/lib/pleroma/web/mastodon_api/mastodon_api.ex index 46944dcbc..ac01d1ff3 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api.ex @@ -13,10 +13,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPI do    alias Pleroma.User    alias Pleroma.Web.CommonAPI +  @spec follow(User.t(), User.t(), map) :: {:ok, User.t()} | {:error, String.t()}    def follow(follower, followed, params \\ %{}) do -    options = cast_params(params) -    reblogs = options[:reblogs] -      result =        if not User.following?(follower, followed) do          CommonAPI.follow(follower, followed) @@ -24,19 +22,25 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPI do          {:ok, follower, followed, nil}        end -    with {:ok, follower, followed, _} <- result do -      reblogs -      |> case do -        false -> CommonAPI.hide_reblogs(follower, followed) -        _ -> CommonAPI.show_reblogs(follower, followed) -      end -      |> case do +    with {:ok, follower, _followed, _} <- result do +      options = cast_params(params) + +      case reblogs_visibility(options[:reblogs], result) do          {:ok, follower} -> {:ok, follower}          _ -> {:ok, follower}        end      end    end +  defp reblogs_visibility(false, {:ok, follower, followed, _}) do +    CommonAPI.hide_reblogs(follower, followed) +  end + +  defp reblogs_visibility(_, {:ok, follower, followed, _}) do +    CommonAPI.show_reblogs(follower, followed) +  end + +  @spec get_followers(User.t(), map()) :: list(User.t())    def get_followers(user, params \\ %{}) do      user      |> User.get_followers_query() diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 96e0d82aa..c3c75bd9a 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -537,8 +537,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do        |> put_view(StatusView)        |> try_render("poll.json", %{object: object, for: user})      else -      nil -> render_error(conn, :not_found, "Record not found") -      false -> render_error(conn, :not_found, "Record not found") +      error when is_nil(error) or error == false -> +        render_error(conn, :not_found, "Record not found")      end    end @@ -1693,45 +1693,35 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do          |> String.replace("{{user}}", user)        with {:ok, %{status: 200, body: body}} <- -             HTTP.get( -               url, -               [], -               adapter: [ -                 recv_timeout: timeout, -                 pool: :default -               ] -             ), +             HTTP.get(url, [], adapter: [recv_timeout: timeout, pool: :default]),             {:ok, data} <- Jason.decode(body) do          data =            data            |> Enum.slice(0, limit)            |> Enum.map(fn x -> -            Map.put( -              x, -              "id", -              case User.get_or_fetch(x["acct"]) do -                {:ok, %User{id: id}} -> id -                _ -> 0 -              end -            ) -          end) -          |> Enum.map(fn x -> -            Map.put(x, "avatar", MediaProxy.url(x["avatar"])) -          end) -          |> Enum.map(fn x -> -            Map.put(x, "avatar_static", MediaProxy.url(x["avatar_static"])) +            x +            |> Map.put("id", fetch_suggestion_id(x)) +            |> Map.put("avatar", MediaProxy.url(x["avatar"])) +            |> Map.put("avatar_static", MediaProxy.url(x["avatar_static"]))            end) -        conn -        |> json(data) +        json(conn, data)        else -        e -> Logger.error("Could not retrieve suggestions at fetch #{url}, #{inspect(e)}") +        e -> +          Logger.error("Could not retrieve suggestions at fetch #{url}, #{inspect(e)}")        end      else        json(conn, [])      end    end +  defp fetch_suggestion_id(attrs) do +    case User.get_or_fetch(attrs["acct"]) do +      {:ok, %User{id: id}} -> id +      _ -> 0 +    end +  end +    def status_card(%{assigns: %{user: user}} = conn, %{"id" => status_id}) do      with %Activity{} = activity <- Activity.get_by_id(status_id),           true <- Visibility.visible_for_user?(activity, user) do diff --git a/lib/pleroma/web/web.ex b/lib/pleroma/web/web.ex index b42f6887e..687346554 100644 --- a/lib/pleroma/web/web.ex +++ b/lib/pleroma/web/web.ex @@ -58,10 +58,10 @@ defmodule Pleroma.Web do        rescue          error ->            Logger.error( -            "#{__MODULE__} failed to render #{inspect({view, template})}: #{inspect(error)}" +            "#{__MODULE__} failed to render #{inspect({view, template})}\n" <> +              Exception.format(:error, error, __STACKTRACE__)            ) -          Logger.error(inspect(__STACKTRACE__))            nil        end diff --git a/test/web/activity_pub/relay_test.exs b/test/web/activity_pub/relay_test.exs index 21a63c493..e10b808f7 100644 --- a/test/web/activity_pub/relay_test.exs +++ b/test/web/activity_pub/relay_test.exs @@ -5,11 +5,71 @@  defmodule Pleroma.Web.ActivityPub.RelayTest do    use Pleroma.DataCase +  alias Pleroma.Activity +  alias Pleroma.Object +  alias Pleroma.Web.ActivityPub.ActivityPub    alias Pleroma.Web.ActivityPub.Relay +  import Pleroma.Factory +    test "gets an actor for the relay" do      user = Relay.get_actor() +    assert user.ap_id == "#{Pleroma.Web.Endpoint.url()}/relay" +  end + +  describe "follow/1" do +    test "returns errors when user not found" do +      assert Relay.follow("test-ap-id") == {:error, "Could not fetch by AP id"} +    end + +    test "returns activity" do +      user = insert(:user) +      service_actor = Relay.get_actor() +      assert {:ok, %Activity{} = activity} = Relay.follow(user.ap_id) +      assert activity.actor == "#{Pleroma.Web.Endpoint.url()}/relay" +      assert user.ap_id in activity.recipients +      assert activity.data["type"] == "Follow" +      assert activity.data["actor"] == service_actor.ap_id +      assert activity.data["object"] == user.ap_id +    end +  end + +  describe "unfollow/1" do +    test "returns errors when user not found" do +      assert Relay.unfollow("test-ap-id") == {:error, "Could not fetch by AP id"} +    end + +    test "returns activity" do +      user = insert(:user) +      service_actor = Relay.get_actor() +      ActivityPub.follow(service_actor, user) +      assert {:ok, %Activity{} = activity} = Relay.unfollow(user.ap_id) +      assert activity.actor == "#{Pleroma.Web.Endpoint.url()}/relay" +      assert user.ap_id in activity.recipients +      assert activity.data["type"] == "Undo" +      assert activity.data["actor"] == service_actor.ap_id +      assert activity.data["to"] == [user.ap_id] +    end +  end + +  describe "publish/1" do +    test "returns error when activity not `Create` type" do +      activity = insert(:like_activity) +      assert Relay.publish(activity) == {:error, "Not implemented"} +    end + +    test "returns error when activity not public" do +      activity = insert(:direct_note_activity) +      assert Relay.publish(activity) == {:error, false} +    end -    assert user.ap_id =~ "/relay" +    test "returns announce activity" do +      service_actor = Relay.get_actor() +      note = insert(:note_activity) +      assert {:ok, %Activity{} = activity, %Object{} = obj} = Relay.publish(note) +      assert activity.data["type"] == "Announce" +      assert activity.data["actor"] == service_actor.ap_id +      assert activity.data["object"] == obj.data["id"] +    end    end  end diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index b023d1e4f..2febe8b3a 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -7,6 +7,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do    alias Ecto.Changeset    alias Pleroma.Activity +  alias Pleroma.Config    alias Pleroma.Notification    alias Pleroma.Object    alias Pleroma.Repo @@ -85,11 +86,11 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do    end    test "the public timeline when public is set to false", %{conn: conn} do -    public = Pleroma.Config.get([:instance, :public]) -    Pleroma.Config.put([:instance, :public], false) +    public = Config.get([:instance, :public]) +    Config.put([:instance, :public], false)      on_exit(fn -> -      Pleroma.Config.put([:instance, :public], public) +      Config.put([:instance, :public], public)      end)      assert conn @@ -250,7 +251,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do      end      test "posting a status with OGP link preview", %{conn: conn} do -      Pleroma.Config.put([:rich_media, :enabled], true) +      Config.put([:rich_media, :enabled], true)        conn =          conn @@ -260,7 +261,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do        assert %{"id" => id, "card" => %{"title" => "The Rock"}} = json_response(conn, 200)        assert Activity.get_by_id(id) -      Pleroma.Config.put([:rich_media, :enabled], false) +      Config.put([:rich_media, :enabled], false)      end      test "posting a direct status", %{conn: conn} do @@ -304,7 +305,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do      test "option limit is enforced", %{conn: conn} do        user = insert(:user) -      limit = Pleroma.Config.get([:instance, :poll_limits, :max_options]) +      limit = Config.get([:instance, :poll_limits, :max_options])        conn =          conn @@ -320,7 +321,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do      test "option character limit is enforced", %{conn: conn} do        user = insert(:user) -      limit = Pleroma.Config.get([:instance, :poll_limits, :max_option_chars]) +      limit = Config.get([:instance, :poll_limits, :max_option_chars])        conn =          conn @@ -339,7 +340,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do      test "minimal date limit is enforced", %{conn: conn} do        user = insert(:user) -      limit = Pleroma.Config.get([:instance, :poll_limits, :min_expiration]) +      limit = Config.get([:instance, :poll_limits, :min_expiration])        conn =          conn @@ -358,7 +359,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do      test "maximum date limit is enforced", %{conn: conn} do        user = insert(:user) -      limit = Pleroma.Config.get([:instance, :poll_limits, :max_expiration]) +      limit = Config.get([:instance, :poll_limits, :max_expiration])        conn =          conn @@ -1633,12 +1634,12 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do    describe "media upload" do      setup do -      upload_config = Pleroma.Config.get([Pleroma.Upload]) -      proxy_config = Pleroma.Config.get([:media_proxy]) +      upload_config = Config.get([Pleroma.Upload]) +      proxy_config = Config.get([:media_proxy])        on_exit(fn -> -        Pleroma.Config.put([Pleroma.Upload], upload_config) -        Pleroma.Config.put([:media_proxy], proxy_config) +        Config.put([Pleroma.Upload], upload_config) +        Config.put([:media_proxy], proxy_config)        end)        user = insert(:user) @@ -2581,7 +2582,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do      conn = get(conn, "/api/v1/instance")      assert result = json_response(conn, 200) -    email = Pleroma.Config.get([:instance, :email]) +    email = Config.get([:instance, :email])      # Note: not checking for "max_toot_chars" since it's optional      assert %{               "uri" => _, @@ -2666,7 +2667,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do    describe "pinned statuses" do      setup do -      Pleroma.Config.put([:instance, :max_pinned_statuses], 1) +      Config.put([:instance, :max_pinned_statuses], 1)        user = insert(:user)        {:ok, activity} = CommonAPI.post(user, %{"status" => "HI!!!"}) @@ -2766,10 +2767,10 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do    describe "cards" do      setup do -      Pleroma.Config.put([:rich_media, :enabled], true) +      Config.put([:rich_media, :enabled], true)        on_exit(fn -> -        Pleroma.Config.put([:rich_media, :enabled], false) +        Config.put([:rich_media, :enabled], false)        end)        user = insert(:user) @@ -2997,7 +2998,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do        reporter: reporter,        target_user: target_user      } do -      max_size = Pleroma.Config.get([:instance, :max_report_comment_size], 1000) +      max_size = Config.get([:instance, :max_report_comment_size], 1000)        comment = String.pad_trailing("a", max_size + 1, "a")        error = %{"error" => "Comment must be up to #{max_size} characters"} @@ -3126,15 +3127,15 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do        conn: conn,        path: path      } do -      is_public = Pleroma.Config.get([:instance, :public]) -      Pleroma.Config.put([:instance, :public], false) +      is_public = Config.get([:instance, :public]) +      Config.put([:instance, :public], false)        conn = get(conn, path)        assert conn.status == 302        assert redirected_to(conn) == "/web/login" -      Pleroma.Config.put([:instance, :public], is_public) +      Config.put([:instance, :public], is_public)      end      test "does not redirect logged in users to the login page", %{conn: conn, path: path} do @@ -3876,8 +3877,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do        token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id)        email = Pleroma.Emails.UserEmail.password_reset_email(user, token_record.token) -      notify_email = Pleroma.Config.get([:instance, :notify_email]) -      instance_name = Pleroma.Config.get([:instance, :name]) +      notify_email = Config.get([:instance, :notify_email]) +      instance_name = Config.get([:instance, :name])        assert_email_sent(          from: {instance_name, notify_email}, @@ -3909,11 +3910,11 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do    describe "POST /api/v1/pleroma/accounts/confirmation_resend" do      setup do -      setting = Pleroma.Config.get([:instance, :account_activation_required]) +      setting = Config.get([:instance, :account_activation_required])        unless setting do -        Pleroma.Config.put([:instance, :account_activation_required], true) -        on_exit(fn -> Pleroma.Config.put([:instance, :account_activation_required], setting) end) +        Config.put([:instance, :account_activation_required], true) +        on_exit(fn -> Config.put([:instance, :account_activation_required], setting) end)        end        user = insert(:user) @@ -3937,8 +3938,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do        |> json_response(:no_content)        email = Pleroma.Emails.UserEmail.account_confirmation_email(user) -      notify_email = Pleroma.Config.get([:instance, :notify_email]) -      instance_name = Pleroma.Config.get([:instance, :name]) +      notify_email = Config.get([:instance, :notify_email]) +      instance_name = Config.get([:instance, :name])        assert_email_sent(          from: {instance_name, notify_email}, @@ -3947,4 +3948,84 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do        )      end    end + +  describe "GET /api/v1/suggestions" do +    setup do +      user = insert(:user) +      other_user = insert(:user) +      config = Config.get(:suggestions) +      on_exit(fn -> Config.put(:suggestions, config) end) + +      host = Config.get([Pleroma.Web.Endpoint, :url, :host]) +      url500 = "http://test500?#{host}&#{user.nickname}" +      url200 = "http://test200?#{host}&#{user.nickname}" + +      mock(fn +        %{method: :get, url: ^url500} -> +          %Tesla.Env{status: 500, body: "bad request"} + +        %{method: :get, url: ^url200} -> +          %Tesla.Env{ +            status: 200, +            body: +              ~s([{"acct":"yj455","avatar":"https://social.heldscal.la/avatar/201.jpeg","avatar_static":"https://social.heldscal.la/avatar/s/201.jpeg"}, {"acct":"#{ +                other_user.ap_id +              }","avatar":"https://social.heldscal.la/avatar/202.jpeg","avatar_static":"https://social.heldscal.la/avatar/s/202.jpeg"}]) +          } +      end) + +      [user: user, other_user: other_user] +    end + +    test "returns empty result when suggestions disabled", %{conn: conn, user: user} do +      Config.put([:suggestions, :enabled], false) + +      res = +        conn +        |> assign(:user, user) +        |> get("/api/v1/suggestions") +        |> json_response(200) + +      assert res == [] +    end + +    test "returns error", %{conn: conn, user: user} do +      Config.put([:suggestions, :enabled], true) +      Config.put([:suggestions, :third_party_engine], "http://test500?{{host}}&{{user}}") + +      res = +        conn +        |> assign(:user, user) +        |> get("/api/v1/suggestions") +        |> json_response(500) + +      assert res == "Something went wrong" +    end + +    test "returns suggestions", %{conn: conn, user: user, other_user: other_user} do +      Config.put([:suggestions, :enabled], true) +      Config.put([:suggestions, :third_party_engine], "http://test200?{{host}}&{{user}}") + +      res = +        conn +        |> assign(:user, user) +        |> get("/api/v1/suggestions") +        |> json_response(200) + +      assert res == [ +               %{ +                 "acct" => "yj455", +                 "avatar" => "https://social.heldscal.la/avatar/201.jpeg", +                 "avatar_static" => "https://social.heldscal.la/avatar/s/201.jpeg", +                 "id" => 0 +               }, +               %{ +                 "acct" => other_user.ap_id, +                 "avatar" => "https://social.heldscal.la/avatar/202.jpeg", +                 "avatar_static" => "https://social.heldscal.la/avatar/s/202.jpeg", +                 "id" => other_user.id +               } +             ] +    end +  end  end diff --git a/test/web/mastodon_api/mastodon_api_test.exs b/test/web/mastodon_api/mastodon_api_test.exs new file mode 100644 index 000000000..b4c0427c9 --- /dev/null +++ b/test/web/mastodon_api/mastodon_api_test.exs @@ -0,0 +1,103 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.MastodonAPITest do +  use Pleroma.Web.ConnCase + +  alias Pleroma.Notification +  alias Pleroma.ScheduledActivity +  alias Pleroma.User +  alias Pleroma.Web.MastodonAPI.MastodonAPI +  alias Pleroma.Web.TwitterAPI.TwitterAPI + +  import Pleroma.Factory + +  describe "follow/3" do +    test "returns error when user deactivated" do +      follower = insert(:user) +      user = insert(:user, local: true, info: %{deactivated: true}) +      {:error, error} = MastodonAPI.follow(follower, user) +      assert error == "Could not follow user: You are deactivated." +    end + +    test "following for user" do +      follower = insert(:user) +      user = insert(:user) +      {:ok, follower} = MastodonAPI.follow(follower, user) +      assert User.following?(follower, user) +    end + +    test "returns ok if user already followed" do +      follower = insert(:user) +      user = insert(:user) +      {:ok, follower} = User.follow(follower, user) +      {:ok, follower} = MastodonAPI.follow(follower, refresh_record(user)) +      assert User.following?(follower, user) +    end +  end + +  describe "get_followers/2" do +    test "returns user followers" do +      follower1_user = insert(:user) +      follower2_user = insert(:user) +      user = insert(:user) +      {:ok, _follower1_user} = User.follow(follower1_user, user) +      {:ok, follower2_user} = User.follow(follower2_user, user) + +      assert MastodonAPI.get_followers(user, %{"limit" => 1}) == [follower2_user] +    end +  end + +  describe "get_friends/2" do +    test "returns user friends" do +      user = insert(:user) +      followed_one = insert(:user) +      followed_two = insert(:user) +      followed_three = insert(:user) + +      {:ok, user} = User.follow(user, followed_one) +      {:ok, user} = User.follow(user, followed_two) +      {:ok, user} = User.follow(user, followed_three) +      res = MastodonAPI.get_friends(user) + +      assert length(res) == 3 +      assert Enum.member?(res, refresh_record(followed_three)) +      assert Enum.member?(res, refresh_record(followed_two)) +      assert Enum.member?(res, refresh_record(followed_one)) +    end +  end + +  describe "get_notifications/2" do +    test "returns notifications for user" do +      user = insert(:user) +      subscriber = insert(:user) + +      User.subscribe(subscriber, user) + +      {:ok, status} = TwitterAPI.create_status(user, %{"status" => "Akariiiin"}) +      {:ok, status1} = TwitterAPI.create_status(user, %{"status" => "Magi"}) +      {:ok, [notification]} = Notification.create_notifications(status) +      {:ok, [notification1]} = Notification.create_notifications(status1) +      res = MastodonAPI.get_notifications(subscriber) + +      assert Enum.member?(Enum.map(res, & &1.id), notification.id) +      assert Enum.member?(Enum.map(res, & &1.id), notification1.id) +    end +  end + +  describe "get_scheduled_activities/2" do +    test "returns user scheduled activities" do +      user = insert(:user) + +      today = +        NaiveDateTime.utc_now() +        |> NaiveDateTime.add(:timer.minutes(6), :millisecond) +        |> NaiveDateTime.to_iso8601() + +      attrs = %{params: %{}, scheduled_at: today} +      {:ok, schedule} = ScheduledActivity.create(user, attrs) +      assert MastodonAPI.get_scheduled_activities(user) == [schedule] +    end +  end +end  | 
