diff options
author | Alex Gleason <alex@alexgleason.me> | 2022-01-03 13:40:19 -0600 |
---|---|---|
committer | Alex Gleason <alex@alexgleason.me> | 2022-01-03 13:40:19 -0600 |
commit | 4081be0001332bac402faec7565807df088b0117 (patch) | |
tree | a5305404e9bb31b3613dbc9631d36f8827be81c2 /test | |
parent | d00f74e036735c1c238f661076f2925b39daa6ac (diff) | |
parent | a3094b64df344622f1bcb03091ef2ff4dce6da82 (diff) | |
download | pleroma-matrix.tar.gz |
Merge remote-tracking branch 'origin/develop' into matrixmatrix
Diffstat (limited to 'test')
481 files changed, 20582 insertions, 16551 deletions
diff --git a/test/activity_expiration_test.exs b/test/activity_expiration_test.exs deleted file mode 100644 index f86d79826..000000000 --- a/test/activity_expiration_test.exs +++ /dev/null @@ -1,55 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.ActivityExpirationTest do - use Pleroma.DataCase - alias Pleroma.ActivityExpiration - import Pleroma.Factory - - setup do: clear_config([ActivityExpiration, :enabled]) - - test "finds activities due to be deleted only" do - activity = insert(:note_activity) - - expiration_due = - insert(:expiration_in_the_past, %{activity_id: activity.id}) |> Repo.preload(:activity) - - activity2 = insert(:note_activity) - insert(:expiration_in_the_future, %{activity_id: activity2.id}) - - expirations = ActivityExpiration.due_expirations() - - assert length(expirations) == 1 - assert hd(expirations) == expiration_due - end - - test "denies expirations that don't live long enough" do - activity = insert(:note_activity) - now = NaiveDateTime.utc_now() - assert {:error, _} = ActivityExpiration.create(activity, now) - end - - test "deletes an expiration activity" do - Pleroma.Config.put([ActivityExpiration, :enabled], true) - activity = insert(:note_activity) - - naive_datetime = - NaiveDateTime.add( - NaiveDateTime.utc_now(), - -:timer.minutes(2), - :millisecond - ) - - expiration = - insert( - :expiration_in_the_past, - %{activity_id: activity.id, scheduled_at: naive_datetime} - ) - - Pleroma.Workers.Cron.PurgeExpiredActivitiesWorker.perform(%Oban.Job{}) - - refute Pleroma.Repo.get(Pleroma.Activity, activity.id) - refute Pleroma.Repo.get(Pleroma.ActivityExpiration, expiration.id) - end -end diff --git a/test/config/deprecation_warnings_test.exs b/test/config/deprecation_warnings_test.exs deleted file mode 100644 index 555661a71..000000000 --- a/test/config/deprecation_warnings_test.exs +++ /dev/null @@ -1,65 +0,0 @@ -defmodule Pleroma.Config.DeprecationWarningsTest do - use ExUnit.Case, async: true - use Pleroma.Tests.Helpers - - import ExUnit.CaptureLog - - test "check_old_mrf_config/0" do - clear_config([:instance, :rewrite_policy], Pleroma.Web.ActivityPub.MRF.NoOpPolicy) - clear_config([:instance, :mrf_transparency], true) - clear_config([:instance, :mrf_transparency_exclusions], []) - - assert capture_log(fn -> Pleroma.Config.DeprecationWarnings.check_old_mrf_config() end) =~ - """ - !!!DEPRECATION WARNING!!! - Your config is using old namespaces for MRF configuration. They should work for now, but you are advised to change to new namespaces to prevent possible issues later: - - * `config :pleroma, :instance, rewrite_policy` is now `config :pleroma, :mrf, policies` - * `config :pleroma, :instance, mrf_transparency` is now `config :pleroma, :mrf, transparency` - * `config :pleroma, :instance, mrf_transparency_exclusions` is now `config :pleroma, :mrf, transparency_exclusions` - """ - end - - test "move_namespace_and_warn/2" do - old_group1 = [:group, :key] - old_group2 = [:group, :key2] - old_group3 = [:group, :key3] - - new_group1 = [:another_group, :key4] - new_group2 = [:another_group, :key5] - new_group3 = [:another_group, :key6] - - clear_config(old_group1, 1) - clear_config(old_group2, 2) - clear_config(old_group3, 3) - - clear_config(new_group1) - clear_config(new_group2) - clear_config(new_group3) - - config_map = [ - {old_group1, new_group1, "\n error :key"}, - {old_group2, new_group2, "\n error :key2"}, - {old_group3, new_group3, "\n error :key3"} - ] - - assert capture_log(fn -> - Pleroma.Config.DeprecationWarnings.move_namespace_and_warn( - config_map, - "Warning preface" - ) - end) =~ "Warning preface\n error :key\n error :key2\n error :key3" - - assert Pleroma.Config.get(new_group1) == 1 - assert Pleroma.Config.get(new_group2) == 2 - assert Pleroma.Config.get(new_group3) == 3 - end - - test "check_media_proxy_whitelist_config/0" do - clear_config([:media_proxy, :whitelist], ["https://example.com", "example2.com"]) - - assert capture_log(fn -> - Pleroma.Config.DeprecationWarnings.check_media_proxy_whitelist_config() - end) =~ "Your config is using old format (only domain) for MediaProxy whitelist option" - end -end diff --git a/test/config/emoji.txt b/test/config/emoji.txt new file mode 100644 index 000000000..14dd0c332 --- /dev/null +++ b/test/config/emoji.txt @@ -0,0 +1 @@ +external_emoji, https://example.com/emoji.png diff --git a/test/credo/check/consistency/file_location.ex b/test/credo/check/consistency/file_location.ex new file mode 100644 index 000000000..abc55fffc --- /dev/null +++ b/test/credo/check/consistency/file_location.ex @@ -0,0 +1,166 @@ +# Pleroma: A lightweight social networking server +# Originally taken from +# https://github.com/VeryBigThings/elixir_common/blob/master/lib/vbt/credo/check/consistency/file_location.ex +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Credo.Check.Consistency.FileLocation do + @moduledoc false + + # credo:disable-for-this-file Credo.Check.Readability.Specs + + @checkdoc """ + File location should follow the namespace hierarchy of the module it defines. + + Examples: + + - `lib/my_system.ex` should define the `MySystem` module + - `lib/my_system/accounts.ex` should define the `MySystem.Accounts` module + """ + @explanation [warning: @checkdoc] + + @special_namespaces [ + "controllers", + "views", + "operations", + "channels" + ] + + # `use Credo.Check` required that module attributes are already defined, so we need + # to place these attributes + # before use/alias expressions. + # credo:disable-for-next-line VBT.Credo.Check.Consistency.ModuleLayout + use Credo.Check, category: :warning, base_priority: :high + + alias Credo.Code + + def run(source_file, params \\ []) do + case verify(source_file, params) do + :ok -> + [] + + {:error, module, expected_file} -> + error(IssueMeta.for(source_file, params), module, expected_file) + end + end + + defp verify(source_file, params) do + source_file.filename + |> Path.relative_to_cwd() + |> verify(Code.ast(source_file), params) + end + + @doc false + def verify(relative_path, ast, params) do + if verify_path?(relative_path, params), + do: ast |> main_module() |> verify_module(relative_path, params), + else: :ok + end + + defp verify_path?(relative_path, params) do + case Path.split(relative_path) do + ["lib" | _] -> not exclude?(relative_path, params) + ["test", "support" | _] -> false + ["test", "test_helper.exs"] -> false + ["test" | _] -> not exclude?(relative_path, params) + _ -> false + end + end + + defp exclude?(relative_path, params) do + params + |> Keyword.get(:exclude, []) + |> Enum.any?(&String.starts_with?(relative_path, &1)) + end + + defp main_module(ast) do + {_ast, modules} = Macro.prewalk(ast, [], &traverse/2) + Enum.at(modules, -1) + end + + defp traverse({:defmodule, _meta, args}, modules) do + [{:__aliases__, _, name_parts}, _module_body] = args + {args, [Module.concat(name_parts) | modules]} + end + + defp traverse(ast, state), do: {ast, state} + + # empty file - shouldn't really happen, but we'll let it through + defp verify_module(nil, _relative_path, _params), do: :ok + + defp verify_module(main_module, relative_path, params) do + parsed_path = parsed_path(relative_path, params) + + expected_file = + expected_file_base(parsed_path.root, main_module) <> + Path.extname(parsed_path.allowed) + + cond do + expected_file == parsed_path.allowed -> + :ok + + special_namespaces?(parsed_path.allowed) -> + original_path = parsed_path.allowed + + namespace = + Enum.find(@special_namespaces, original_path, fn namespace -> + String.contains?(original_path, namespace) + end) + + allowed = String.replace(original_path, "/" <> namespace, "") + + if expected_file == allowed, + do: :ok, + else: {:error, main_module, expected_file} + + true -> + {:error, main_module, expected_file} + end + end + + defp special_namespaces?(path), do: String.contains?(path, @special_namespaces) + + defp parsed_path(relative_path, params) do + parts = Path.split(relative_path) + + allowed = + Keyword.get(params, :ignore_folder_namespace, %{}) + |> Stream.flat_map(fn {root, folders} -> Enum.map(folders, &Path.join([root, &1])) end) + |> Stream.map(&Path.split/1) + |> Enum.find(&List.starts_with?(parts, &1)) + |> case do + nil -> + relative_path + + ignore_parts -> + Stream.drop(ignore_parts, -1) + |> Enum.concat(Stream.drop(parts, length(ignore_parts))) + |> Path.join() + end + + %{root: hd(parts), allowed: allowed} + end + + defp expected_file_base(root_folder, module) do + {parent_namespace, module_name} = module |> Module.split() |> Enum.split(-1) + + relative_path = + if parent_namespace == [], + do: "", + else: parent_namespace |> Module.concat() |> Macro.underscore() + + file_name = module_name |> Module.concat() |> Macro.underscore() + + Path.join([root_folder, relative_path, file_name]) + end + + defp error(issue_meta, module, expected_file) do + format_issue(issue_meta, + message: + "Mismatch between file name and main module #{inspect(module)}. " <> + "Expected file path to be #{expected_file}. " <> + "Either move the file or rename the module.", + line_no: 1 + ) + end +end diff --git a/test/earmark_renderer_test.exs b/test/earmark_renderer_test.exs deleted file mode 100644 index 220d97d16..000000000 --- a/test/earmark_renderer_test.exs +++ /dev/null @@ -1,79 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.EarmarkRendererTest do - use ExUnit.Case - - test "Paragraph" do - code = ~s[Hello\n\nWorld!] - result = Earmark.as_html!(code, %Earmark.Options{renderer: Pleroma.EarmarkRenderer}) - assert result == "<p>Hello</p><p>World!</p>" - end - - test "raw HTML" do - code = ~s[<a href="http://example.org/">OwO</a><!-- what's this?-->] - result = Earmark.as_html!(code, %Earmark.Options{renderer: Pleroma.EarmarkRenderer}) - assert result == "<p>#{code}</p>" - end - - test "rulers" do - code = ~s[before\n\n-----\n\nafter] - result = Earmark.as_html!(code, %Earmark.Options{renderer: Pleroma.EarmarkRenderer}) - assert result == "<p>before</p><hr /><p>after</p>" - end - - test "headings" do - code = ~s[# h1\n## h2\n### h3\n] - result = Earmark.as_html!(code, %Earmark.Options{renderer: Pleroma.EarmarkRenderer}) - assert result == ~s[<h1>h1</h1><h2>h2</h2><h3>h3</h3>] - end - - test "blockquote" do - code = ~s[> whoms't are you quoting?] - result = Earmark.as_html!(code, %Earmark.Options{renderer: Pleroma.EarmarkRenderer}) - assert result == "<blockquote><p>whoms’t are you quoting?</p></blockquote>" - end - - test "code" do - code = ~s[`mix`] - result = Earmark.as_html!(code, %Earmark.Options{renderer: Pleroma.EarmarkRenderer}) - assert result == ~s[<p><code class="inline">mix</code></p>] - - code = ~s[``mix``] - result = Earmark.as_html!(code, %Earmark.Options{renderer: Pleroma.EarmarkRenderer}) - assert result == ~s[<p><code class="inline">mix</code></p>] - - code = ~s[```\nputs "Hello World"\n```] - result = Earmark.as_html!(code, %Earmark.Options{renderer: Pleroma.EarmarkRenderer}) - assert result == ~s[<pre><code class="">puts "Hello World"</code></pre>] - end - - test "lists" do - code = ~s[- one\n- two\n- three\n- four] - result = Earmark.as_html!(code, %Earmark.Options{renderer: Pleroma.EarmarkRenderer}) - assert result == "<ul><li>one</li><li>two</li><li>three</li><li>four</li></ul>" - - code = ~s[1. one\n2. two\n3. three\n4. four\n] - result = Earmark.as_html!(code, %Earmark.Options{renderer: Pleroma.EarmarkRenderer}) - assert result == "<ol><li>one</li><li>two</li><li>three</li><li>four</li></ol>" - end - - test "delegated renderers" do - code = ~s[a<br/>b] - result = Earmark.as_html!(code, %Earmark.Options{renderer: Pleroma.EarmarkRenderer}) - assert result == "<p>#{code}</p>" - - code = ~s[*aaaa~*] - result = Earmark.as_html!(code, %Earmark.Options{renderer: Pleroma.EarmarkRenderer}) - assert result == ~s[<p><em>aaaa~</em></p>] - - code = ~s[**aaaa~**] - result = Earmark.as_html!(code, %Earmark.Options{renderer: Pleroma.EarmarkRenderer}) - assert result == ~s[<p><strong>aaaa~</strong></p>] - - # strikethrought - code = ~s[<del>aaaa~</del>] - result = Earmark.as_html!(code, %Earmark.Options{renderer: Pleroma.EarmarkRenderer}) - assert result == ~s[<p><del>aaaa~</del></p>] - end -end diff --git a/test/filter_test.exs b/test/filter_test.exs deleted file mode 100644 index 0a5c4426a..000000000 --- a/test/filter_test.exs +++ /dev/null @@ -1,158 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.FilterTest do - use Pleroma.DataCase - - import Pleroma.Factory - - alias Pleroma.Filter - alias Pleroma.Repo - - describe "creating filters" do - test "creating one filter" do - user = insert(:user) - - query = %Filter{ - user_id: user.id, - filter_id: 42, - phrase: "knights", - context: ["home"] - } - - {:ok, %Filter{} = filter} = Filter.create(query) - result = Filter.get(filter.filter_id, user) - assert query.phrase == result.phrase - end - - test "creating one filter without a pre-defined filter_id" do - user = insert(:user) - - query = %Filter{ - user_id: user.id, - phrase: "knights", - context: ["home"] - } - - {:ok, %Filter{} = filter} = Filter.create(query) - # Should start at 1 - assert filter.filter_id == 1 - end - - test "creating additional filters uses previous highest filter_id + 1" do - user = insert(:user) - - query_one = %Filter{ - user_id: user.id, - filter_id: 42, - phrase: "knights", - context: ["home"] - } - - {:ok, %Filter{} = filter_one} = Filter.create(query_one) - - query_two = %Filter{ - user_id: user.id, - # No filter_id - phrase: "who", - context: ["home"] - } - - {:ok, %Filter{} = filter_two} = Filter.create(query_two) - assert filter_two.filter_id == filter_one.filter_id + 1 - end - - test "filter_id is unique per user" do - user_one = insert(:user) - user_two = insert(:user) - - query_one = %Filter{ - user_id: user_one.id, - phrase: "knights", - context: ["home"] - } - - {:ok, %Filter{} = filter_one} = Filter.create(query_one) - - query_two = %Filter{ - user_id: user_two.id, - phrase: "who", - context: ["home"] - } - - {:ok, %Filter{} = filter_two} = Filter.create(query_two) - - assert filter_one.filter_id == 1 - assert filter_two.filter_id == 1 - - result_one = Filter.get(filter_one.filter_id, user_one) - assert result_one.phrase == filter_one.phrase - - result_two = Filter.get(filter_two.filter_id, user_two) - assert result_two.phrase == filter_two.phrase - end - end - - test "deleting a filter" do - user = insert(:user) - - query = %Filter{ - user_id: user.id, - filter_id: 0, - phrase: "knights", - context: ["home"] - } - - {:ok, _filter} = Filter.create(query) - {:ok, filter} = Filter.delete(query) - assert is_nil(Repo.get(Filter, filter.filter_id)) - end - - test "getting all filters by an user" do - user = insert(:user) - - query_one = %Filter{ - user_id: user.id, - filter_id: 1, - phrase: "knights", - context: ["home"] - } - - query_two = %Filter{ - user_id: user.id, - filter_id: 2, - phrase: "who", - context: ["home"] - } - - {:ok, filter_one} = Filter.create(query_one) - {:ok, filter_two} = Filter.create(query_two) - filters = Filter.get_filters(user) - assert filter_one in filters - assert filter_two in filters - end - - test "updating a filter" do - user = insert(:user) - - query_one = %Filter{ - user_id: user.id, - filter_id: 1, - phrase: "knights", - context: ["home"] - } - - changes = %{ - phrase: "who", - context: ["home", "timeline"] - } - - {:ok, filter_one} = Filter.create(query_one) - {:ok, filter_two} = Filter.update(filter_one, changes) - - assert filter_one != filter_two - assert filter_two.phrase == changes.phrase - assert filter_two.context == changes.context - end -end diff --git a/test/fixtures/23211.atom b/test/fixtures/23211.atom deleted file mode 100644 index d5d111baa..000000000 --- a/test/fixtures/23211.atom +++ /dev/null @@ -1,508 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:georss="http://www.georss.org/georss" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:media="http://purl.org/syndication/atommedia" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:statusnet="http://status.net/schema/api/1/"> - <generator uri="https://gnu.io/social" version="1.0.2-dev">GNU social</generator> - <id>https://social.heldscal.la/api/statuses/user_timeline/23211.atom</id> - <title>lambadalambda timeline</title> - <subtitle>Updates from lambadalambda on social.heldscal.la!</subtitle> - <logo>https://social.heldscal.la/avatar/23211-96-20170416114255.jpeg</logo> - <updated>2017-05-02T14:59:30+00:00</updated> -<author> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://social.heldscal.la/user/23211</uri> - <name>lambadalambda</name> - <summary>Call me Deacon Blues.</summary> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/lambadalambda"/> - <link rel="avatar" type="image/jpeg" media:width="236" media:height="236" href="https://social.heldscal.la/avatar/23211-original-20170416114255.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/23211-96-20170416114255.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="48" media:height="48" href="https://social.heldscal.la/avatar/23211-48-20170416114255.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="24" media:height="24" href="https://social.heldscal.la/avatar/23211-24-20170416114257.jpeg"/> - <poco:preferredUsername>lambadalambda</poco:preferredUsername> - <poco:displayName>Constance Variable</poco:displayName> - <poco:note>Call me Deacon Blues.</poco:note> - <poco:address> - <poco:formatted>Berlin</poco:formatted> - </poco:address> - <poco:urls> - <poco:type>homepage</poco:type> - <poco:value>https://heldscal.la</poco:value> - <poco:primary>true</poco:primary> - </poco:urls> - <followers url="https://social.heldscal.la/lambadalambda/subscribers"></followers> - <statusnet:profile_info local_id="23211"></statusnet:profile_info> -</author> - <link href="https://social.heldscal.la/lambadalambda" rel="alternate" type="text/html"/> - <link href="https://social.heldscal.la/main/sup" rel="http://api.friendfeed.com/2008/03#sup" type="application/json"/> - <link href="https://social.heldscal.la/api/statuses/user_timeline/23211.atom?max_id=2012090" rel="next" type="application/atom+xml"/> - <link href="https://social.heldscal.la/main/push/hub" rel="hub"/> - <link href="https://social.heldscal.la/main/salmon/user/23211" rel="salmon"/> - <link href="https://social.heldscal.la/main/salmon/user/23211" rel="http://salmon-protocol.org/ns/salmon-replies"/> - <link href="https://social.heldscal.la/main/salmon/user/23211" rel="http://salmon-protocol.org/ns/salmon-mention"/> - <link href="https://social.heldscal.la/api/statuses/user_timeline/23211.atom" rel="self" type="application/atom+xml"/> -<entry> - <id>tag:social.heldscal.la,2017-05-02:fave:23211:comment:2015260:2017-05-02T14:45:47+00:00</id> - <title>Favorite</title> - <content type="html">lambadalambda favorited something by godemperorofdune: <p><span class="h-card"><a href="https://social.heldscal.la/lambadalambda" class="u-url mention">@<span>lambadalambda</span></a></span> It's because your instance decided to be trap! lol.</p></content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2015305"/> - <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb> - <published>2017-05-02T14:45:47+00:00</published> - <updated>2017-05-02T14:45:47+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>tag:pawoo.net,2017-05-02:objectId=7397439:objectType=Status</id> - <title>New comment by godemperorofdune</title> - <content type="html"><p><span class="h-card"><a href="https://social.heldscal.la/lambadalambda" class="u-url mention">@<span>lambadalambda</span></a></span> It's because your instance decided to be trap! lol.</p></content> - <link rel="alternate" type="text/html" href="https://pawoo.net/users/God_Emperor_of_Dune/updates/2090090"/> - <status_net notice_id="2015260"></status_net> - </activity:object> - <thr:in-reply-to ref="tag:pawoo.net,2017-05-02:objectId=7397439:objectType=Status" href="https://pawoo.net/users/God_Emperor_of_Dune/updates/2090090"></thr:in-reply-to> - <link rel="related" href="https://pawoo.net/users/God_Emperor_of_Dune/updates/2090090"/> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1035308"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/1035308" local_id="1035308" ref="tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=136e244b26cdf1e9">tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=136e244b26cdf1e9</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2015305.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2015305.atom"/> - <statusnet:notice_info local_id="2015305" source="unknown"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:social.heldscal.la,2017-05-02:noticeId=2015221:objectType=note</id> - <title>New note by lambadalambda</title> - <content type="html">Some script thinks I'm a mastodon server.<br /> <br /> [info] GET /api/v1/timelines/public<br /> [debug] Processing with Fallback.RedirectController.redirector/2<br /> Parameters: %{&quot;limit&quot; =&gt; &quot;40&quot;, &quot;path&quot; =&gt; [&quot;api&quot;, &quot;v1&quot;, &quot;timelines&quot;, &quot;public&quot;]}<br /> Pipelines: []</content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2015221"/> - <status_net notice_id="2015221"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-05-02T14:40:50+00:00</published> - <updated>2017-05-02T14:40:50+00:00</updated> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1035308"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/1035308" local_id="1035308" ref="tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=136e244b26cdf1e9">tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=136e244b26cdf1e9</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2015221.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2015221.atom"/> - <statusnet:notice_info local_id="2015221" source="Pleroma FE"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>tag:social.heldscal.la,2017-05-02:noticeId=2014759:objectType=comment</id> - <title>New comment by lambadalambda</title> - <content type="html">@<a href="https://mstdn.io/users/mattskala" class="h-card u-url p-nickname mention" title="Matthew Skala">mattskala</a> You and @<a href="https://mastodon.social/users/kevinmarks" class="h-card u-url p-nickname mention" title="Kevin Marks">kevinmarks</a> are not wrong, but my comment was a suggestion to users and admins: Don't use big instances, don't run big instances. Also, it's a secondary advice to devs: Don't add features that encourage big instances.</content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2014759"/> - <status_net notice_id="2014759"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-05-02T14:11:54+00:00</published> - <updated>2017-05-02T14:11:54+00:00</updated> - <thr:in-reply-to ref="tag:mstdn.io,2017-05-02:objectId=1316931:objectType=Status" href="https://mstdn.io/users/mattskala/updates/35698"></thr:in-reply-to> - <link rel="related" href="https://mstdn.io/users/mattskala/updates/35698"/> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1031866"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/1031866" local_id="1031866" ref="tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=58e32e013ab6487d">tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=58e32e013ab6487d</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.social/users/kevinmarks"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mstdn.io/users/mattskala"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2014759.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2014759.atom"/> - <statusnet:notice_info local_id="2014759" source="Pleroma FE"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>tag:social.heldscal.la,2017-05-02:noticeId=2014684:objectType=comment</id> - <title>New comment by lambadalambda</title> - <content type="html">@<a href="https://mastodon.social/users/Ronkjeffries" class="h-card u-url p-nickname mention" title="Ron K Jeffries social">ronkjeffries</a> @<a href="https://xoxo.zone/users/KevinMarks" class="h-card u-url p-nickname mention" title="Kevin Marks ">kevinmarks</a> Usually people who run their own private instance just look at the timelines of other servers, follow a seed population and then go from there. This is of course hard on Mastodon, because it doesn't have a publicly visible timeline.</content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2014684"/> - <status_net notice_id="2014684"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-05-02T14:07:00+00:00</published> - <updated>2017-05-02T14:07:00+00:00</updated> - <thr:in-reply-to ref="tag:mastodon.social,2017-05-02:objectId=4883853:objectType=Status" href="https://mastodon.social/users/Ronkjeffries/updates/2221244"></thr:in-reply-to> - <link rel="related" href="https://mastodon.social/users/Ronkjeffries/updates/2221244"/> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1031866"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/1031866" local_id="1031866" ref="tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=58e32e013ab6487d">tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=58e32e013ab6487d</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://xoxo.zone/users/KevinMarks"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.social/users/Ronkjeffries"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2014684.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2014684.atom"/> - <statusnet:notice_info local_id="2014684" source="Pleroma FE"></statusnet:notice_info> -</entry> -<entry> - <id>tag:social.heldscal.la,2017-05-02:fave:23211:comment:2014584:2017-05-02T14:05:32+00:00</id> - <title>Favorite</title> - <content type="html">lambadalambda favorited something by mattskala: <p><span class="h-card"><a href="https://social.heldscal.la/lambadalambda" class="u-url mention">@<span>lambadalambda</span></a></span> It's reasonable to expect that instance sizes will obey a power-law distribution because that's what such things in nature nearly always do. If so, there'll necessarily be a few instances much larger than the others; even if most are small, the network both socially and technically has to be able to deal with the existence of the few large ones.</p></content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2014659"/> - <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb> - <published>2017-05-02T14:05:32+00:00</published> - <updated>2017-05-02T14:05:32+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>tag:mstdn.io,2017-05-02:objectId=1316931:objectType=Status</id> - <title>New comment by mattskala</title> - <content type="html"><p><span class="h-card"><a href="https://social.heldscal.la/lambadalambda" class="u-url mention">@<span>lambadalambda</span></a></span> It's reasonable to expect that instance sizes will obey a power-law distribution because that's what such things in nature nearly always do. If so, there'll necessarily be a few instances much larger than the others; even if most are small, the network both socially and technically has to be able to deal with the existence of the few large ones.</p></content> - <link rel="alternate" type="text/html" href="https://mstdn.io/users/mattskala/updates/35698"/> - <status_net notice_id="2014584"></status_net> - </activity:object> - <thr:in-reply-to ref="tag:mstdn.io,2017-05-02:objectId=1316931:objectType=Status" href="https://mstdn.io/users/mattskala/updates/35698"></thr:in-reply-to> - <link rel="related" href="https://mstdn.io/users/mattskala/updates/35698"/> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1031866"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/1031866" local_id="1031866" ref="tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=58e32e013ab6487d">tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=58e32e013ab6487d</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2014659.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2014659.atom"/> - <statusnet:notice_info local_id="2014659" source="unknown"></statusnet:notice_info> -</entry> -<entry> - <id>tag:social.heldscal.la,2017-05-02:fave:23211:comment:2013568:2017-05-02T14:05:29+00:00</id> - <title>Favorite</title> - <content type="html">lambadalambda favorited something by kevinmarks: <p><span class="h-card"><a href="https://social.heldscal.la/lambadalambda" class="u-url mention">@<span>lambadalambda</span></a></span> except instance populations will be power law distributed, and the problems for the tummlers are worse at scale</p></content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2014657"/> - <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb> - <published>2017-05-02T14:05:29+00:00</published> - <updated>2017-05-02T14:05:29+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>tag:xoxo.zone,2017-05-02:objectId=89478:objectType=Status</id> - <title>New comment by kevinmarks</title> - <content type="html"><p><span class="h-card"><a href="https://social.heldscal.la/lambadalambda" class="u-url mention">@<span>lambadalambda</span></a></span> except instance populations will be power law distributed, and the problems for the tummlers are worse at scale</p></content> - <link rel="alternate" type="text/html" href="https://xoxo.zone/users/KevinMarks/updates/1749"/> - <status_net notice_id="2013568"></status_net> - </activity:object> - <thr:in-reply-to ref="tag:xoxo.zone,2017-05-02:objectId=89478:objectType=Status" href="https://xoxo.zone/users/KevinMarks/updates/1749"></thr:in-reply-to> - <link rel="related" href="https://xoxo.zone/users/KevinMarks/updates/1749"/> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1031866"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/1031866" local_id="1031866" ref="tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=58e32e013ab6487d">tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=58e32e013ab6487d</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2014657.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2014657.atom"/> - <statusnet:notice_info local_id="2014657" source="unknown"></statusnet:notice_info> -</entry> -<entry> - <id>tag:social.heldscal.la,2017-05-02:fave:23211:comment:2014060:2017-05-02T13:34:32+00:00</id> - <title>Favorite</title> - <content type="html">lambadalambda favorited something by gcarregues: <p><span class="h-card"><a href="https://social.heldscal.la/lambadalambda" class="u-url mention">@<span>lambadalambda</span></a></span> Oh purée ! Ma vie en images !</p></content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2014147"/> - <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb> - <published>2017-05-02T13:34:32+00:00</published> - <updated>2017-05-02T13:34:32+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>tag:mastodon.etalab.gouv.fr,2017-05-02:objectId=55287:objectType=Status</id> - <title>New comment by gcarregues</title> - <content type="html"><p><span class="h-card"><a href="https://social.heldscal.la/lambadalambda" class="u-url mention">@<span>lambadalambda</span></a></span> Oh purée ! Ma vie en images !</p></content> - <link rel="alternate" type="text/html" href="https://mastodon.etalab.gouv.fr/users/gcarregues/updates/4370"/> - <status_net notice_id="2014060"></status_net> - </activity:object> - <thr:in-reply-to ref="tag:mastodon.etalab.gouv.fr,2017-05-02:objectId=55287:objectType=Status" href="https://mastodon.etalab.gouv.fr/users/gcarregues/updates/4370"></thr:in-reply-to> - <link rel="related" href="https://mastodon.etalab.gouv.fr/users/gcarregues/updates/4370"/> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1034065"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/1034065" local_id="1034065" ref="tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=2c27c27df8ec4dcc">tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=2c27c27df8ec4dcc</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2014147.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2014147.atom"/> - <statusnet:notice_info local_id="2014147" source="unknown"></statusnet:notice_info> -</entry> -<entry> - <id>tag:social.heldscal.la,2017-05-02:fave:23211:note:2013573:2017-05-02T13:03:33+00:00</id> - <title>Favorite</title> - <content type="html">lambadalambda favorited something by phildobangnz: also @<a href="https://sealion.club/user/579" class="h-card mention" title="Sim Bot">sim</a> reminder you are awesome; don't even trip- u kewler than Tutankhamen's cucumber, fam. Okay, good night.</content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2013702"/> - <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb> - <published>2017-05-02T13:03:33+00:00</published> - <updated>2017-05-02T13:03:33+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:sealion.club,2017-05-02:noticeId=3060818:objectType=note</id> - <title>New note by phildobangnz</title> - <content type="html">also @<a href="https://sealion.club/user/579" class="h-card mention" title="Sim Bot">sim</a> reminder you are awesome; don't even trip- u kewler than Tutankhamen's cucumber, fam. Okay, good night.</content> - <link rel="alternate" type="text/html" href="https://sealion.club/notice/3060818"/> - <status_net notice_id="2013573"></status_net> - </activity:object> - <thr:in-reply-to ref="tag:sealion.club,2017-05-02:noticeId=3060818:objectType=note" href="https://sealion.club/notice/3060818"></thr:in-reply-to> - <link rel="related" href="https://sealion.club/notice/3060818"/> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1034282"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/1034282" local_id="1034282" ref="https://sealion.club/conversation/1633267">https://sealion.club/conversation/1633267</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2013702.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2013702.atom"/> - <statusnet:notice_info local_id="2013702" source="unknown"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>tag:social.heldscal.la,2017-05-02:noticeId=2013586:objectType=comment</id> - <title>New comment by lambadalambda</title> - <content type="html">@<a href="https://xoxo.zone/users/KevinMarks" class="h-card u-url p-nickname mention" title="Kevin Marks ">kevinmarks</a> People can stay in their giant unmoderatable instances with meaningless public and federated timelines and experience constant federation drama if they want. I'll stay here with my 5 friends.</content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2013586"/> - <status_net notice_id="2013586"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-05-02T12:54:59+00:00</published> - <updated>2017-05-02T12:54:59+00:00</updated> - <thr:in-reply-to ref="tag:xoxo.zone,2017-05-02:objectId=89478:objectType=Status" href="https://xoxo.zone/users/KevinMarks/updates/1749"></thr:in-reply-to> - <link rel="related" href="https://xoxo.zone/users/KevinMarks/updates/1749"/> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1031866"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/1031866" local_id="1031866" ref="tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=58e32e013ab6487d">tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=58e32e013ab6487d</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://xoxo.zone/users/KevinMarks"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2013586.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2013586.atom"/> - <statusnet:notice_info local_id="2013586" source="Pleroma FE"></statusnet:notice_info> -</entry> -<entry> - <id>tag:social.heldscal.la,2017-05-02:fave:23211:note:2013486:2017-05-02T12:46:48+00:00</id> - <title>Favorite</title> - <content type="html">lambadalambda favorited something by fortune: There once was a dentist named Stone<br /> Who saw all his patients alone.<br /> In a fit of depravity<br /> He filled the wrong cavity,<br /> And my, how his practice has grown!</content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2013511"/> - <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb> - <published>2017-05-02T12:46:48+00:00</published> - <updated>2017-05-02T12:46:48+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:gs.kawa-kun.com,2017-05-02:noticeId=1655658:objectType=note</id> - <title>New note by fortune</title> - <content type="html">There once was a dentist named Stone<br /> Who saw all his patients alone.<br /> In a fit of depravity<br /> He filled the wrong cavity,<br /> And my, how his practice has grown!</content> - <link rel="alternate" type="text/html" href="https://gs.kawa-kun.com/notice/1655658"/> - <status_net notice_id="2013486"></status_net> - </activity:object> - <thr:in-reply-to ref="tag:gs.kawa-kun.com,2017-05-02:noticeId=1655658:objectType=note" href="https://gs.kawa-kun.com/notice/1655658"></thr:in-reply-to> - <link rel="related" href="https://gs.kawa-kun.com/notice/1655658"/> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1034222"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/1034222" local_id="1034222" ref="https://gs.kawa-kun.com/conversation/714072">https://gs.kawa-kun.com/conversation/714072</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2013511.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2013511.atom"/> - <statusnet:notice_info local_id="2013511" source="unknown"></statusnet:notice_info> -</entry> -<entry> - <id>tag:social.heldscal.la,2017-05-02:fave:23211:note:2013365:2017-05-02T12:37:55+00:00</id> - <title>Favorite</title> - <content type="html">lambadalambda favorited something by xj9: <p>&gt; rollerblading to work</p></content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2013394"/> - <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb> - <published>2017-05-02T12:37:55+00:00</published> - <updated>2017-05-02T12:37:55+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:sunshinegardens.org,2017-05-02:objectId=61020:objectType=Status</id> - <title>New note by xj9</title> - <content type="html"><p>&gt; rollerblading to work</p></content> - <link rel="alternate" type="text/html" href="https://sunshinegardens.org/users/xj9/updates/748"/> - <status_net notice_id="2013365"></status_net> - </activity:object> - <thr:in-reply-to ref="tag:sunshinegardens.org,2017-05-02:objectId=61020:objectType=Status" href="https://sunshinegardens.org/users/xj9/updates/748"></thr:in-reply-to> - <link rel="related" href="https://sunshinegardens.org/users/xj9/updates/748"/> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1034152"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/1034152" local_id="1034152" ref="tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=5a0e98612f634218">tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=5a0e98612f634218</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2013394.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2013394.atom"/> - <statusnet:notice_info local_id="2013394" source="unknown"></statusnet:notice_info> -</entry> -<entry> - <id>tag:social.heldscal.la,2017-05-02:fave:23211:comment:2013259:2017-05-02T12:29:03+00:00</id> - <title>Favorite</title> - <content type="html">lambadalambda favorited something by cereal: @<a href="https://gs.smuglo.li/user/28250" class="h-card mention" title="Bricky">thatbrickster</a> @<a href="https://social.heldscal.la/user/23211" class="h-card mention" title="Constance Variable">lambadalambda</a> But why?</content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2013267"/> - <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb> - <published>2017-05-02T12:29:03+00:00</published> - <updated>2017-05-02T12:29:03+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>tag:sealion.club,2017-05-02:noticeId=3059985:objectType=comment</id> - <title>New comment by cereal</title> - <content type="html">@<a href="https://gs.smuglo.li/user/28250" class="h-card mention" title="Bricky">thatbrickster</a> @<a href="https://social.heldscal.la/user/23211" class="h-card mention" title="Constance Variable">lambadalambda</a> But why?</content> - <link rel="alternate" type="text/html" href="https://sealion.club/notice/3059985"/> - <status_net notice_id="2013259"></status_net> - </activity:object> - <thr:in-reply-to ref="tag:sealion.club,2017-05-02:noticeId=3059985:objectType=comment" href="https://sealion.club/notice/3059985"></thr:in-reply-to> - <link rel="related" href="https://sealion.club/notice/3059985"/> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1034065"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/1034065" local_id="1034065" ref="tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=2c27c27df8ec4dcc">tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=2c27c27df8ec4dcc</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2013267.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2013267.atom"/> - <statusnet:notice_info local_id="2013267" source="unknown"></statusnet:notice_info> -</entry> -<entry> - <id>tag:social.heldscal.la,2017-05-02:fave:23211:comment:2013227:2017-05-02T12:24:27+00:00</id> - <title>Favorite</title> - <content type="html">lambadalambda favorited something by thatbrickster: @<a href="https://social.heldscal.la/user/23211" class="h-card u-url p-nickname mention" title="Constance Variable">lambadalambda</a> install gentoo</content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2013230"/> - <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb> - <published>2017-05-02T12:24:27+00:00</published> - <updated>2017-05-02T12:24:27+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>tag:gs.smuglo.li,2017-05-02:noticeId=2144296:objectType=comment</id> - <title>New comment by thatbrickster</title> - <content type="html">@<a href="https://social.heldscal.la/user/23211" class="h-card u-url p-nickname mention" title="Constance Variable">lambadalambda</a> install gentoo</content> - <link rel="alternate" type="text/html" href="https://gs.smuglo.li/notice/2144296"/> - <status_net notice_id="2013227"></status_net> - </activity:object> - <thr:in-reply-to ref="tag:gs.smuglo.li,2017-05-02:noticeId=2144296:objectType=comment" href="https://gs.smuglo.li/notice/2144296"></thr:in-reply-to> - <link rel="related" href="https://gs.smuglo.li/notice/2144296"/> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1034065"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/1034065" local_id="1034065" ref="tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=2c27c27df8ec4dcc">tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=2c27c27df8ec4dcc</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2013230.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2013230.atom"/> - <statusnet:notice_info local_id="2013230" source="unknown"></statusnet:notice_info> -</entry> -<entry> - <id>tag:social.heldscal.la,2017-05-02:fave:23211:comment:2013213:2017-05-02T12:22:53+00:00</id> - <title>Favorite</title> - <content type="html">lambadalambda favorited something by dwmatiz: @<a href="https://social.heldscal.la/user/23211" class="h-card mention">lambadalambda</a> *unzips dick*</content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2013218"/> - <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb> - <published>2017-05-02T12:22:53+00:00</published> - <updated>2017-05-02T12:22:53+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>tag:sealion.club,2017-05-02:noticeId=3059800:objectType=comment</id> - <title>New comment by dwmatiz</title> - <content type="html">@<a href="https://social.heldscal.la/user/23211" class="h-card mention">lambadalambda</a> *unzips dick*</content> - <link rel="alternate" type="text/html" href="https://sealion.club/notice/3059800"/> - <status_net notice_id="2013213"></status_net> - </activity:object> - <thr:in-reply-to ref="tag:sealion.club,2017-05-02:noticeId=3059800:objectType=comment" href="https://sealion.club/notice/3059800"></thr:in-reply-to> - <link rel="related" href="https://sealion.club/notice/3059800"/> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1034065"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/1034065" local_id="1034065" ref="tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=2c27c27df8ec4dcc">tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=2c27c27df8ec4dcc</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2013218.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2013218.atom"/> - <statusnet:notice_info local_id="2013218" source="unknown"></statusnet:notice_info> -</entry> -<entry> - <id>tag:social.heldscal.la,2017-05-02:fave:23211:comment:2013199:2017-05-02T12:22:03+00:00</id> - <title>Favorite</title> - <content type="html">lambadalambda favorited something by shpuld: @<a href="https://social.heldscal.la/user/23211" class="h-card mention" title="Constance Variable">lambadalambda</a> get #<span class="tag"><a href="https://shitposter.club/tag/cofe" rel="tag">cofe</a></span></content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2013206"/> - <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb> - <published>2017-05-02T12:22:03+00:00</published> - <updated>2017-05-02T12:22:03+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>tag:shitposter.club,2017-05-02:noticeId=2783524:objectType=comment</id> - <title>New comment by shpuld</title> - <content type="html">@<a href="https://social.heldscal.la/user/23211" class="h-card mention" title="Constance Variable">lambadalambda</a> get #<span class="tag"><a href="https://shitposter.club/tag/cofe" rel="tag">cofe</a></span></content> - <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2783524"/> - <status_net notice_id="2013199"></status_net> - </activity:object> - <thr:in-reply-to ref="tag:shitposter.club,2017-05-02:noticeId=2783524:objectType=comment" href="https://shitposter.club/notice/2783524"></thr:in-reply-to> - <link rel="related" href="https://shitposter.club/notice/2783524"/> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1034065"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/1034065" local_id="1034065" ref="tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=2c27c27df8ec4dcc">tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=2c27c27df8ec4dcc</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2013206.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2013206.atom"/> - <statusnet:notice_info local_id="2013206" source="unknown"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:social.heldscal.la,2017-05-02:noticeId=2013185:objectType=note</id> - <title>New note by lambadalambda</title> - <content type="html">What now? <a href="https://social.heldscal.la/file/e4822d95de677757ff50d49672a4046c83218b76c04a0ad5e5f1f0a9a9eb1a74.gif" title="https://social.heldscal.la/file/e4822d95de677757ff50d49672a4046c83218b76c04a0ad5e5f1f0a9a9eb1a74.gif" rel="nofollow external noreferrer" class="attachment" id="attachment-422572">https://social.heldscal.la/attachment/422572</a></content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2013185"/> - <status_net notice_id="2013185"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-05-02T12:21:04+00:00</published> - <updated>2017-05-02T12:21:04+00:00</updated> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1034065"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/1034065" local_id="1034065" ref="tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=2c27c27df8ec4dcc">tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=2c27c27df8ec4dcc</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="enclosure" href="https://social.heldscal.la/file/e4822d95de677757ff50d49672a4046c83218b76c04a0ad5e5f1f0a9a9eb1a74.gif" type="image/gif" length="132349"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2013185.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2013185.atom"/> - <statusnet:notice_info local_id="2013185" source="Pleroma FE"></statusnet:notice_info> -</entry> -<entry> - <id>tag:social.heldscal.la,2017-05-02:fave:23211:note:2012929:2017-05-02T12:01:25+00:00</id> - <title>Favorite</title> - <content type="html">lambadalambda favorited something by drkmttr: <p><span class="h-card"><a href="https://social.heldscal.la/lambadalambda" class="u-url mention">@<span>lambadalambda</span></a></span> I checked out No Agenda because I saw you mention it several time. Sadly, I wasn't impressed. I'm all about varying perspectives but Adam and John basically just sound like resentful curmudgeons. It seems like their shtick is basically playing devil's advocate to everything to arouse some discontent. Just my two cents. 😉</p></content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2012940"/> - <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb> - <published>2017-05-02T12:01:25+00:00</published> - <updated>2017-05-02T12:01:25+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:mstdn.io,2017-05-02:objectId=1310093:objectType=Status</id> - <title>New note by drkmttr</title> - <content type="html"><p><span class="h-card"><a href="https://social.heldscal.la/lambadalambda" class="u-url mention">@<span>lambadalambda</span></a></span> I checked out No Agenda because I saw you mention it several time. Sadly, I wasn't impressed. I'm all about varying perspectives but Adam and John basically just sound like resentful curmudgeons. It seems like their shtick is basically playing devil's advocate to everything to arouse some discontent. Just my two cents. 😉</p></content> - <link rel="alternate" type="text/html" href="https://mstdn.io/users/drkmttr/updates/35653"/> - <status_net notice_id="2012929"></status_net> - </activity:object> - <thr:in-reply-to ref="tag:mstdn.io,2017-05-02:objectId=1310093:objectType=Status" href="https://mstdn.io/users/drkmttr/updates/35653"></thr:in-reply-to> - <link rel="related" href="https://mstdn.io/users/drkmttr/updates/35653"/> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1033892"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/1033892" local_id="1033892" ref="tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=2f329b4eb20e83e2">tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=2f329b4eb20e83e2</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2012940.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2012940.atom"/> - <statusnet:notice_info local_id="2012940" source="unknown"></statusnet:notice_info> -</entry> -<entry> - <id>tag:social.heldscal.la,2017-05-02:fave:23211:comment:2012336:2017-05-02T11:06:42+00:00</id> - <title>Favorite</title> - <content type="html">lambadalambda favorited something by clacke: @<a href="https://mastodon.org.uk/users/dick_turpin" class="h-card u-url p-nickname mention" title="dick_turpin">dickturpin</a> @<a href="http://quitter.se/user/113503" class="h-card u-url p-nickname mention" title="Luke">luke</a> Oh no, I miss being irritated by you, it helps me understand myself and others. Also it builds character. :-)<br /> <br /> So if this is not federation because you can't follow all of online mankind, what should we call it? Proto-federated? Pre-federated?<br /> <br /> The term has been used decades ago for just one Microsoft Active Directory domain cross-certifying the root of another, by mutual agreement. I don't see how it's any less relevant to opportunistic federation between open servers on an open internet.<br /> <br /> I'm not saying we should be satisfied, I'm just saying that "federate" is a useful word and to build a big system we need to start with a small one. And focus on the things we *can* change, like helping the OStatus network grow and making the tools more useful.<br /> <br /> Saying that the network's ideals have failed because other networks aren't joining is doing neither of that.</content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2012341"/> - <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb> - <published>2017-05-02T11:06:42+00:00</published> - <updated>2017-05-02T11:06:42+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>tag:social.heldscal.la,2017-05-02:noticeId=2012336:objectType=comment</id> - <title>New comment by clacke</title> - <content type="html">@<a href="https://mastodon.org.uk/users/dick_turpin" class="h-card u-url p-nickname mention" title="dick_turpin">dickturpin</a> @<a href="http://quitter.se/user/113503" class="h-card u-url p-nickname mention" title="Luke">luke</a> Oh no, I miss being irritated by you, it helps me understand myself and others. Also it builds character. :-)<br /> <br /> So if this is not federation because you can't follow all of online mankind, what should we call it? Proto-federated? Pre-federated?<br /> <br /> The term has been used decades ago for just one Microsoft Active Directory domain cross-certifying the root of another, by mutual agreement. I don't see how it's any less relevant to opportunistic federation between open servers on an open internet.<br /> <br /> I'm not saying we should be satisfied, I'm just saying that &quot;federate&quot; is a useful word and to build a big system we need to start with a small one. And focus on the things we *can* change, like helping the OStatus network grow and making the tools more useful.<br /> <br /> Saying that the network's ideals have failed because other networks aren't joining is doing neither of that.</content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2012336"/> - <status_net notice_id="2012336"></status_net> - </activity:object> - <thr:in-reply-to ref="tag:social.heldscal.la,2017-05-02:noticeId=2012336:objectType=comment" href="https://social.heldscal.la/notice/2012336"></thr:in-reply-to> - <link rel="related" href="https://social.heldscal.la/notice/2012336"/> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1016421"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/1016421" local_id="1016421" ref="https://s.wefamlee.be/conversation/16478">https://s.wefamlee.be/conversation/16478</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2012341.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2012341.atom"/> - <statusnet:notice_info local_id="2012341" source="unknown"></statusnet:notice_info> -</entry> -<entry> - <id>tag:social.heldscal.la,2017-05-02:fave:23211:comment:2011332:2017-05-02T10:37:40+00:00</id> - <title>Favorite</title> - <content type="html">lambadalambda favorited something by moonman: @<a href="https://social.heldscal.la/user/23211" class="h-card mention" title="Constance Variable">lambadalambda</a> <a href="https://www.youtube.com/watch?v=mKLizztikRk" title="https://www.youtube.com/watch?v=mKLizztikRk" class="attachment" rel="nofollow">https://www.youtube.com/watch?v=mKLizztikRk</a></content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2012148"/> - <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb> - <published>2017-05-02T10:37:40+00:00</published> - <updated>2017-05-02T10:37:40+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>tag:shitposter.club,2017-05-02:noticeId=2781833:objectType=comment</id> - <title>New comment by moonman</title> - <content type="html">@<a href="https://social.heldscal.la/user/23211" class="h-card mention" title="Constance Variable">lambadalambda</a> <a href="https://www.youtube.com/watch?v=mKLizztikRk" title="https://www.youtube.com/watch?v=mKLizztikRk" class="attachment" rel="nofollow">https://www.youtube.com/watch?v=mKLizztikRk</a></content> - <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2781833"/> - <status_net notice_id="2011332"></status_net> - </activity:object> - <thr:in-reply-to ref="tag:shitposter.club,2017-05-02:noticeId=2781833:objectType=comment" href="https://shitposter.club/notice/2781833"></thr:in-reply-to> - <link rel="related" href="https://shitposter.club/notice/2781833"/> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1032783"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/1032783" local_id="1032783" ref="tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=11d8b8c27d9513ec">tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=11d8b8c27d9513ec</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2012148.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2012148.atom"/> - <statusnet:notice_info local_id="2012148" source="unknown"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>tag:social.heldscal.la,2017-05-02:noticeId=2012145:objectType=comment</id> - <title>New comment by lambadalambda</title> - <content type="html">@<a href="https://sealion.club/user/186" class="h-card u-url p-nickname mention" title="I'M CEREAL U GUISE">cereal</a> ? No, you don't even need the identity servers for federation.</content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2012145"/> - <status_net notice_id="2012145"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-05-02T10:37:33+00:00</published> - <updated>2017-05-02T10:37:33+00:00</updated> - <thr:in-reply-to ref="tag:sealion.club,2017-05-02:noticeId=3056001:objectType=comment" href="https://sealion.club/notice/3056001"></thr:in-reply-to> - <link rel="related" href="https://sealion.club/notice/3056001"/> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1033277"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/1033277" local_id="1033277" ref="https://sealion.club/conversation/1629037">https://sealion.club/conversation/1629037</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://sealion.club/user/186"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2012145.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2012145.atom"/> - <statusnet:notice_info local_id="2012145" source="Pleroma FE"></statusnet:notice_info> -</entry> -</feed> diff --git a/test/fixtures/activitypub-client-post-activity.json b/test/fixtures/activitypub-client-post-activity.json index c985e072b..e592081bc 100644 --- a/test/fixtures/activitypub-client-post-activity.json +++ b/test/fixtures/activitypub-client-post-activity.json @@ -3,6 +3,7 @@ "type": "Create", "object": { "type": "Note", + "to": ["https://www.w3.org/ns/activitystreams#Public"], "content": "It's a note" }, "to": ["https://www.w3.org/ns/activitystreams#Public"] diff --git a/test/fixtures/bridgy/actor.json b/test/fixtures/bridgy/actor.json new file mode 100644 index 000000000..5b2d8982b --- /dev/null +++ b/test/fixtures/bridgy/actor.json @@ -0,0 +1,80 @@ +{ + "id": "https://fed.brid.gy/jk.nipponalba.scot", + "url": "https://fed.brid.gy/r/https://jk.nipponalba.scot", + "urls": [ + { + "value": "https://jk.nipponalba.scot" + }, + { + "value": "https://social.nipponalba.scot/jk" + }, + { + "value": "https://px.nipponalba.scot/jk" + } + ], + "@context": "https://www.w3.org/ns/activitystreams", + "type": "Person", + "name": "J K 🇯🇵🏴", + "image": [ + { + "url": "https://jk.nipponalba.scot/images/profile.jpg", + "type": "Image", + "name": "profile picture" + } + ], + "tag": [ + { + "type": "Tag", + "name": "Craft Beer" + }, + { + "type": "Tag", + "name": "Single Malt Whisky" + }, + { + "type": "Tag", + "name": "Homebrewing" + }, + { + "type": "Tag", + "name": "Scottish Politics" + }, + { + "type": "Tag", + "name": "Scottish History" + }, + { + "type": "Tag", + "name": "Japanese History" + }, + { + "type": "Tag", + "name": "Tech" + }, + { + "type": "Tag", + "name": "Veganism" + }, + { + "type": "Tag", + "name": "Cooking" + } + ], + "icon": [ + { + "url": "https://jk.nipponalba.scot/images/profile.jpg", + "type": "Image", + "name": "profile picture" + } + ], + "preferredUsername": "jk.nipponalba.scot", + "summary": "", + "publicKey": { + "id": "jk.nipponalba.scot", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDdarxwzxnNbJ2hneWOYHkYJowk\npyigQtxlUd0VjgSQHwxU9kWqfbrHBVADyTtcqi/4dAzQd3UnCI1TPNnn4LPZY9PW\noiWd3Zl1/EfLFxO7LU9GS7fcSLQkyj5JNhSlN3I8QPudZbybrgRDVZYooDe1D+52\n5KLGqC2ajrIVOiDRTQIDAQAB\n-----END PUBLIC KEY-----" + }, + "inbox": "https://fed.brid.gy/jk.nipponalba.scot/inbox", + "outbox": "https://fed.brid.gy/jk.nipponalba.scot/outbox", + "following": "https://fed.brid.gy/jk.nipponalba.scot/following", + "followers": "https://fed.brid.gy/jk.nipponalba.scot/followers" +} diff --git a/test/fixtures/config/temp.exported_from_db.secret.exs b/test/fixtures/config/temp.exported_from_db.secret.exs new file mode 100644 index 000000000..dda5d0fa6 --- /dev/null +++ b/test/fixtures/config/temp.exported_from_db.secret.exs @@ -0,0 +1,5 @@ +import Config + +config :pleroma, exported_config_merged: true + +config :pleroma, :first_setting, key: "new value" diff --git a/test/fixtures/config/temp.secret.exs b/test/fixtures/config/temp.secret.exs index fa8c7c7e8..9c5c88d98 100644 --- a/test/fixtures/config/temp.secret.exs +++ b/test/fixtures/config/temp.secret.exs @@ -1,4 +1,8 @@ -use Mix.Config +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +import Config config :pleroma, :first_setting, key: "value", key2: [Pleroma.Repo] diff --git a/test/fixtures/custom_instance_panel.html b/test/fixtures/custom_instance_panel.html new file mode 100644 index 000000000..6371a1e43 --- /dev/null +++ b/test/fixtures/custom_instance_panel.html @@ -0,0 +1 @@ +<h2>Custom instance panel</h2>
\ No newline at end of file diff --git a/test/fixtures/cw_retweet.xml b/test/fixtures/cw_retweet.xml deleted file mode 100644 index c99a569d7..000000000 --- a/test/fixtures/cw_retweet.xml +++ /dev/null @@ -1,68 +0,0 @@ -<?xml version="1.0"?> -<feed xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:media="http://purl.org/syndication/atommedia" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:mastodon="http://mastodon.social/schema/1.0"> - <id>https://mastodon.social/users/lambadalambda.atom</id> - <title>Critical Value</title> - <subtitle></subtitle> - <updated>2017-04-16T21:47:25Z</updated> - <logo>https://files.mastodon.social/accounts/avatars/000/000/264/original/1429214160519.gif</logo> - <author> - <id>https://mastodon.social/users/lambadalambda</id> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://mastodon.social/users/lambadalambda</uri> - <name>lambadalambda</name> - <email>lambadalambda@mastodon.social</email> - <link rel="alternate" type="text/html" href="https://mastodon.social/@lambadalambda"/> - <link rel="avatar" type="image/gif" media:width="120" media:height="120" href="https://files.mastodon.social/accounts/avatars/000/000/264/original/1429214160519.gif"/> - <link rel="header" type="" media:width="700" media:height="335" href="/headers/original/missing.png"/> - <poco:preferredUsername>lambadalambda</poco:preferredUsername> - <poco:displayName>Critical Value</poco:displayName> - <mastodon:scope>public</mastodon:scope> - </author> - <link rel="alternate" type="text/html" href="https://mastodon.social/@lambadalambda"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda.atom"/> - <link rel="hub" href="https://mastodon.social/api/push"/> - <link rel="salmon" href="https://mastodon.social/api/salmon/264"/> - <entry> - <id>tag:mastodon.social,2017-05-11:objectId=5647963:objectType=Status</id> - <published>2017-05-11T10:23:15Z</published> - <updated>2017-05-11T10:23:15Z</updated> - <title>lambadalambda shared a status by Skruyb@mamot.fr</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb> - <activity:object> - <id>tag:mamot.fr,2017-05-10:objectId=1294943:objectType=Status</id> - <published>2017-05-10T17:31:44Z</published> - <updated>2017-05-10T17:31:45Z</updated> - <title>New status by Skruyb@mamot.fr</title> - <author> - <id>https://mamot.fr/users/Skruyb</id> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://mamot.fr/users/Skruyb</uri> - <name>Skruyb</name> - <email>Skruyb@mamot.fr</email> - <summary type="html"><p>Fr and En.<br>Posts will disappear on a regular basis.</p></summary> - <link rel="alternate" type="text/html" href="https://mamot.fr/@Skruyb"/> - <link rel="avatar" type="image/jpeg" media:width="120" media:height="120" href="https://files.mastodon.social/accounts/avatars/000/106/282/original/d95dbcfc76f77f4c.jpg"/> - <link rel="header" type="image/jpeg" media:width="700" media:height="335" href="https://files.mastodon.social/accounts/headers/000/106/282/original/c1aabdf5c97eb875.jpg"/> - <poco:preferredUsername>Skruyb</poco:preferredUsername> - <poco:displayName>The 7th Son</poco:displayName> - <poco:note>Fr and En.Posts will disappear on a regular basis.</poco:note> - <mastodon:scope>public</mastodon:scope> - </author> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <summary xml:lang="it">Hey.</summary> - <content type="html" xml:lang="it"><p><span class="h-card"><a href="https://mastodon.social/@lambadalambda">@<span>lambadalambda</span></a></span></p><p>Hey!!!</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.social/users/lambadalambda"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mamot.fr/users/Skruyb/updates/176041"/> - <thr:in-reply-to ref="tag:mastodon.social,2017-05-10:objectId=5582979:objectType=Status" href="https://mastodon.social/@lambadalambda/5582979"/> - </activity:object> - <content type="html" xml:lang="en"><p><span class="h-card"><a href="https://mastodon.social/@lambadalambda">@<span>lambadalambda</span></a></span></p><p>Hey!!!</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/2325225"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/2325225.atom"/> - </entry> -</feed> diff --git a/test/fixtures/delete.xml b/test/fixtures/delete.xml deleted file mode 100644 index 731e1c204..000000000 --- a/test/fixtures/delete.xml +++ /dev/null @@ -1,39 +0,0 @@ -<?xml version="1.0"?> -<feed xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:media="http://purl.org/syndication/atommedia" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:mastodon="http://mastodon.social/schema/1.0"> - <id>https://mastodon.sdf.org/users/snowdusk.atom</id> - <title>snowdusk</title> - <subtitle>Amateur live performance DJ/radio DJ on SDF's underground Internet radio http://aNONradio.net (LIVE Sat Sun Mon Tue 23:00-24:00 UTC) - http://snowdusk.sdf.org</subtitle> - <updated>2017-06-17T04:14:34Z</updated> - <logo>https://mastodon.sdf.org/system/accounts/avatars/000/000/002/original/405a7652d5f60449.jpg?1497672873</logo> - <author> - <id>https://mastodon.sdf.org/users/snowdusk</id> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://mastodon.sdf.org/users/snowdusk</uri> - <name>snowdusk</name> - <email>snowdusk@mastodon.sdf.org</email> - <summary type="html"><p>Amateur live performance DJ/radio DJ on SDF&apos;s underground Internet radio <a href="http://anonradio.net/" rel="nofollow noopener" target="_blank"><span class="invisible">http://</span><span class="">anonradio.net/</span><span class="invisible"></span></a> (LIVE Sat Sun Mon Tue 23:00-24:00 UTC) - <a href="http://snowdusk.sdf.org/" rel="nofollow noopener" target="_blank"><span class="invisible">http://</span><span class="">snowdusk.sdf.org/</span><span class="invisible"></span></a></p></summary> - <link rel="alternate" type="text/html" href="https://mastodon.sdf.org/@snowdusk"/> - <link rel="avatar" type="image/jpeg" media:width="120" media:height="120" href="https://mastodon.sdf.org/system/accounts/avatars/000/000/002/original/405a7652d5f60449.jpg?1497672873"/> - <link rel="header" type="image/jpeg" media:width="700" media:height="335" href="https://mastodon.sdf.org/system/accounts/headers/000/000/002/original/f1e9b0fb21b4e5a0.jpeg?1495793472"/> - <poco:preferredUsername>snowdusk</poco:preferredUsername> - <poco:displayName>snowdusk</poco:displayName> - <poco:note>Amateur live performance DJ/radio DJ on SDF's underground Internet radio http://aNONradio.net (LIVE Sat Sun Mon Tue 23:00-24:00 UTC) - http://snowdusk.sdf.org</poco:note> - <mastodon:scope>public</mastodon:scope> - </author> - <link rel="alternate" type="text/html" href="https://mastodon.sdf.org/@snowdusk"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.sdf.org/users/snowdusk.atom"/> - <link rel="next" type="application/atom+xml" href="https://mastodon.sdf.org/users/snowdusk.atom?max_id=7592"/> - <link rel="hub" href="https://mastodon.sdf.org/api/push"/> - <link rel="salmon" href="https://mastodon.sdf.org/api/salmon/2"/> - <entry> - <id>tag:mastodon.sdf.org,2017-06-10:objectId=310513:objectType=Status</id> - <published>2017-06-10T22:02:31Z</published> - <updated>2017-06-10T22:02:31Z</updated> - <title>snowdusk deleted status</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/delete</activity:verb> - <content>Deleted status</content> - <link rel="alternate" type="text/html" href="https://mastodon.sdf.org/users/snowdusk/updates/7782"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.sdf.org/users/snowdusk/updates/7782.atom"/> - </entry> -</feed> diff --git a/test/fixtures/dm.xml b/test/fixtures/dm.xml deleted file mode 100644 index d0b8aa811..000000000 --- a/test/fixtures/dm.xml +++ /dev/null @@ -1,27 +0,0 @@ -<?xml version="1.0"?> -<entry xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:media="http://purl.org/syndication/atommedia" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:mastodon="http://mastodon.social/schema/1.0"> - <id>tag:mastodon.social,2017-06-30:objectId=11260427:objectType=Status</id> - <published>2017-06-30T13:27:47Z</published> - <updated>2017-06-30T13:27:47Z</updated> - <title>New status by lambadalambda</title> - <author> - <id>https://mastodon.social/users/lambadalambda</id> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://mastodon.social/users/lambadalambda</uri> - <name>lambadalambda</name> - <email>lambadalambda@mastodon.social</email> - <link rel="alternate" type="text/html" href="https://mastodon.social/@lambadalambda"/> - <link rel="avatar" type="image/gif" media:width="120" media:height="120" href="https://files.mastodon.social/accounts/avatars/000/000/264/original/1429214160519.gif"/> - <poco:preferredUsername>lambadalambda</poco:preferredUsername> - <poco:displayName>Critical Value</poco:displayName> - <mastodon:scope>public</mastodon:scope> - </author> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="ky"><p><span class="h-card"><a href="https://pleroma.soykaf.com/users/lain" class="u-url mention">@<span>lain</span></a></span> Hey.</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://pleroma.soykaf.com/users/lain"/> - <mastodon:scope>direct</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/3514345"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/3514345.atom"/> - <ostatus:conversation ref="tag:mastodon.social,2017-06-30:objectId=4009714:objectType=Conversation"/> -</entry> diff --git a/test/fixtures/emojis.zip b/test/fixtures/emojis.zip Binary files differnew file mode 100644 index 000000000..d7fc4732b --- /dev/null +++ b/test/fixtures/emojis.zip diff --git a/test/fixtures/empty.zip b/test/fixtures/empty.zip Binary files differnew file mode 100644 index 000000000..15cb0ecb3 --- /dev/null +++ b/test/fixtures/empty.zip diff --git a/test/fixtures/favorite.xml b/test/fixtures/favorite.xml deleted file mode 100644 index c32b4a403..000000000 --- a/test/fixtures/favorite.xml +++ /dev/null @@ -1,65 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:georss="http://www.georss.org/georss" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:media="http://purl.org/syndication/atommedia" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:statusnet="http://status.net/schema/api/1/"> - <generator uri="https://gnu.io/social" version="1.0.2-dev">GNU social</generator> - <id>https://social.heldscal.la/api/statuses/user_timeline/23211.atom</id> - <title>lambadalambda timeline</title> - <subtitle>Updates from lambadalambda on social.heldscal.la!</subtitle> - <logo>https://social.heldscal.la/avatar/23211-96-20170416114255.jpeg</logo> - <updated>2017-05-05T09:12:53+00:00</updated> -<author> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://social.heldscal.la/user/23211</uri> - <name>lambadalambda</name> - <summary>Call me Deacon Blues.</summary> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/lambadalambda"/> - <link rel="avatar" type="image/jpeg" media:width="236" media:height="236" href="https://social.heldscal.la/avatar/23211-original-20170416114255.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/23211-96-20170416114255.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="48" media:height="48" href="https://social.heldscal.la/avatar/23211-48-20170416114255.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="24" media:height="24" href="https://social.heldscal.la/avatar/23211-24-20170416114257.jpeg"/> - <poco:preferredUsername>lambadalambda</poco:preferredUsername> - <poco:displayName>Constance Variable</poco:displayName> - <poco:note>Call me Deacon Blues.</poco:note> - <poco:address> - <poco:formatted>Berlin</poco:formatted> - </poco:address> - <poco:urls> - <poco:type>homepage</poco:type> - <poco:value>https://heldscal.la</poco:value> - <poco:primary>true</poco:primary> - </poco:urls> - <followers url="https://social.heldscal.la/lambadalambda/subscribers"></followers> - <statusnet:profile_info local_id="23211"></statusnet:profile_info> -</author> - <link href="https://social.heldscal.la/lambadalambda" rel="alternate" type="text/html"/> - <link href="https://social.heldscal.la/main/sup" rel="http://api.friendfeed.com/2008/03#sup" type="application/json"/> - <link href="https://social.heldscal.la/main/push/hub" rel="hub"/> - <link href="https://social.heldscal.la/main/salmon/user/23211" rel="salmon"/> - <link href="https://social.heldscal.la/main/salmon/user/23211" rel="http://salmon-protocol.org/ns/salmon-replies"/> - <link href="https://social.heldscal.la/main/salmon/user/23211" rel="http://salmon-protocol.org/ns/salmon-mention"/> - <link href="https://social.heldscal.la/api/statuses/user_timeline/23211.atom" rel="self" type="application/atom+xml"/> -<entry> - <id>tag:social.heldscal.la,2017-05-05:fave:23211:comment:2061643:2017-05-05T09:12:50+00:00</id> - <title>Favorite</title> - <content type="html">lambadalambda favorited something by moonman: @<a href="https://shitposter.club/user/9655" class="h-card mention" title="Solidarity for Pigs">neimzr4luzerz</a> @<a href="https://gs.smuglo.li/user/2326" class="h-card mention" title="Dolus_McHonest">dolus</a> childhood poring over Strong's concordance and a koine Greek dictionary, fast forward to 2017 and some fuckstick who translates japanese jackoff material tells me you just need to make it sound right in English</content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2061828"/> - <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb> - <published>2017-05-05T09:12:50+00:00</published> - <updated>2017-05-05T09:12:50+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment</id> - <title>New comment by moonman</title> - <content type="html">@<a href="https://shitposter.club/user/9655" class="h-card mention" title="Solidarity for Pigs">neimzr4luzerz</a> @<a href="https://gs.smuglo.li/user/2326" class="h-card mention" title="Dolus_McHonest">dolus</a> childhood poring over Strong's concordance and a koine Greek dictionary, fast forward to 2017 and some fuckstick who translates japanese jackoff material tells me you just need to make it sound right in English</content> - <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2827873"/> - <status_net notice_id="2061643"></status_net> - </activity:object> - <thr:in-reply-to ref="tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment" href="https://shitposter.club/notice/2827873"></thr:in-reply-to> - <link rel="related" href="https://shitposter.club/notice/2827873"/> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1061781"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/1061781" local_id="1061781" ref="tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=55ead90125cd4bd4">tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=55ead90125cd4bd4</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2061828.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2061828.atom"/> - <statusnet:notice_info local_id="2061828" source="unknown"></statusnet:notice_info> -</entry> -</feed> diff --git a/test/fixtures/favorite_with_local_note.xml b/test/fixtures/favorite_with_local_note.xml deleted file mode 100644 index 3c955607d..000000000 --- a/test/fixtures/favorite_with_local_note.xml +++ /dev/null @@ -1,64 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:georss="http://www.georss.org/georss" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:media="http://purl.org/syndication/atommedia" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:statusnet="http://status.net/schema/api/1/"> - <generator uri="https://gnu.io/social" version="1.0.2-dev">GNU social</generator> - <id>https://social.heldscal.la/api/statuses/user_timeline/23211.atom</id> - <title>lambadalambda timeline</title> - <subtitle>Updates from lambadalambda on social.heldscal.la!</subtitle> - <logo>https://social.heldscal.la/avatar/23211-96-20170416114255.jpeg</logo> - <updated>2017-05-05T09:12:53+00:00</updated> -<author> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://social.heldscal.la/user/23211</uri> - <name>lambadalambda</name> - <summary>Call me Deacon Blues.</summary> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/lambadalambda"/> - <link rel="avatar" type="image/jpeg" media:width="236" media:height="236" href="https://social.heldscal.la/avatar/23211-original-20170416114255.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/23211-96-20170416114255.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="48" media:height="48" href="https://social.heldscal.la/avatar/23211-48-20170416114255.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="24" media:height="24" href="https://social.heldscal.la/avatar/23211-24-20170416114257.jpeg"/> - <poco:preferredUsername>lambadalambda</poco:preferredUsername> - <poco:displayName>Constance Variable</poco:displayName> - <poco:note>Call me Deacon Blues.</poco:note> - <poco:address> - <poco:formatted>Berlin</poco:formatted> - </poco:address> - <poco:urls> - <poco:type>homepage</poco:type> - <poco:value>https://heldscal.la</poco:value> - <poco:primary>true</poco:primary> - </poco:urls> - <followers url="https://social.heldscal.la/lambadalambda/subscribers"></followers> - <statusnet:profile_info local_id="23211"></statusnet:profile_info> -</author> - <link href="https://social.heldscal.la/lambadalambda" rel="alternate" type="text/html"/> - <link href="https://social.heldscal.la/main/sup" rel="http://api.friendfeed.com/2008/03#sup" type="application/json"/> - <link href="https://social.heldscal.la/main/push/hub" rel="hub"/> - <link href="https://social.heldscal.la/main/salmon/user/23211" rel="salmon"/> - <link href="https://social.heldscal.la/main/salmon/user/23211" rel="http://salmon-protocol.org/ns/salmon-replies"/> - <link href="https://social.heldscal.la/main/salmon/user/23211" rel="http://salmon-protocol.org/ns/salmon-mention"/> - <link href="https://social.heldscal.la/api/statuses/user_timeline/23211.atom" rel="self" type="application/atom+xml"/> -<entry> - <id>tag:social.heldscal.la,2017-05-05:fave:23211:comment:2061643:2017-05-05T09:12:50+00:00</id> - <title>Favorite</title> - <content type="html">lambadalambda favorited something by moonman: @<a href="https://shitposter.club/user/9655" class="h-card mention" title="Solidarity for Pigs">neimzr4luzerz</a> @<a href="https://gs.smuglo.li/user/2326" class="h-card mention" title="Dolus_McHonest">dolus</a> childhood poring over Strong's concordance and a koine Greek dictionary, fast forward to 2017 and some fuckstick who translates japanese jackoff material tells me you just need to make it sound right in English</content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2061828"/> - <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb> - <published>2017-05-05T09:12:50+00:00</published> - <updated>2017-05-05T09:12:50+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>localid</id> - <title>New comment by moonman</title> - <content type="html">@<a href="https://shitposter.club/user/9655" class="h-card mention" title="Solidarity for Pigs">neimzr4luzerz</a> @<a href="https://gs.smuglo.li/user/2326" class="h-card mention" title="Dolus_McHonest">dolus</a> childhood poring over Strong's concordance and a koine Greek dictionary, fast forward to 2017 and some fuckstick who translates japanese jackoff material tells me you just need to make it sound right in English</content> - <status_net notice_id="2061643"></status_net> - </activity:object> - <thr:in-reply-to ref="tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment" href="https://shitposter.club/notice/2827873"></thr:in-reply-to> - <link rel="related" href="https://shitposter.club/notice/2827873"/> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1061781"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/1061781" local_id="1061781" ref="tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=55ead90125cd4bd4">tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=55ead90125cd4bd4</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2061828.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2061828.atom"/> - <statusnet:notice_info local_id="2061828" source="unknown"></statusnet:notice_info> -</entry> -</feed> diff --git a/test/fixtures/follow.xml b/test/fixtures/follow.xml deleted file mode 100644 index d4e89954b..000000000 --- a/test/fixtures/follow.xml +++ /dev/null @@ -1,68 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:georss="http://www.georss.org/georss" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:media="http://purl.org/syndication/atommedia" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:statusnet="http://status.net/schema/api/1/"> - <generator uri="https://gnu.io/social" version="1.0.2-dev">GNU social</generator> - <id>https://social.heldscal.la/api/statuses/user_timeline/23211.atom</id> - <title>lambadalambda timeline</title> - <subtitle>Updates from lambadalambda on social.heldscal.la!</subtitle> - <logo>https://social.heldscal.la/avatar/23211-96-20170416114255.jpeg</logo> - <updated>2017-05-07T09:54:49+00:00</updated> -<author> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://social.heldscal.la/user/23211</uri> - <name>lambadalambda</name> - <summary>Call me Deacon Blues.</summary> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/lambadalambda"/> - <link rel="avatar" type="image/jpeg" media:width="236" media:height="236" href="https://social.heldscal.la/avatar/23211-original-20170416114255.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/23211-96-20170416114255.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="48" media:height="48" href="https://social.heldscal.la/avatar/23211-48-20170416114255.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="24" media:height="24" href="https://social.heldscal.la/avatar/23211-24-20170416114257.jpeg"/> - <poco:preferredUsername>lambadalambda</poco:preferredUsername> - <poco:displayName>Constance Variable</poco:displayName> - <poco:note>Call me Deacon Blues.</poco:note> - <poco:address> - <poco:formatted>Berlin</poco:formatted> - </poco:address> - <poco:urls> - <poco:type>homepage</poco:type> - <poco:value>https://heldscal.la</poco:value> - <poco:primary>true</poco:primary> - </poco:urls> - <followers url="https://social.heldscal.la/lambadalambda/subscribers"></followers> - <statusnet:profile_info local_id="23211"></statusnet:profile_info> -</author> - <link href="https://social.heldscal.la/lambadalambda" rel="alternate" type="text/html"/> - <link href="https://social.heldscal.la/main/sup" rel="http://api.friendfeed.com/2008/03#sup" type="application/json"/> - <link href="https://social.heldscal.la/main/push/hub" rel="hub"/> - <link href="https://social.heldscal.la/main/salmon/user/23211" rel="salmon"/> - <link href="https://social.heldscal.la/main/salmon/user/23211" rel="http://salmon-protocol.org/ns/salmon-replies"/> - <link href="https://social.heldscal.la/main/salmon/user/23211" rel="http://salmon-protocol.org/ns/salmon-mention"/> - <link href="https://social.heldscal.la/api/statuses/user_timeline/23211.atom" rel="self" type="application/atom+xml"/> -<entry> - <id>tag:social.heldscal.la,2017-05-07:subscription:23211:person:44803:2017-05-07T09:54:48+00:00</id> - <title>Constance Variable (lambadalambda@social.heldscal.la)'s status on Sunday, 07-May-2017 09:54:49 UTC</title> - <content type="html"><a href="https://social.heldscal.la/lambadalambda">Constance Variable</a> started following <a href="https://pawoo.net/@pekorino">mono</a>.</content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2092981"/> - <activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb> - <published>2017-05-07T09:54:49+00:00</published> - <updated>2017-05-07T09:54:49+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <id>https://pawoo.net/users/pekorino</id> - <title>mono</title> - <summary>http://shitposter.club/mono 孤独のグルメ</summary> - <link rel="alternate" type="text/html" href="https://pawoo.net/@pekorino"/> - <link rel="avatar" type="image/png" media:width="96" media:height="96" href="http://social.heldscal.la/theme/neo-gnu/default-avatar-profile.png"/> - <link rel="avatar" type="image/png" media:width="48" media:height="48" href="http://social.heldscal.la/theme/neo-gnu/default-avatar-stream.png"/> - <link rel="avatar" type="image/png" media:width="24" media:height="24" href="http://social.heldscal.la/theme/neo-gnu/default-avatar-mini.png"/> - <poco:preferredUsername>pekorino</poco:preferredUsername> - <poco:displayName>mono</poco:displayName> - <poco:note>http://shitposter.club/mono 孤独のグルメ</poco:note> - </activity:object> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1079786"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/1079786" local_id="1079786" ref="tag:social.heldscal.la,2017-05-07:objectType=thread:nonce=6e80caf94e03029f">tag:social.heldscal.la,2017-05-07:objectType=thread:nonce=6e80caf94e03029f</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2092981.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2092981.atom"/> - <statusnet:notice_info local_id="2092981" source="activity"></statusnet:notice_info> -</entry> -</feed> diff --git a/test/fixtures/guppe-actor.json b/test/fixtures/guppe-actor.json new file mode 100644 index 000000000..d5829ee1f --- /dev/null +++ b/test/fixtures/guppe-actor.json @@ -0,0 +1,26 @@ +{ + "@context" : [ + "https://www.w3.org/ns/activitystreams", + "https://w3id.org/security/v1" + ], + "followers" : "https://gup.pe/u/bernie2020/followers", + "following" : "https://gup.pe/u/bernie2020/following", + "icon" : { + "mediaType" : "image/jpeg", + "type" : "Image", + "url" : "https://gup.pe/f/guppe.png" + }, + "id" : "https://gup.pe/u/bernie2020", + "inbox" : "https://gup.pe/u/bernie2020/inbox", + "liked" : "https://gup.pe/u/bernie2020/liked", + "name" : "Bernie2020 group", + "outbox" : "https://gup.pe/u/bernie2020/outbox", + "preferredUsername" : "Bernie2020", + "publicKey" : { + "id" : "https://gup.pe/u/bernie2020#main-key", + "owner" : "https://gup.pe/u/bernie2020", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAw4J8nSrdWWxFaipgWDhR\nbTFzHUGoFy7Gjdc6gg9ZWGWDm9ZU5Ct0C/4o72dXSWdyLbQGYMbWVHLI1LHWKSiC\nVtwIYoccQBaxfi5bCxsahWhhSNPfK8tVlySHvBy73ir8KUZm93eAYh1iE9x+Dk63\nInmi7wzjsqHSlu1KxPGYcnyxs+xxhlTUSd5LsPfO1b9sHMW+X4rEky7OC90veCdD\nsoHU+nCmf+2zJSlOrU7DAzqB4Axc9oS9Q5RlT3yARJQMeu6JyjJJP9CMbpGFbUNT\n5Gsw0km1Rc1rR4tUoz8pLUYtliEUK+/0EmHi2EHAT1ueEfMoGGbCaX/mCoMmAwYJ\nwIGYXmKn2/ARIJpw2XPmrKWXqa2AndOQdb3l44Sl3ej2rC/JQmimGCn7tbfKEZyC\n6mMkOYTIeBtyW/wXFc1+GzJxtvA3C9HjilE+O/7gLHfCLP6FRIxg/9kOLhEj64Ed\n5HZ3sylvifXXubS/lLZr6sZW6d9ICoYLZpFw9AoF2zaYWpvJqBrWinnCJzvbMCYj\nfq/RAkcQYSxkDOHquiGgbRZHGAMKLnz5fMKJIzBtdQojYCUmB14OArW+ITUE9i2a\nPAJaXEGZ+BHYp/0ScFaXwp5LIgT1S+sPKxWJU//77wQfs25i7NZHSN/jtXVmsFS6\nLFVw49LcWAz3J2Im+A+uSd8CAwEAAQ==\n-----END PUBLIC KEY-----\n" + }, + "summary" : "I'm a group about Bernie2020. Follow me to get all the group posts. Tag me to share with the group. Create other groups by searching for or tagging @yourGroupName@gup.pe", + "type" : "Group" +} diff --git a/test/fixtures/image.gif b/test/fixtures/image.gif Binary files differnew file mode 100755 index 000000000..9df64778b --- /dev/null +++ b/test/fixtures/image.gif diff --git a/test/fixtures/image.png b/test/fixtures/image.png Binary files differnew file mode 100755 index 000000000..e999e8800 --- /dev/null +++ b/test/fixtures/image.png diff --git a/test/fixtures/incoming_note_activity.xml b/test/fixtures/incoming_note_activity.xml deleted file mode 100644 index 21eda2d30..000000000 --- a/test/fixtures/incoming_note_activity.xml +++ /dev/null @@ -1,42 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?><entry xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:georss="http://www.georss.org/georss" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:media="http://purl.org/syndication/atommedia" xmlns:statusnet="http://status.net/schema/api/1/"> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:gs.example.org:4040,2017-04-23:noticeId=29:objectType=note</id> - <title>New note by lambda</title> - <content type="html">@<a href="http://pleroma.example.org:4000/users/lain3" class="h-card mention">lain3</a></content> - <link rel="alternate" type="text/html" href="http://gs.example.org:4040/index.php/notice/29"/> - <link name="marko" rel="emoji" href="marko.png" /> - <link name="reimu" rel="emoji" href="reimu.png" /> - <status_net notice_id="29"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-04-23T14:51:03+00:00</published> - <updated>2017-04-23T14:51:03+00:00</updated> - <author> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>http://gs.example.org:4040/index.php/user/1</uri> - <name>lambda</name> - <link rel="alternate" type="text/html" href="http://gs.example.org:4040/index.php/lambda"/> - <link rel="avatar" type="image/png" media:width="96" media:height="96" href="http://gs.example.org:4040/theme/neo-gnu/default-avatar-profile.png"/> - <link rel="avatar" type="image/png" media:width="48" media:height="48" href="http://gs.example.org:4040/theme/neo-gnu/default-avatar-stream.png"/> - <link rel="avatar" type="image/png" media:width="24" media:height="24" href="http://gs.example.org:4040/theme/neo-gnu/default-avatar-mini.png"/> - <poco:preferredUsername>lambda</poco:preferredUsername> - <poco:displayName>lambda</poco:displayName> - <followers url="http://gs.example.org:4040/index.php/lambda/subscribers"></followers> - <statusnet:profile_info local_id="1"></statusnet:profile_info> - </author> - <link rel="ostatus:conversation" href="tag:gs.example.org:4040,2017-04-23:objectType=thread:nonce=f09e22f58abd5c7b"/> - <ostatus:conversation>tag:gs.example.org:4040,2017-04-23:objectType=thread:nonce=f09e22f58abd5c7b</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="http://pleroma.example.org:4000/users/lain3"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <source> - <id>http://gs.example.org:4040/index.php/api/statuses/user_timeline/1.atom</id> - <title>lambda</title> - <link rel="alternate" type="text/html" href="http://gs.example.org:4040/index.php/lambda"/> - <link rel="self" type="application/atom+xml" href="http://gs.example.org:4040/index.php/api/statuses/user_timeline/1.atom"/> - <link rel="license" href="https://creativecommons.org/licenses/by/3.0/"/> - <icon>http://gs.example.org:4040/theme/neo-gnu/default-avatar-profile.png</icon> - <updated>2017-04-23T14:51:03+00:00</updated> - </source> - <link rel="self" type="application/atom+xml" href="http://gs.example.org:4040/index.php/api/statuses/show/29.atom"/> - <link rel="edit" type="application/atom+xml" href="http://gs.example.org:4040/index.php/api/statuses/show/29.atom"/> - <statusnet:notice_info local_id="29" source="web"></statusnet:notice_info> -</entry> diff --git a/test/fixtures/incoming_note_activity_answer.xml b/test/fixtures/incoming_note_activity_answer.xml deleted file mode 100644 index b1244faa6..000000000 --- a/test/fixtures/incoming_note_activity_answer.xml +++ /dev/null @@ -1,42 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?><entry xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:georss="http://www.georss.org/georss" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:media="http://purl.org/syndication/atommedia" xmlns:statusnet="http://status.net/schema/api/1/"> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:gs.example.org:4040,2017-04-25:noticeId=55:objectType=note</id> - <title>New note by lambda</title> - <content type="html">hey.</content> - <link rel="alternate" type="text/html" href="http://gs.example.org:4040/index.php/notice/55"/> - <status_net notice_id="55"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-04-25T18:16:13+00:00</published> - <updated>2017-04-25T18:16:13+00:00</updated> - <author> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>http://gs.example.org:4040/index.php/user/1</uri> - <name>lambda</name> - <link rel="alternate" type="text/html" href="http://gs.example.org:4040/index.php/lambda"/> - <link rel="avatar" type="image/png" media:width="96" media:height="96" href="http://gs.example.org:4040/theme/neo-gnu/default-avatar-profile.png"/> - <link rel="avatar" type="image/png" media:width="48" media:height="48" href="http://gs.example.org:4040/theme/neo-gnu/default-avatar-stream.png"/> - <link rel="avatar" type="image/png" media:width="24" media:height="24" href="http://gs.example.org:4040/theme/neo-gnu/default-avatar-mini.png"/> - <poco:preferredUsername>lambda</poco:preferredUsername> - <poco:displayName>lambda</poco:displayName> - <followers url="http://gs.example.org:4040/index.php/lambda/subscribers"></followers> - <statusnet:profile_info local_id="1"></statusnet:profile_info> - </author> - <thr:in-reply-to ref="http://pleroma.example.org:4000/objects/55bce8fc-b423-46b1-af71-3759ab4670bc" href="http://pleroma.example.org:4000/objects/55bce8fc-b423-46b1-af71-3759ab4670bc"></thr:in-reply-to> - <link rel="related" href="http://pleroma.example.org:4000/objects/55bce8fc-b423-46b1-af71-3759ab4670bc"/> - <link rel="ostatus:conversation" href="http://pleroma.example.org:4000/contexts/8f6f45d4-8e4d-4e1a-a2de-09f27367d2d0"/> - <ostatus:conversation>http://pleroma.example.org:4000/contexts/8f6f45d4-8e4d-4e1a-a2de-09f27367d2d0</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="http://pleroma.example.org:4000/users/lain5"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <source> - <id>http://gs.example.org:4040/index.php/api/statuses/user_timeline/1.atom</id> - <title>lambda</title> - <link rel="alternate" type="text/html" href="http://gs.example.org:4040/index.php/lambda"/> - <link rel="self" type="application/atom+xml" href="http://gs.example.org:4040/index.php/api/statuses/user_timeline/1.atom"/> - <link rel="license" href="https://creativecommons.org/licenses/by/3.0/"/> - <icon>http://gs.example.org:4040/theme/neo-gnu/default-avatar-profile.png</icon> - <updated>2017-04-25T18:16:13+00:00</updated> - </source> - <link rel="self" type="application/atom+xml" href="http://gs.example.org:4040/index.php/api/statuses/show/55.atom"/> - <link rel="edit" type="application/atom+xml" href="http://gs.example.org:4040/index.php/api/statuses/show/55.atom"/> - <statusnet:notice_info local_id="55" source="web"></statusnet:notice_info> -</entry> diff --git a/test/fixtures/incoming_reply_mastodon.xml b/test/fixtures/incoming_reply_mastodon.xml deleted file mode 100644 index 8ee1186cc..000000000 --- a/test/fixtures/incoming_reply_mastodon.xml +++ /dev/null @@ -1,29 +0,0 @@ -<?xml version="1.0"?> -<entry xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:media="http://purl.org/syndication/atommedia" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:mastodon="http://mastodon.social/schema/1.0"> - <id>tag:mastodon.social,2017-05-02:objectId=4901603:objectType=Status</id> - <published>2017-05-02T18:33:06Z</published> - <updated>2017-05-02T18:33:06Z</updated> - <title>New status by lambadalambda</title> - <author> - <id>https://mastodon.social/users/lambadalambda</id> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://mastodon.social/users/lambadalambda</uri> - <name>lambadalambda</name> - <email>lambadalambda@mastodon.social</email> - <link rel="alternate" type="text/html" href="https://mastodon.social/@lambadalambda"/> - <link rel="avatar" type="image/gif" media:width="120" media:height="120" href="https://files.mastodon.social/accounts/avatars/000/000/264/original/1429214160519.gif"/> - <link rel="header" type="" media:width="700" media:height="335" href="/headers/original/missing.png"/> - <poco:preferredUsername>lambadalambda</poco:preferredUsername> - <poco:displayName>Critical Value</poco:displayName> - <mastodon:scope>public</mastodon:scope> - </author> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="el"><p><span class="h-card"><a href="https://pleroma.soykaf.com/users/lain" class="u-url mention">@<span>lain</span></a></span> hey</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://pleroma.soykaf.com/users/lain"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/2224923"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/2224923.atom"/> - <thr:in-reply-to ref="https://pleroma.soykaf.com/objects/c237d966-ac75-4fe3-a87a-d89d71a3a7a4" href=""/> -</entry> diff --git a/test/fixtures/incoming_websub_gnusocial_attachments.xml b/test/fixtures/incoming_websub_gnusocial_attachments.xml deleted file mode 100644 index 9d331ef32..000000000 --- a/test/fixtures/incoming_websub_gnusocial_attachments.xml +++ /dev/null @@ -1,59 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:georss="http://www.georss.org/georss" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:media="http://purl.org/syndication/atommedia" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:statusnet="http://status.net/schema/api/1/"> - <generator uri="https://gnu.io/social" version="1.0.2-dev">GNU social</generator> - <id>https://social.heldscal.la/api/statuses/user_timeline/23211.atom</id> - <title>lambadalambda timeline</title> - <subtitle>Updates from lambadalambda on social.heldscal.la!</subtitle> - <logo>https://social.heldscal.la/avatar/23211-96-20170416114255.jpeg</logo> - <updated>2017-05-02T20:29:35+00:00</updated> -<author> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://social.heldscal.la/user/23211</uri> - <name>lambadalambda</name> - <summary>Call me Deacon Blues.</summary> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/lambadalambda"/> - <link rel="avatar" type="image/jpeg" media:width="236" media:height="236" href="https://social.heldscal.la/avatar/23211-original-20170416114255.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/23211-96-20170416114255.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="48" media:height="48" href="https://social.heldscal.la/avatar/23211-48-20170416114255.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="24" media:height="24" href="https://social.heldscal.la/avatar/23211-24-20170416114257.jpeg"/> - <poco:preferredUsername>lambadalambda</poco:preferredUsername> - <poco:displayName>Constance Variable</poco:displayName> - <poco:note>Call me Deacon Blues.</poco:note> - <poco:address> - <poco:formatted>Berlin</poco:formatted> - </poco:address> - <poco:urls> - <poco:type>homepage</poco:type> - <poco:value>https://heldscal.la</poco:value> - <poco:primary>true</poco:primary> - </poco:urls> - <followers url="https://social.heldscal.la/lambadalambda/subscribers"></followers> - <statusnet:profile_info local_id="23211"></statusnet:profile_info> -</author> - <link href="https://social.heldscal.la/lambadalambda" rel="alternate" type="text/html"/> - <link href="https://social.heldscal.la/main/sup" rel="http://api.friendfeed.com/2008/03#sup" type="application/json"/> - <link href="https://social.heldscal.la/main/push/hub" rel="hub"/> - <link href="https://social.heldscal.la/main/salmon/user/23211" rel="salmon"/> - <link href="https://social.heldscal.la/main/salmon/user/23211" rel="http://salmon-protocol.org/ns/salmon-replies"/> - <link href="https://social.heldscal.la/main/salmon/user/23211" rel="http://salmon-protocol.org/ns/salmon-mention"/> - <link href="https://social.heldscal.la/api/statuses/user_timeline/23211.atom" rel="self" type="application/atom+xml"/> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:social.heldscal.la,2017-05-02:noticeId=2020923:objectType=note</id> - <title>New note by lambadalambda</title> - <content type="html">Okay gonna stream some cool games!! <a href="https://social.heldscal.la/file/7ed5ee508e6376a6e3dd581e17e7ed0b7b638147c7e86784bf83abc2641ee3d4.gif" title="https://social.heldscal.la/file/7ed5ee508e6376a6e3dd581e17e7ed0b7b638147c7e86784bf83abc2641ee3d4.gif" rel="nofollow external noreferrer" class="attachment" id="attachment-423842">https://social.heldscal.la/attachment/423842</a> <a href="https://social.heldscal.la/file/4c209099cadfc5afd3e27a334aa0db96b3a7510dde1603305d68a2707e59a11f.png" title="https://social.heldscal.la/file/4c209099cadfc5afd3e27a334aa0db96b3a7510dde1603305d68a2707e59a11f.png" rel="nofollow external noreferrer" class="attachment" id="attachment-423843">https://social.heldscal.la/attachment/423843</a></content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2020923"/> - <status_net notice_id="2020923"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-05-02T20:29:35+00:00</published> - <updated>2017-05-02T20:29:35+00:00</updated> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1038558"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/1038558" local_id="1038558" ref="tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=26c7afdcbcf4ebd4">tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=26c7afdcbcf4ebd4</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="enclosure" href="https://social.heldscal.la/file/7ed5ee508e6376a6e3dd581e17e7ed0b7b638147c7e86784bf83abc2641ee3d4.gif" type="image/gif" length="17283"/> - <link rel="enclosure" href="https://social.heldscal.la/file/4c209099cadfc5afd3e27a334aa0db96b3a7510dde1603305d68a2707e59a11f.png" type="image/png" length="6965"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2020923.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2020923.atom"/> - <statusnet:notice_info local_id="2020923" source="Pleroma FE"></statusnet:notice_info> -</entry> -</feed> diff --git a/test/fixtures/lambadalambda.atom b/test/fixtures/lambadalambda.atom deleted file mode 100644 index 964a416f7..000000000 --- a/test/fixtures/lambadalambda.atom +++ /dev/null @@ -1,479 +0,0 @@ -<?xml version="1.0"?> -<feed xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:media="http://purl.org/syndication/atommedia" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:mastodon="http://mastodon.social/schema/1.0"> - <id>https://mastodon.social/users/lambadalambda.atom</id> - <title>Critical Value</title> - <subtitle></subtitle> - <updated>2017-04-16T21:47:25Z</updated> - <logo>https://files.mastodon.social/accounts/avatars/000/000/264/original/1429214160519.gif?1492379244</logo> - <author> - <id>https://mastodon.social/users/lambadalambda</id> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://mastodon.social/users/lambadalambda</uri> - <name>lambadalambda</name> - <email>lambadalambda@mastodon.social</email> - <summary>a cool dude.</summary> - <link rel="alternate" type="text/html" href="https://mastodon.social/@lambadalambda"/> - <link rel="avatar" type="image/gif" media:width="120" media:height="120" href="https://files.mastodon.social/accounts/avatars/000/000/264/original/1429214160519.gif?1492379244"/> - <link rel="header" type="" media:width="700" media:height="335" href="/headers/original/missing.png"/> - <poco:preferredUsername>lambadalambda</poco:preferredUsername> - <poco:displayName>Critical Value</poco:displayName> - <mastodon:scope>public</mastodon:scope> - </author> - <link rel="alternate" type="text/html" href="https://mastodon.social/@lambadalambda"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda.atom"/> - <link rel="next" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda.atom?max_id=1488609"/> - <link rel="hub" href="https://mastodon.social/api/push"/> - <link rel="salmon" href="https://mastodon.social/api/salmon/264"/> - <entry> - <id>tag:mastodon.social,2017-04-07:objectId=1874242:objectType=Status</id> - <published>2017-04-07T11:02:56Z</published> - <updated>2017-04-07T11:02:56Z</updated> - <title>lambadalambda shared a status by 0xroy@social.wxcafe.net</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb> - <activity:object> - <id>tag:social.wxcafe.net,2017-04-07:objectId=72554:objectType=Status</id> - <published>2017-04-07T11:01:59Z</published> - <updated>2017-04-07T11:02:00Z</updated> - <title>New status by 0xroy@social.wxcafe.net</title> - <author> - <id>https://social.wxcafe.net/users/0xroy</id> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://social.wxcafe.net/users/0xroy</uri> - <name>0xroy</name> - <email>0xroy@social.wxcafe.net</email> - <summary>ta caution weeb | discussions privées : <a href="https://💌.0xroy.me" rel="nofollow noopener" target="_blank"><span class="invisible">https://</span><span class="">💌.0xroy.me</span><span class="invisible"></span></a></summary> - <link rel="alternate" type="text/html" href="https://social.wxcafe.net/@0xroy"/> - <link rel="avatar" type="image/jpeg" media:width="120" media:height="120" href="https://files.mastodon.social/accounts/avatars/000/036/953/original/20068e41d0310172.jpg?1491240516"/> - <link rel="header" type="image/jpeg" media:width="700" media:height="335" href="https://files.mastodon.social/accounts/headers/000/036/953/original/2229d0e3f129fe8c.jpg?1491381114"/> - <poco:preferredUsername>0xroy</poco:preferredUsername> - <poco:displayName>「R O Y 🍵 B O S」</poco:displayName> - <poco:note>ta caution weeb | discussions privées : <a href="https://%F0%9F%92%8C.0xroy.me" rel="nofollow noopener"><span class="invisible">https://</span><span class="">💌.0xroy.me</span><span class="invisible"></span></a></poco:note> - <mastodon:scope>public</mastodon:scope> - </author> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="en"><p>someone pls eli5 matrix (protocol) and riot</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://social.wxcafe.net/users/0xroy/updates/4510"/> - </activity:object> - <content type="html" xml:lang="en"><p>someone pls eli5 matrix (protocol) and riot</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/1689208"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/1689208.atom"/> - </entry> - <entry> - <id>tag:mastodon.social,2017-04-06:objectId=1768247:objectType=Status</id> - <published>2017-04-06T11:10:19Z</published> - <updated>2017-04-06T11:10:19Z</updated> - <title>lambadalambda shared a status by areyoutoo@mastodon.xyz</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb> - <activity:object> - <id>tag:mastodon.xyz,2017-04-05:objectId=133327:objectType=Status</id> - <published>2017-04-05T17:36:41Z</published> - <updated>2017-04-05T18:12:14Z</updated> - <title>New status by areyoutoo@mastodon.xyz</title> - <author> - <id>https://mastodon.xyz/users/areyoutoo</id> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://mastodon.xyz/users/areyoutoo</uri> - <name>areyoutoo</name> - <email>areyoutoo@mastodon.xyz</email> - <summary>devops | retired gamedev | always boost puppy pics</summary> - <link rel="alternate" type="text/html" href="https://mastodon.xyz/@areyoutoo"/> - <link rel="avatar" type="image/png" media:width="120" media:height="120" href="https://files.mastodon.social/accounts/avatars/000/047/888/original/5ce2e132d4c18d65.png?1491343828"/> - <link rel="header" type="image/png" media:width="700" media:height="335" href="https://files.mastodon.social/accounts/headers/000/047/888/original/missing.png?1491336769"/> - <poco:preferredUsername>areyoutoo</poco:preferredUsername> - <poco:displayName>Raw Butter</poco:displayName> - <poco:note>devops | retired gamedev | always boost puppy pics</poco:note> - <mastodon:scope>public</mastodon:scope> - </author> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="en"><p>Some UX thoughts for <a href="https://mastodon.xyz/tags/mastodev" class="mention hashtag">#<span>mastodev</span></a>:</p><p>- Would be nice if I could work on multiple draft toots? Clicking to reply to someone seems to erase any draft I had been working on.</p><p>- Kinda risky to click on the Federated Timeline if it loads new toots and scrolls 10ms before I click on something.</p><p>I probably don't know enough web frontend to help, but it might be fun to try.</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <category term="mastodev"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.xyz/users/areyoutoo/updates/36028"/> - </activity:object> - <content type="html" xml:lang="en"><p>Some UX thoughts for <a href="https://mastodon.xyz/tags/mastodev" class="mention hashtag">#<span>mastodev</span></a>:</p><p>- Would be nice if I could work on multiple draft toots? Clicking to reply to someone seems to erase any draft I had been working on.</p><p>- Kinda risky to click on the Federated Timeline if it loads new toots and scrolls 10ms before I click on something.</p><p>I probably don't know enough web frontend to help, but it might be fun to try.</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/1658950"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/1658950.atom"/> - </entry> - <entry> - <id>tag:mastodon.social,2017-04-06:objectId=1764509:objectType=Status</id> - <published>2017-04-06T10:15:38Z</published> - <updated>2017-04-06T10:15:38Z</updated> - <title>New status by lambadalambda</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <summary xml:lang="en">This is a test for cw federation</summary> - <content type="html" xml:lang="en"><p>This is a test for cw federation body text.</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/1657819"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/1657819.atom"/> - </entry> - <entry> - <id>tag:mastodon.social,2017-04-05:objectId=1645208:objectType=Status</id> - <published>2017-04-05T07:14:53Z</published> - <updated>2017-04-05T07:14:53Z</updated> - <title>lambadalambda shared a status by lambadalambda@social.heldscal.la</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb> - <activity:object> - <id>tag:social.heldscal.la,2017-04-05:noticeId=1502088:objectType=note</id> - <published>2017-04-05T06:12:09Z</published> - <updated>2017-04-05T07:12:47Z</updated> - <title>New status by lambadalambda@social.heldscal.la</title> - <author> - <id>https://social.heldscal.la/user/23211</id> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://social.heldscal.la/user/23211</uri> - <name>lambadalambda</name> - <email>lambadalambda@social.heldscal.la</email> - <summary>Call me Deacon Blues.</summary> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/lambadalambda"/> - <link rel="avatar" type="image/jpeg" media:width="120" media:height="120" href="https://files.mastodon.social/accounts/avatars/000/000/236/original/23211-original-20170416114255.jpeg?1492345317"/> - <link rel="header" type="" media:width="700" media:height="335" href="/headers/original/missing.png"/> - <poco:preferredUsername>lambadalambda</poco:preferredUsername> - <poco:displayName>Constance Variable</poco:displayName> - <poco:note>Call me Deacon Blues.</poco:note> - <mastodon:scope>public</mastodon:scope> - </author> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="en">Federation 101: <a href="https://www.youtube.com/watch?v=t1lYU5CA40o" rel="nofollow external noreferrer" class="attachment thumbnail">https://www.youtube.com/watch?v=t1lYU5CA40o</a></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/1502088"/> - </activity:object> - <content type="html" xml:lang="en">Federation 101: <a href="https://www.youtube.com/watch?v=t1lYU5CA40o" rel="nofollow external noreferrer" class="attachment thumbnail">https://www.youtube.com/watch?v=t1lYU5CA40o</a></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/1618003"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/1618003.atom"/> - </entry> - <entry> - <id>tag:mastodon.social,2017-04-05:objectId=1641750:objectType=Status</id> - <published>2017-04-05T05:44:48Z</published> - <updated>2017-04-05T05:44:48Z</updated> - <title>New status by lambadalambda</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="en"><p><span class="h-card"><a href="https://social.heldscal.la/lambadalambda" class="u-url mention">@<span>lambadalambda</span></a></span> just a test.</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://social.heldscal.la/user/23211"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/1616358"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/1616358.atom"/> - </entry> - <entry> - <id>tag:mastodon.social,2017-04-04:objectId=1540149:objectType=Status</id> - <published>2017-04-04T06:31:09Z</published> - <updated>2017-04-04T06:31:09Z</updated> - <title>New status by lambadalambda</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="en"><p>Looks like you still can&apos;t delete your account here (PRIVACY!), but I won&apos;t be posting here anymore, my main account is <span class="h-card"><a href="https://social.heldscal.la/lambadalambda" class="u-url mention">@<span>lambadalambda</span></a></span></p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://social.heldscal.la/user/23211"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/1559641"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/1559641.atom"/> - </entry> - <entry> - <id>tag:mastodon.social,2017-04-04:objectId=1539608:objectType=Status</id> - <published>2017-04-04T06:18:16Z</published> - <updated>2017-04-04T06:18:16Z</updated> - <title>New status by lambadalambda</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="en"><p><span class="h-card"><a href="https://mastodon.social/@ghostbar" class="u-url mention">@<span>ghostbar</span></a></span> Remember to rewrite it in Rust once you&apos;re done.</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.social/users/ghostbar"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/1559263"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/1559263.atom"/> - <thr:in-reply-to ref="tag:mastodon.social,2017-04-03:objectId=1514426:objectType=Status" href="https://mastodon.social/@ghostbar/1514426"/> - </entry> - <entry> - <id>tag:mastodon.social,2017-04-03:objectId=1504813:objectType=Status</id> - <published>2017-04-03T18:01:20Z</published> - <updated>2017-04-03T18:01:20Z</updated> - <title>New status by lambadalambda</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="en"><p><span class="h-card"><a href="https://mastodon.xyz/@Azurolu" class="u-url mention">@<span>Azurolu</span></a></span> You mean gs.smuglo.li?</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.xyz/users/Azurolu"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/1535844"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/1535844.atom"/> - <thr:in-reply-to ref="tag:mastodon.xyz,2017-04-03:objectId=21879:objectType=Status" href="https://mastodon.xyz/users/Azurolu/updates/3813"/> - </entry> - <entry> - <id>tag:mastodon.social,2017-04-03:objectId=1504805:objectType=Status</id> - <published>2017-04-03T18:01:05Z</published> - <updated>2017-04-03T18:01:05Z</updated> - <title>New status by lambadalambda</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="en"><p>There&apos;s nothing wrong with having several alt accounts all across the fediverse. Try out another mastodon instance (<a href="https://icosahedron.website" rel="nofollow noopener" target="_blank"><span class="invisible">https://</span><span class="">icosahedron.website</span><span class="invisible"></span></a>) or a GNU Social instance (like <a href="https://shitposter.club" rel="nofollow noopener" target="_blank"><span class="invisible">https://</span><span class="">shitposter.club</span><span class="invisible"></span></a> or <a href="https://freezepeach.xyz" rel="nofollow noopener" target="_blank"><span class="invisible">https://</span><span class="">freezepeach.xyz</span><span class="invisible"></span></a>), or friendica. They are all on the same network, so you can still follow all your friends!</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/1535837"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/1535837.atom"/> - </entry> - <entry> - <id>tag:mastodon.social,2017-04-03:objectId=1503965:objectType=Status</id> - <published>2017-04-03T17:31:30Z</published> - <updated>2017-04-03T17:31:30Z</updated> - <title>New status by lambadalambda</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="en"><p><span class="h-card"><a href="https://mastodon.social/@20Hz" class="u-url mention">@<span>20Hz</span></a></span> you could also try out a GS instance, which are on the same network :)</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.social/users/20Hz"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/1535176"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/1535176.atom"/> - <thr:in-reply-to ref="tag:mastodon.social,2017-04-03:objectId=1503524:objectType=Status" href="https://mastodon.social/@20Hz/1503524"/> - </entry> - <entry> - <id>tag:mastodon.social,2017-04-03:objectId=1503955:objectType=Status</id> - <published>2017-04-03T17:31:08Z</published> - <updated>2017-04-03T17:31:08Z</updated> - <title>lambadalambda shared a status by shpuld@shitposter.club</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb> - <activity:object> - <id>tag:shitposter.club,2017-04-03:noticeId=2251717:objectType=note</id> - <published>2017-04-03T17:06:43Z</published> - <updated>2017-04-03T17:12:06Z</updated> - <title>New status by shpuld@shitposter.club</title> - <author> - <id>https://shitposter.club/user/5381</id> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://shitposter.club/user/5381</uri> - <name>shpuld</name> - <email>shpuld@shitposter.club</email> - <summary></summary> - <link rel="alternate" type="text/html" href="https://shitposter.club/shpuld"/> - <link rel="avatar" type="image/jpeg" media:width="120" media:height="120" href="https://files.mastodon.social/accounts/avatars/000/005/895/original/5381-original-20170401213417.jpeg?1491082522"/> - <link rel="header" type="" media:width="700" media:height="335" href="/headers/original/missing.png"/> - <poco:preferredUsername>shpuld</poco:preferredUsername> - <poco:displayName>shp</poco:displayName> - <mastodon:scope>public</mastodon:scope> - </author> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="en">reposting the classic <a href="https://shitposter.club/file/89c5fe483526caf3a46cfc5cdd4ae68061054350e767397731af658d54786e31.jpg" class="attachment" rel="nofollow external">https://shitposter.club/attachment/219846</a></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="enclosure" type="image/jpeg" length="30588" href="https://files.mastodon.social/media_attachments/files/000/156/256/original/89c5fe483526caf3a46cfc5cdd4ae68061054350e767397731af658d54786e31.jpg"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2251717"/> - </activity:object> - <content type="html" xml:lang="en">reposting the classic <a href="https://shitposter.club/file/89c5fe483526caf3a46cfc5cdd4ae68061054350e767397731af658d54786e31.jpg" class="attachment" rel="nofollow external">https://shitposter.club/attachment/219846</a></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/1535166"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/1535166.atom"/> - </entry> - <entry> - <id>tag:mastodon.social,2017-04-03:objectId=1503929:objectType=Status</id> - <published>2017-04-03T17:30:43Z</published> - <updated>2017-04-03T17:30:43Z</updated> - <title>New status by lambadalambda</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="en"><p><span class="h-card"><a href="https://mastodon.social/@ghostbar" class="u-url mention">@<span>ghostbar</span></a></span> Normally you shouldn&apos;t be running tens of thousands of users on one instance... That&apos;s one of the reasons for federation.</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.social/users/ghostbar"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/1535144"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/1535144.atom"/> - <thr:in-reply-to ref="tag:mastodon.social,2017-04-03:objectId=1503526:objectType=Status" href="https://mastodon.social/@ghostbar/1503526"/> - </entry> - <entry> - <id>tag:mastodon.social,2017-04-03:objectId=1477255:objectType=Status</id> - <published>2017-04-03T08:24:39Z</published> - <updated>2017-04-03T08:24:39Z</updated> - <title>New status by lambadalambda</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="en"><p><span class="h-card"><a href="https://mastodon.social/@dot_tiff" class="u-url mention">@<span>dot_tiff</span></a></span> it&apos;s the vaporwave mode.</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.social/users/dot_tiff"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/1513305"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/1513305.atom"/> - <thr:in-reply-to ref="tag:mastodon.social,2017-04-03:objectId=1477220:objectType=Status" href="https://mastodon.social/@dot_tiff/1477220"/> - </entry> - <entry> - <id>tag:mastodon.social,2017-04-03:objectId=1476210:objectType=Status</id> - <published>2017-04-03T07:45:42Z</published> - <updated>2017-04-03T07:45:42Z</updated> - <title>lambadalambda shared a status by lambadalambda@social.heldscal.la</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb> - <activity:object> - <id>tag:social.heldscal.la,2017-04-03:noticeId=1475727:objectType=note</id> - <published>2017-04-03T07:44:43Z</published> - <updated>2017-04-03T07:44:48Z</updated> - <title>New status by lambadalambda@social.heldscal.la</title> - <author> - <id>https://social.heldscal.la/user/23211</id> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://social.heldscal.la/user/23211</uri> - <name>lambadalambda</name> - <email>lambadalambda@social.heldscal.la</email> - <summary>Call me Deacon Blues.</summary> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/lambadalambda"/> - <link rel="avatar" type="image/jpeg" media:width="120" media:height="120" href="https://files.mastodon.social/accounts/avatars/000/000/236/original/23211-original-20170416114255.jpeg?1492345317"/> - <link rel="header" type="" media:width="700" media:height="335" href="/headers/original/missing.png"/> - <poco:preferredUsername>lambadalambda</poco:preferredUsername> - <poco:displayName>Constance Variable</poco:displayName> - <poco:note>Call me Deacon Blues.</poco:note> - <mastodon:scope>public</mastodon:scope> - </author> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="en">Here's a song by the original anti-idol, Togawa Jun: <a href="https://www.youtube.com/watch?v=kNI_NK2YY-s" rel="nofollow external noreferrer" class="attachment">https://www.youtube.com/watch?v=kNI_NK2YY-s</a></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/1475727"/> - </activity:object> - <content type="html" xml:lang="en">Here's a song by the original anti-idol, Togawa Jun: <a href="https://www.youtube.com/watch?v=kNI_NK2YY-s" rel="nofollow external noreferrer" class="attachment">https://www.youtube.com/watch?v=kNI_NK2YY-s</a></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/1512485"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/1512485.atom"/> - </entry> - <entry> - <id>tag:mastodon.social,2017-04-03:objectId=1476047:objectType=Status</id> - <published>2017-04-03T07:39:14Z</published> - <updated>2017-04-03T07:39:14Z</updated> - <title>New status by lambadalambda</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="en"><p><span class="h-card"><a href="https://mastodon.social/@amrrr" class="u-url mention">@<span>amrrr</span></a></span> tumblr/10, but pretty good!</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.social/users/amrrr"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/1512350"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/1512350.atom"/> - <thr:in-reply-to ref="tag:mastodon.social,2017-04-03:objectId=1476030:objectType=Status" href="https://mastodon.social/@amrrr/1476030"/> - </entry> - <entry> - <id>tag:mastodon.social,2017-04-03:objectId=1475949:objectType=Status</id> - <published>2017-04-03T07:35:45Z</published> - <updated>2017-04-03T07:35:45Z</updated> - <title>New status by lambadalambda</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="en"><p><span class="h-card"><a href="https://mastodon.social/@Shookaite" class="u-url mention">@<span>Shookaite</span></a></span> Oh, you mean like userstyles?</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.social/users/Shookaite"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/1512271"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/1512271.atom"/> - <thr:in-reply-to ref="tag:mastodon.social,2017-04-03:objectId=1475879:objectType=Status" href="https://mastodon.social/@Shookaite/1475879"/> - </entry> - <entry> - <id>tag:mastodon.social,2017-04-03:objectId=1475581:objectType=Status</id> - <published>2017-04-03T07:20:03Z</published> - <updated>2017-04-03T07:20:03Z</updated> - <title>New status by lambadalambda</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="en"><p><span class="h-card"><a href="https://mastodon.social/@Shookaite" class="u-url mention">@<span>Shookaite</span></a></span> Would be nice if someone helped port Pleroma to Mastodon, that has a theme switcher (click on the cog in the upper right): <a href="https://pleroma.heldscal.la/main/all" rel="nofollow noopener" target="_blank"><span class="invisible">https://</span><span class="">pleroma.heldscal.la/main/all</span><span class="invisible"></span></a></p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.social/users/Shookaite"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/1511987"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/1511987.atom"/> - <thr:in-reply-to ref="tag:mastodon.social,2017-04-03:objectId=1475550:objectType=Status" href="https://mastodon.social/@Shookaite/1475550"/> - </entry> - <entry> - <id>tag:mastodon.social,2017-04-02:objectId=1457325:objectType=Status</id> - <published>2017-04-02T21:57:43Z</published> - <updated>2017-04-02T21:57:43Z</updated> - <title>New status by lambadalambda</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="en"><p><span class="h-card"><a href="https://mastodon.social/@rhosyn" class="u-url mention">@<span>rhosyn</span></a></span> <span class="h-card"><a href="https://mastodon.social/@Meaningness" class="u-url mention">@<span>Meaningness</span></a></span> you could take a look at those listed at social.guhnoo.org</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.social/users/rhosyn"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.social/users/Meaningness"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/1496564"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/1496564.atom"/> - <thr:in-reply-to ref="tag:mastodon.social,2017-04-02:objectId=1449283:objectType=Status" href="https://mastodon.social/@rhosyn/1449283"/> - </entry> - <entry> - <id>tag:mastodon.social,2017-04-02:objectId=1447926:objectType=Status</id> - <published>2017-04-02T18:31:52Z</published> - <updated>2017-04-02T18:31:52Z</updated> - <title>New status by lambadalambda</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="en"><p>My main account is <span class="h-card"><a href="https://social.heldscal.la/lambadalambda" class="u-url mention">@<span>lambadalambda</span></a></span> , btw.</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://social.heldscal.la/user/23211"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/1488648"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/1488648.atom"/> - </entry> - <entry> - <id>tag:mastodon.social,2017-04-02:objectId=1447878:objectType=Status</id> - <published>2017-04-02T18:30:37Z</published> - <updated>2017-04-02T18:30:37Z</updated> - <title>lambadalambda shared a status by Firstaide@awoo.space</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb> - <activity:object> - <id>tag:awoo.space,2017-04-02:objectId=135324:objectType=Status</id> - <published>2017-04-02T18:29:32Z</published> - <updated>2017-04-02T18:29:32Z</updated> - <title>New status by Firstaide@awoo.space</title> - <author> - <id>https://awoo.space/users/Firstaide</id> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://awoo.space/users/Firstaide</uri> - <name>Firstaide</name> - <email>Firstaide@awoo.space</email> - <summary>A smol awoo account, for a smol autistic 💙 -They/them please! -NB/white/ace</summary> - <link rel="alternate" type="text/html" href="https://awoo.space/@Firstaide"/> - <link rel="avatar" type="image/png" media:width="120" media:height="120" href="https://files.mastodon.social/accounts/avatars/000/023/707/original/95e92639771fd225.png?1492022811"/> - <link rel="header" type="image/jpeg" media:width="700" media:height="335" href="https://files.mastodon.social/accounts/headers/000/023/707/original/e98df174c26747be.jpg?1491667928"/> - <poco:preferredUsername>Firstaide</poco:preferredUsername> - <poco:displayName>Miff🚑✨</poco:displayName> - <poco:note>A smol awoo account, for a smol autistic 💙 -They/them please! -NB/white/ace</poco:note> - <mastodon:scope>public</mastodon:scope> - </author> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="en"><p><a href="https://mastodon.social/users/lambadalambda" class="h-card u-url p-nickname mention">@<span>lambadalambda</span></a> yeah, I think that's p much the big issue here? <br>When I first heard of Masto, I thought it was just like twitter at first, I had no idea federation was even a thing?, and I actually joined p early on? :-o </p><p>idk I think more stuff needs to be done about federation promotion, but honestly its gotta come from the get go when people get here to make an account I feel :-o</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.social/users/lambadalambda"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://awoo.space/users/Firstaide/updates/10904"/> - <thr:in-reply-to ref="tag:mastodon.social,2017-04-02:objectId=1447682:objectType=Status" href="https://mastodon.social/@lambadalambda/1447682"/> - </activity:object> - <content type="html" xml:lang="en"><p><a href="https://mastodon.social/users/lambadalambda" class="h-card u-url p-nickname mention">@<span>lambadalambda</span></a> yeah, I think that's p much the big issue here? <br>When I first heard of Masto, I thought it was just like twitter at first, I had no idea federation was even a thing?, and I actually joined p early on? :-o </p><p>idk I think more stuff needs to be done about federation promotion, but honestly its gotta come from the get go when people get here to make an account I feel :-o</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/1488609"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/1488609.atom"/> - </entry> -</feed> diff --git a/test/fixtures/mastodon-delete.json b/test/fixtures/mastodon-delete.json index 87a582002..8559f724e 100644 --- a/test/fixtures/mastodon-delete.json +++ b/test/fixtures/mastodon-delete.json @@ -2,12 +2,9 @@ "type": "Delete", "signature": { "type": "RsaSignature2017", - "signatureValue": "cw0RlfNREf+5VdsOYcCBDrv521eiLsDTAYNHKffjF0bozhCnOh+wHkFik7WamUk$ -uEiN4L2H6vPlGRprAZGRhEwgy+A7rIFQNmLrpW5qV5UNVI/2F7kngEHqZQgbQYj9hW+5GMYmPkHdv3D72ZefGw$ -4Xa2NBLGFpAjQllfzt7kzZLKKY2DM99FdUa64I2Wj3iD04Hs23SbrUdAeuGk/c1Cg6bwGNG4vxoiwn1jikgJLA$ -NAlSGjsRGdR7LfbC7GqWWsW3cSNsLFPoU6FyALjgTrrYoHiXe0QHggw+L3yMLfzB2S/L46/VRbyb+WDKMBIXUL$ -5owmzHSi6e/ZtCI3w==", - "creator": "http://mastodon.example.org/users/gargron#main-key", "created": "2018-03-03T16:24:11Z" + "signatureValue": "cw0RlfNREf+5VdsOYcCBDrv521eiLsDTAYNHKffjF0bozhCnOh+wHkFik7WamUk$uEiN4L2H6vPlGRprAZGRhEwgy+A7rIFQNmLrpW5qV5UNVI/2F7kngEHqZQgbQYj9hW+5GMYmPkHdv3D72ZefGw$4Xa2NBLGFpAjQllfzt7kzZLKKY2DM99FdUa64I2Wj3iD04Hs23SbrUdAeuGk/c1Cg6bwGNG4vxoiwn1jikgJLA$NAlSGjsRGdR7LfbC7GqWWsW3cSNsLFPoU6FyALjgTrrYoHiXe0QHggw+L3yMLfzB2S/L46/VRbyb+WDKMBIXUL$5owmzHSi6e/ZtCI3w==", + "creator": "http://mastodon.example.org/users/gargron#main-key", + "created": "2018-03-03T16:24:11Z" }, "object": { "type": "Tombstone", diff --git a/test/fixtures/mastodon-note-cw.xml b/test/fixtures/mastodon-note-cw.xml deleted file mode 100644 index 02f49dd61..000000000 --- a/test/fixtures/mastodon-note-cw.xml +++ /dev/null @@ -1,39 +0,0 @@ -<?xml version="1.0"?> -<feed xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:media="http://purl.org/syndication/atommedia" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:mastodon="http://mastodon.social/schema/1.0"> - <id>https://mastodon.social/users/lambadalambda.atom</id> - <title>Critical Value</title> - <subtitle></subtitle> - <updated>2017-04-16T21:47:25Z</updated> - <logo>https://files.mastodon.social/accounts/avatars/000/000/264/original/1429214160519.gif</logo> - <author> - <id>https://mastodon.social/users/lambadalambda</id> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://mastodon.social/users/lambadalambda</uri> - <name>lambadalambda</name> - <email>lambadalambda@mastodon.social</email> - <link rel="alternate" type="text/html" href="https://mastodon.social/@lambadalambda"/> - <link rel="avatar" type="image/gif" media:width="120" media:height="120" href="https://files.mastodon.social/accounts/avatars/000/000/264/original/1429214160519.gif"/> - <link rel="header" type="" media:width="700" media:height="335" href="/headers/original/missing.png"/> - <poco:preferredUsername>lambadalambda</poco:preferredUsername> - <poco:displayName>Critical Value</poco:displayName> - <mastodon:scope>public</mastodon:scope> - </author> - <link rel="alternate" type="text/html" href="https://mastodon.social/@lambadalambda"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda.atom"/> - <link rel="hub" href="https://mastodon.social/api/push"/> - <link rel="salmon" href="https://mastodon.social/api/salmon/264"/> - <entry> - <id>tag:mastodon.social,2017-05-10:objectId=5551985:objectType=Status</id> - <published>2017-05-10T12:21:36Z</published> - <updated>2017-05-10T12:21:36Z</updated> - <title>New status by lambadalambda</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <summary xml:lang="sv">technologic</summary> - <content type="html" xml:lang="sv"><p>test</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/2314748"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/2314748.atom"/> - </entry> -</feed> diff --git a/test/fixtures/mastodon-note-unlisted.xml b/test/fixtures/mastodon-note-unlisted.xml deleted file mode 100644 index d21017b80..000000000 --- a/test/fixtures/mastodon-note-unlisted.xml +++ /dev/null @@ -1,38 +0,0 @@ -<?xml version="1.0"?> -<feed xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:media="http://purl.org/syndication/atommedia" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:mastodon="http://mastodon.social/schema/1.0"> - <id>https://mastodon.social/users/lambadalambda.atom</id> - <title>Critical Value</title> - <subtitle></subtitle> - <updated>2017-04-16T21:47:25Z</updated> - <logo>https://files.mastodon.social/accounts/avatars/000/000/264/original/1429214160519.gif</logo> - <author> - <id>https://mastodon.social/users/lambadalambda</id> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://mastodon.social/users/lambadalambda</uri> - <name>lambadalambda</name> - <email>lambadalambda@mastodon.social</email> - <link rel="alternate" type="text/html" href="https://mastodon.social/@lambadalambda"/> - <link rel="avatar" type="image/gif" media:width="120" media:height="120" href="https://files.mastodon.social/accounts/avatars/000/000/264/original/1429214160519.gif"/> - <link rel="header" type="" media:width="700" media:height="335" href="/headers/original/missing.png"/> - <poco:preferredUsername>lambadalambda</poco:preferredUsername> - <poco:displayName>Critical Value</poco:displayName> - <mastodon:scope>public</mastodon:scope> - </author> - <link rel="alternate" type="text/html" href="https://mastodon.social/@lambadalambda"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda.atom"/> - <link rel="hub" href="https://mastodon.social/api/push"/> - <link rel="salmon" href="https://mastodon.social/api/salmon/264"/> - <entry> - <id>tag:mastodon.social,2017-05-10:objectId=5551985:objectType=Status</id> - <published>2017-05-10T12:21:36Z</published> - <updated>2017-05-10T12:21:36Z</updated> - <title>New status by lambadalambda</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <summary xml:lang="sv">technologic</summary> - <content type="html" xml:lang="sv"><p>test</p></content> - <mastodon:scope>unlisted</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/2314748"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/2314748.atom"/> - </entry> -</feed> diff --git a/test/fixtures/mastodon-post-activity-nsfw.json b/test/fixtures/mastodon-post-activity-nsfw.json new file mode 100644 index 000000000..70729a1bd --- /dev/null +++ b/test/fixtures/mastodon-post-activity-nsfw.json @@ -0,0 +1,68 @@ +{ + "@context": [ + "https://www.w3.org/ns/activitystreams", + "https://w3id.org/security/v1", + { + "Emoji": "toot:Emoji", + "Hashtag": "as:Hashtag", + "atomUri": "ostatus:atomUri", + "conversation": "ostatus:conversation", + "inReplyToAtomUri": "ostatus:inReplyToAtomUri", + "manuallyApprovesFollowers": "as:manuallyApprovesFollowers", + "movedTo": "as:movedTo", + "ostatus": "http://ostatus.org#", + "toot": "http://joinmastodon.org/ns#" + } + ], + "actor": "http://mastodon.example.org/users/admin", + "cc": [ + "http://mastodon.example.org/users/admin/followers", + "http://localtesting.pleroma.lol/users/lain" + ], + "id": "http://mastodon.example.org/users/admin/statuses/99512778738411822/activity", + "nickname": "lain", + "object": { + "atomUri": "http://mastodon.example.org/users/admin/statuses/99512778738411822", + "attachment": [], + "attributedTo": "http://mastodon.example.org/users/admin", + "cc": [ + "http://mastodon.example.org/users/admin/followers", + "http://localtesting.pleroma.lol/users/lain" + ], + "content": "<p><span class=\"h-card\"><a href=\"http://localtesting.pleroma.lol/users/lain\" class=\"u-url mention\">@<span>lain</span></a></span> #moo</p>", + "conversation": "tag:mastodon.example.org,2018-02-12:objectId=20:objectType=Conversation", + "id": "http://mastodon.example.org/users/admin/statuses/99512778738411822", + "inReplyTo": null, + "inReplyToAtomUri": null, + "published": "2018-02-12T14:08:20Z", + "summary": "cw", + "tag": [ + { + "href": "http://localtesting.pleroma.lol/users/lain", + "name": "@lain@localtesting.pleroma.lol", + "type": "Mention" + }, + { + "href": "http://mastodon.example.org/tags/nsfw", + "name": "#NSFW", + "type": "Hashtag" + } + ], + "to": [ + "https://www.w3.org/ns/activitystreams#Public" + ], + "type": "Note", + "url": "http://mastodon.example.org/@admin/99512778738411822" + }, + "published": "2018-02-12T14:08:20Z", + "signature": { + "created": "2018-02-12T14:08:20Z", + "creator": "http://mastodon.example.org/users/admin#main-key", + "signatureValue": "rnNfcopkc6+Ju73P806popcfwrK9wGYHaJVG1/ZvrlEbWVDzaHjkXqj9Q3/xju5l8CSn9tvSgCCtPFqZsFQwn/pFIFUcw7ZWB2xi4bDm3NZ3S4XQ8JRaaX7og5hFxAhWkGhJhAkfxVnOg2hG+w2d/7d7vRVSC1vo5ip4erUaA/PkWusZvPIpxnRWoXaxJsFmVx0gJgjpJkYDyjaXUlp+jmaoseeZ4EPQUWqHLKJ59PRG0mg8j2xAjYH9nQaN14qMRmTGPxY8gfv/CUFcatA+8VJU9KEsJkDAwLVvglydNTLGrxpAJU78a2eaht0foV43XUIZGe3DKiJPgE+UOKGCJw==", + "type": "RsaSignature2017" + }, + "to": [ + "https://www.w3.org/ns/activitystreams#Public" + ], + "type": "Create" +} diff --git a/test/fixtures/mastodon-problematic.xml b/test/fixtures/mastodon-problematic.xml deleted file mode 100644 index a39e72759..000000000 --- a/test/fixtures/mastodon-problematic.xml +++ /dev/null @@ -1,72 +0,0 @@ -<?xml version="1.0"?> -<feed xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:media="http://purl.org/syndication/atommedia" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:mastodon="http://mastodon.social/schema/1.0"> - <id>https://icosahedron.website/users/shel.atom</id> - <title>shel🍖‼️</title> - <subtitle>Gay jackal dog, poet, future librarian. - -http://datapup.info -avatar: @puppytube@twitter.com</subtitle> - <updated>2017-05-02T23:26:01Z</updated> - <logo>https://icosahedron.website/system/accounts/avatars/000/001/207/original/b1e07b09ae1cc787.png?1493767561</logo> - <author> - <id>https://icosahedron.website/users/shel</id> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://icosahedron.website/users/shel</uri> - <name>shel</name> - <email>shel@icosahedron.website</email> - <summary type="html"><p>Gay jackal dog, poet, future librarian. </p><p><a href="http://datapup.info/" rel="nofollow noopener" target="_blank"><span class="invisible">http://</span><span class="">datapup.info/</span><span class="invisible"></span></a><br />avatar: @puppytube@twitter.com</p></summary> - <link rel="alternate" type="text/html" href="https://icosahedron.website/@shel"/> - <link rel="avatar" type="image/png" media:width="120" media:height="120" href="https://icosahedron.website/system/accounts/avatars/000/001/207/original/b1e07b09ae1cc787.png?1493767561"/> - <link rel="header" type="image/jpeg" media:width="700" media:height="335" href="https://icosahedron.website/system/accounts/headers/000/001/207/original/13e50e0ddfe359fd.jpg?1493767561"/> - <poco:preferredUsername>shel</poco:preferredUsername> - <poco:displayName>shel🍖‼️</poco:displayName> - <poco:note>Gay jackal dog, poet, future librarian. - -http://datapup.info -avatar: @puppytube@twitter.com</poco:note> - <mastodon:scope>public</mastodon:scope> - </author> - <link rel="alternate" type="text/html" href="https://icosahedron.website/@shel"/> - <link rel="self" type="application/atom+xml" href="https://icosahedron.website/users/shel.atom"/> - <link rel="hub" href="https://icosahedron.website/api/push"/> - <link rel="salmon" href="https://icosahedron.website/api/salmon/1207"/> - <entry> - <id>tag:icosahedron.website,2017-05-10:objectId=1414013:objectType=Status</id> - <published>2017-05-10T17:16:24Z</published> - <updated>2017-05-10T17:16:24Z</updated> - <title>shel shared a status by instance_names@cybre.space</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb> - <activity:object> - <id>tag:cybre.space,2017-05-10:objectId=946671:objectType=Status</id> - <published>2017-05-10T17:15:51Z</published> - <updated>2017-05-10T17:15:52Z</updated> - <title>New status by instance_names@cybre.space</title> - <author> - <id>https://cybre.space/users/instance_names</id> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://cybre.space/users/instance_names</uri> - <name>instance_names</name> - <email>instance_names@cybre.space</email> - <summary type="html"><p>name ideas for your new mastodon instance. made by <span class="h-card"><a href="https://witches.town/@lycaon">@<span>lycaon</span></a></span> source available at <a href="https://github.com/LycaonIsAWolf/instance_names"><span class="invisible">https://</span><span class="ellipsis">github.com/LycaonIsAWolf/insta</span><span class="invisible">nce_names</span></a></p></summary> - <link rel="alternate" type="text/html" href="https://cybre.space/@instance_names"/> - <link rel="avatar" type="image/jpeg" media:width="120" media:height="120" href="https://icosahedron.website/system/accounts/avatars/000/011/176/original/3845c33e63aa28bd.jpg?1492882822"/> - <link rel="header" type="image/png" media:width="700" media:height="335" href="https://icosahedron.website/system/accounts/headers/000/011/176/original/a7810908beeeef7e.png?1492882825"/> - <poco:preferredUsername>instance_names</poco:preferredUsername> - <poco:displayName>instance names</poco:displayName> - <poco:note>name ideas for your new mastodon instance. made by @lycaon source available at https://github.com/LycaonIsAWolf/instance_names</poco:note> - <mastodon:scope>public</mastodon:scope> - </author> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="fr"><p>dildo.codes</p></content> - <mastodon:scope>unlisted</mastodon:scope> - <link rel="alternate" type="text/html" href="https://cybre.space/users/instance_names/updates/37775"/> - </activity:object> - <content type="html" xml:lang="en"><p>dildo.codes</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://icosahedron.website/users/shel/updates/47932"/> - <link rel="self" type="application/atom+xml" href="https://icosahedron.website/users/shel/updates/47932.atom"/> - </entry> -</feed> diff --git a/test/fixtures/mastodon/application_actor.json b/test/fixtures/mastodon/application_actor.json new file mode 100644 index 000000000..2089ea049 --- /dev/null +++ b/test/fixtures/mastodon/application_actor.json @@ -0,0 +1,67 @@ +{ + "@context": [ + "https://www.w3.org/ns/activitystreams", + "https://w3id.org/security/v1", + { + "manuallyApprovesFollowers": "as:manuallyApprovesFollowers", + "toot": "http://joinmastodon.org/ns#", + "featured": { + "@id": "toot:featured", + "@type": "@id" + }, + "alsoKnownAs": { + "@id": "as:alsoKnownAs", + "@type": "@id" + }, + "movedTo": { + "@id": "as:movedTo", + "@type": "@id" + }, + "schema": "http://schema.org#", + "PropertyValue": "schema:PropertyValue", + "value": "schema:value", + "IdentityProof": "toot:IdentityProof", + "discoverable": "toot:discoverable", + "Device": "toot:Device", + "Ed25519Signature": "toot:Ed25519Signature", + "Ed25519Key": "toot:Ed25519Key", + "Curve25519Key": "toot:Curve25519Key", + "EncryptedMessage": "toot:EncryptedMessage", + "publicKeyBase64": "toot:publicKeyBase64", + "deviceId": "toot:deviceId", + "claim": { + "@type": "@id", + "@id": "toot:claim" + }, + "fingerprintKey": { + "@type": "@id", + "@id": "toot:fingerprintKey" + }, + "identityKey": { + "@type": "@id", + "@id": "toot:identityKey" + }, + "devices": { + "@type": "@id", + "@id": "toot:devices" + }, + "messageFranking": "toot:messageFranking", + "messageType": "toot:messageType", + "cipherText": "toot:cipherText" + } + ], + "id": "https://{{DOMAIN}}/actor", + "type": "Application", + "inbox": "https://{{DOMAIN}}/actor/inbox", + "preferredUsername": "{{DOMAIN}}", + "url": "https://{{DOMAIN}}/about/more?instance_actor=true", + "manuallyApprovesFollowers": true, + "publicKey": { + "id": "https://{{DOMAIN}}/actor#main-key", + "owner": "https://{{DOMAIN}}/actor", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAA0CA08AMIIBCgKCAQEAyi2T2FFZJgRPY+96YQrn\n6J6eF2P60J+nz+/pRc/acv/Nx+NLxxPyXby0F2s60MV7uALRQbBBnf7oNKCd/T4S\nvbr7UXMCWTdaJBpYubMKWT9uBlaUUkUfqL+WTV+IQnlcKtssQ4+AwrAKAZXza8ws\nZypevOsLHzayyEzztmm1KQC9GCUOITCLf7Q6qEhy8z/HuqLBEC0Own0pD7QsbfcS\no1peuZY7g1E/jJ9HR9GqJccMaR0H28KmJ7tT1Yzlyf5uZMRIdPxsoMR9sGLjR2B8\noegSwaf9SogR3ScP395Tt/9Ud1VVzuhpoS8Uy7jKSs+3CuLJsEGoMrib8VyOwadS\n9wIDAQAB\n-----END PUBLIC KEY-----\n" + }, + "endpoints": { + "sharedInbox": "https://{{DOMAIN}}/inbox" + } +} diff --git a/test/fixtures/mastodon/collections/featured.json b/test/fixtures/mastodon/collections/featured.json new file mode 100644 index 000000000..56f8f56fa --- /dev/null +++ b/test/fixtures/mastodon/collections/featured.json @@ -0,0 +1,39 @@ +{ + "@context": [ + "https://www.w3.org/ns/activitystreams", + "https://{{domain}}/schemas/litepub-0.1.jsonld", + { + "@language": "und" + } + ], + "id": "https://{{domain}}/users/{{nickname}}/collections/featured", + "orderedItems": [ + { + "@context": [ + "https://www.w3.org/ns/activitystreams", + "https://{{domain}}/schemas/litepub-0.1.jsonld", + { + "@language": "und" + } + ], + "actor": "https://{{domain}}/users/{{nickname}}", + "attachment": [], + "attributedTo": "https://{{domain}}/users/{{nickname}}", + "cc": [ + "https://{{domain}}/users/{{nickname}}/followers" + ], + "content": "", + "id": "https://{{domain}}/objects/{{object_id}}", + "published": "2021-02-12T15:13:43.915429Z", + "sensitive": false, + "source": "", + "summary": "", + "tag": [], + "to": [ + "https://www.w3.org/ns/activitystreams#Public" + ], + "type": "Note" + } + ], + "type": "OrderedCollection" +} diff --git a/test/fixtures/mastodon_conversation.xml b/test/fixtures/mastodon_conversation.xml deleted file mode 100644 index 8faab2304..000000000 --- a/test/fixtures/mastodon_conversation.xml +++ /dev/null @@ -1,30 +0,0 @@ -<?xml version="1.0"?> -<entry xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:media="http://purl.org/syndication/atommedia" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:mastodon="http://mastodon.social/schema/1.0"> - <id>tag:mastodon.social,2017-08-28:objectId=16402826:objectType=Status</id> - <published>2017-08-28T17:58:55Z</published> - <updated>2017-08-28T17:58:55Z</updated> - <title>New status by lambadalambda</title> - <author> - <id>https://mastodon.social/users/lambadalambda</id> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://mastodon.social/users/lambadalambda</uri> - <name>lambadalambda</name> - <email>lambadalambda@mastodon.social</email> - <link rel="alternate" type="text/html" href="https://mastodon.social/@lambadalambda"/> - <link rel="avatar" type="image/gif" media:width="120" media:height="120" href="https://files.mastodon.social/accounts/avatars/000/000/264/original/1429214160519.gif"/> - <link rel="header" type="image/gif" media:width="700" media:height="335" href="https://files.mastodon.social/accounts/headers/000/000/264/original/28b26104f83747d2.gif"/> - <poco:preferredUsername>lambadalambda</poco:preferredUsername> - <poco:displayName>Critical Value</poco:displayName> - <mastodon:scope>public</mastodon:scope> - </author> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <link rel="alternate" type="application/activity+json" href="https://mastodon.social/users/lambadalambda/statuses/16402826"/> - <content type="html" xml:lang=""><p>test. <a href="https://mastodon.social/media/XCp0OHGPON9kWZwhjaI" rel="nofollow noopener" target="_blank"><span class="invisible">https://</span><span class="ellipsis">mastodon.social/media/XCp0OHGP</span><span class="invisible">ON9kWZwhjaI</span></a></p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="enclosure" type="image/png" length="307682" href="https://files.mastodon.social/media_attachments/files/001/271/957/original/6b426b164a09a40e.png"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/4215320"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/4215320.atom"/> - <ostatus:conversation ref="tag:mastodon.social,2017-08-28:objectId=7876885:objectType=Conversation"/> -</entry> diff --git a/test/fixtures/mewmew_no_name.json b/test/fixtures/mewmew_no_name.json new file mode 100644 index 000000000..532d4cf70 --- /dev/null +++ b/test/fixtures/mewmew_no_name.json @@ -0,0 +1,46 @@ +{ + "@context" : [ + "https://www.w3.org/ns/activitystreams", + "https://princess.cat/schemas/litepub-0.1.jsonld", + { + "@language" : "und" + } + ], + "attachment" : [], + "capabilities" : { + "acceptsChatMessages" : true + }, + "discoverable" : false, + "endpoints" : { + "oauthAuthorizationEndpoint" : "https://princess.cat/oauth/authorize", + "oauthRegistrationEndpoint" : "https://princess.cat/api/v1/apps", + "oauthTokenEndpoint" : "https://princess.cat/oauth/token", + "sharedInbox" : "https://princess.cat/inbox", + "uploadMedia" : "https://princess.cat/api/ap/upload_media" + }, + "followers" : "https://princess.cat/users/mewmew/followers", + "following" : "https://princess.cat/users/mewmew/following", + "icon" : { + "type" : "Image", + "url" : "https://princess.cat/media/12794fb50e86911e65be97f69196814049dcb398a2f8b58b99bb6591576e648c.png?name=blobcatpresentpink.png" + }, + "id" : "https://princess.cat/users/mewmew", + "image" : { + "type" : "Image", + "url" : "https://princess.cat/media/05d8bf3953ab6028fc920494ffc643fbee9dcef40d7bdd06f107e19acbfbd7f9.png" + }, + "inbox" : "https://princess.cat/users/mewmew/inbox", + "manuallyApprovesFollowers" : true, + "name" : " ", + "outbox" : "https://princess.cat/users/mewmew/outbox", + "preferredUsername" : "mewmew", + "publicKey" : { + "id" : "https://princess.cat/users/mewmew#main-key", + "owner" : "https://princess.cat/users/mewmew", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAru7VpygVef4zrFwnj0Mh\nrbO/2z2EdKN3rERtNrT8zWsLXNLQ50lfpRPnGDrd+xq7Rva4EIu0d5KJJ9n4vtY0\nuxK3On9vA2oyjLlR9O0lI3XTrHJborG3P7IPXrmNUMFpHiFHNqHp5tugUrs1gUFq\n7tmOmM92IP4Wjk8qNHFcsfnUbaPTX7sNIhteQKdi5HrTb/6lrEIe4G/FlMKRqxo3\nRNHuv6SNFQuiUKvFzjzazvjkjvBSm+aFROgdHa2tKl88StpLr7xmuY8qNFCRT6W0\nLacRp6c8ah5f03Kd+xCBVhCKvKaF1K0ERnQTBiitUh85md+Mtx/CoDoLnmpnngR3\nvQIDAQAB\n-----END PUBLIC KEY-----\n\n" + }, + "summary" : "please reply to my posts as direct messages if you have many followers", + "tag" : [], + "type" : "Person", + "url" : "https://princess.cat/users/mewmew" +} diff --git a/test/fixtures/modules/good_mrf.ex b/test/fixtures/modules/good_mrf.ex new file mode 100644 index 000000000..5afa1c1d1 --- /dev/null +++ b/test/fixtures/modules/good_mrf.ex @@ -0,0 +1,19 @@ +defmodule Fixtures.Modules.GoodMRF do + @behaviour Pleroma.Web.ActivityPub.MRF.Policy + + @impl true + def filter(a), do: {:ok, a} + + @impl true + def describe, do: %{} + + @impl true + def config_description do + %{ + key: :good_mrf, + related_policy: "Fixtures.Modules.GoodMRF", + label: "Good MRF", + description: "Some description" + } + end +end diff --git a/test/fixtures/modules/runtime_module.ex b/test/fixtures/modules/runtime_module.ex index f11032b57..940b58a1b 100644 --- a/test/fixtures/modules/runtime_module.ex +++ b/test/fixtures/modules/runtime_module.ex @@ -1,8 +1,8 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only -defmodule RuntimeModule do +defmodule Fixtures.Modules.RuntimeModule do @moduledoc """ This is a dummy module to test custom runtime modules. """ diff --git a/test/fixtures/nil_mention_entry.xml b/test/fixtures/nil_mention_entry.xml deleted file mode 100644 index e13024cb3..000000000 --- a/test/fixtures/nil_mention_entry.xml +++ /dev/null @@ -1,52 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:georss="http://www.georss.org/georss" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:media="http://purl.org/syndication/atommedia" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:statusnet="http://status.net/schema/api/1/"> - <generator uri="https://gnu.io/social" version="1.2.0-alpha2">GNU social</generator> - <id>https://social.stopwatchingus-heidelberg.de/api/statuses/user_timeline/18330.atom</id> - <title>atarifrosch timeline</title> - <subtitle>Updates from atarifrosch on social.stopwatchingus-heidelberg.de!</subtitle> - <logo>https://social.stopwatchingus-heidelberg.de/avatar/18330-96-20150628163706.png</logo> - <updated>2017-08-24T11:36:49+02:00</updated> -<author> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://social.stopwatchingus-heidelberg.de/user/18330</uri> - <name>atarifrosch</name> - <summary>Nerd, Pirat, Debian user, CAcert assurer, Geocacher, Freifunker. Autismus/Depression, agender. GnuPG Key-ID: 0xBCF81ADE</summary> - <link rel="alternate" type="text/html" href="https://social.stopwatchingus-heidelberg.de/atarifrosch"/> - <link rel="avatar" type="image/png" media:width="480" media:height="480" href="https://social.stopwatchingus-heidelberg.de/avatar/18330-480-20150628163705.png"/> - <link rel="avatar" type="image/png" media:width="96" media:height="96" href="https://social.stopwatchingus-heidelberg.de/avatar/18330-96-20150628163706.png"/> - <link rel="avatar" type="image/png" media:width="48" media:height="48" href="https://social.stopwatchingus-heidelberg.de/avatar/18330-48-20150628163713.png"/> - <link rel="avatar" type="image/png" media:width="24" media:height="24" href="https://social.stopwatchingus-heidelberg.de/avatar/18330-24-20150628163714.png"/> - <poco:preferredUsername>atarifrosch</poco:preferredUsername> - <poco:displayName>Atari-Frosch</poco:displayName> - <poco:note>Nerd, Pirat, Debian user, CAcert assurer, Geocacher, Freifunker. Autismus/Depression, agender. GnuPG Key-ID: 0xBCF81ADE</poco:note> - <poco:address> - <poco:formatted>Düsseldorf, NRW, Germany</poco:formatted> - </poco:address> - <poco:urls> - <poco:type>homepage</poco:type> - <poco:value>https://www.atari-frosch.de/</poco:value> - <poco:primary>true</poco:primary> - </poco:urls> - <followers url="https://social.stopwatchingus-heidelberg.de/atarifrosch/subscribers"></followers> - <statusnet:profile_info local_id="18330"></statusnet:profile_info> -</author> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:social.stopwatchingus-heidelberg.de,2017-08-22:noticeId=978072:objectType=note</id> - <title>New note by atarifrosch</title> - <content type="html">2017-08-22 Bundesverfassungsgericht: Erfolgreiche Verfassungsbeschwerde gegen die Versagung vorläufiger Leistungen für Kosten der Unterkunft und Heizung – <a href="https://www.bundesverfassungsgericht.de/SharedDocs/Pressemitteilungen/DE/2017/bvg17-072.html" title="https://www.bundesverfassungsgericht.de/SharedDocs/Pressemitteilungen/DE/2017/bvg17-072.html" class="attachment" id="attachment-450768" rel="nofollow external">https://www.bundesverfassungsgericht.de/SharedDocs/Pressemitteilungen/DE/2017/bvg17-072.html</a> !<a href="http://quitter.se/group/2184/id" class="h-card group" title="HartzIV (hartziv)">hartziv</a></content> - <link rel="alternate" type="text/html" href="https://social.stopwatchingus-heidelberg.de/notice/978072"/> - <status_net notice_id="978072"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-08-22T12:00:21+00:00</published> - <updated>2017-08-22T12:00:21+00:00</updated> - <link rel="ostatus:conversation" href="tag:social.stopwatchingus-heidelberg.de,2017-08-22:noticeId=978072:objectType=thread:crc32=28a35f44"/> - <ostatus:conversation>tag:social.stopwatchingus-heidelberg.de,2017-08-22:noticeId=978072:objectType=thread:crc32=28a35f44</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href=""/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/group" href="http://quitter.se/group/2184/id"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.stopwatchingus-heidelberg.de/api/statuses/show/978072.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.stopwatchingus-heidelberg.de/api/statuses/show/978072.atom"/> - <statusnet:notice_info local_id="978072" source="web"></statusnet:notice_info> -</entry> -</feed> diff --git a/test/fixtures/osada-follow-activity.json b/test/fixtures/osada-follow-activity.json index b991eea36..be10ce88f 100644 --- a/test/fixtures/osada-follow-activity.json +++ b/test/fixtures/osada-follow-activity.json @@ -1,56 +1,52 @@ { - "@context":[ + "@context": [ "https://www.w3.org/ns/activitystreams", "https://w3id.org/security/v1", "https://apfed.club/apschema/v1.4" ], - "id":"https://apfed.club/follow/9", - "type":"Follow", - "actor":{ - "type":"Person", - "id":"https://apfed.club/channel/indio", - "preferredUsername":"indio", - "name":"Indio", - "updated":"2019-08-20T23:52:34Z", - "icon":{ - "type":"Image", - "mediaType":"image/jpeg", - "updated":"2019-08-20T23:53:37Z", - "url":"https://apfed.club/photo/profile/l/2", - "height":300, - "width":300 + "id": "https://apfed.club/follow/9", + "type": "Follow", + "actor": { + "type": "Person", + "id": "https://apfed.club/channel/indio", + "preferredUsername": "indio", + "name": "Indio", + "updated": "2019-08-20T23:52:34Z", + "icon": { + "type": "Image", + "mediaType": "image/jpeg", + "updated": "2019-08-20T23:53:37Z", + "url": "https://apfed.club/photo/profile/l/2", + "height": 300, + "width": 300 }, - "url":"https://apfed.club/channel/indio", - "inbox":"https://apfed.club/inbox/indio", - "outbox":"https://apfed.club/outbox/indio", - "followers":"https://apfed.club/followers/indio", - "following":"https://apfed.club/following/indio", - "endpoints":{ - "sharedInbox":"https://apfed.club/inbox" + "url": "https://apfed.club/channel/indio", + "inbox": "https://apfed.club/inbox/indio", + "outbox": "https://apfed.club/outbox/indio", + "followers": "https://apfed.club/followers/indio", + "following": "https://apfed.club/following/indio", + "endpoints": { + "sharedInbox": "https://apfed.club/inbox" }, - "publicKey":{ - "id":"https://apfed.club/channel/indio", - "owner":"https://apfed.club/channel/indio", - "publicKeyPem":"-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA77TIR1VuSYFnmDRFGHHb\n4vaGdx9ranzRX4bfOKAqa++Ch5L4EqJpPy08RuM+NrYCYiYl4QQFDSSDXAEgb5g9\nC1TgWTfI7q/E0UBX2Vr0mU6X4i1ztv0tuQvegRjcSJ7l1AvoBs8Ip4MEJ3OPEQhB\ngJqAACB3Gnps4zi2I0yavkxUfGVKr6zKT3BxWh5hTpKC7Do+ChIrVZC2EwxND9K6 -\nsAnQHThcb5EQuvuzUQZKeS7IEOsd0JpZDmJjbfMGrAWE81pLIfEeeA2joCJiBBTO\nglDsW+juvZ+lWqJpMr2hMWpvfrFjJeUawNJCIzsLdVIZR+aKj5yy6yqoS8hkN9Ha\n1MljZpsXl+EmwcwAIqim1YeLwERCEAQ/JWbSt8pQTQbzZ6ibwQ4mchCxacrRbIVR -\nnL59fWMBassJcbY0VwrTugm2SBsYbDjESd55UZV03Rwr8qseGTyi+hH8O7w2SIaY\nzjN6AdZiPmsh00YflzlCk8MSLOHMol1vqIUzXxU8CdXn9+KsuQdZGrTz0YKN/db4\naVwUGJatz2Tsvf7R1tJBjJfeQWOWbbn3pycLVH86LjZ83qngp9ZVnAveUnUqz0yS -\nhe+buZ6UMsfGzbIYon2bKNlz6gYTH0YPcr+cLe+29drtt0GZiXha1agbpo4RB8zE -\naNL2fucF5YT0yNpbd/5WoV0CAwEAAQ==\n-----END PUBLIC KEY-----\n" + "publicKey": { + "id": "https://apfed.club/channel/indio", + "owner": "https://apfed.club/channel/indio", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA77TIR1VuSYFnmDRFGHHb\n4vaGdx9ranzRX4bfOKAqa++Ch5L4EqJpPy08RuM+NrYCYiYl4QQFDSSDXAEgb5g9\nC1TgWTfI7q/E0UBX2Vr0mU6X4i1ztv0tuQvegRjcSJ7l1AvoBs8Ip4MEJ3OPEQhB\ngJqAACB3Gnps4zi2I0yavkxUfGVKr6zKT3BxWh5hTpKC7Do+ChIrVZC2EwxND9K6\nsAnQHThcb5EQuvuzUQZKeS7IEOsd0JpZDmJjbfMGrAWE81pLIfEeeA2joCJiBBTO\nglDsW+juvZ+lWqJpMr2hMWpvfrFjJeUawNJCIzsLdVIZR+aKj5yy6yqoS8hkN9Ha\n1MljZpsXl+EmwcwAIqim1YeLwERCEAQ/JWbSt8pQTQbzZ6ibwQ4mchCxacrRbIVR\nnL59fWMBassJcbY0VwrTugm2SBsYbDjESd55UZV03Rwr8qseGTyi+hH8O7w2SIaY\nzjN6AdZiPmsh00YflzlCk8MSLOHMol1vqIUzXxU8CdXn9+KsuQdZGrTz0YKN/db4\naVwUGJatz2Tsvf7R1tJBjJfeQWOWbbn3pycLVH86LjZ83qngp9ZVnAveUnUqz0yS\nhe+buZ6UMsfGzbIYon2bKNlz6gYTH0YPcr+cLe+29drtt0GZiXha1agbpo4RB8zE\naNL2fucF5YT0yNpbd/5WoV0CAwEAAQ==\n-----END PUBLIC KEY-----\n" } }, - "object":"https://pleroma.site/users/kaniini", - "to":[ + "object": "https://pleroma.site/users/kaniini", + "to": [ "https://pleroma.site/users/kaniini" ], - "signature":{ - "@context":[ + "signature": { + "@context": [ "https://www.w3.org/ns/activitystreams", "https://w3id.org/security/v1" ], - "type":"RsaSignature2017", - "nonce":"52c035e0a9e81dce8b486159204e97c22637e91f75cdfad5378de91de68e9117", - "creator":"https://apfed.club/channel/indio/public_key_pem", - "created":"2019-08-22T03:38:02Z", - "signatureValue":"oVliRCIqNIh6yUp851dYrF0y21aHp3Rz6VkIpW1pFMWfXuzExyWSfcELpyLseeRmsw5bUu9zJkH44B4G2LiJQKA9UoEQDjrDMZBmbeUpiQqq3DVUzkrBOI8bHZ7xyJ/CjSZcNHHh0MHhSKxswyxWMGi4zIqzkAZG3vRRgoPVHdjPm00sR3B8jBLw1cjoffv+KKeM/zEUpe13gqX9qHAWHHqZepxgSWmq+EKOkRvHUPBXiEJZfXzc5uW+vZ09F3WBYmaRoy8Y0e1P29fnRLqSy7EEINdrHaGclRqoUZyiawpkgy3lWWlynesV/HiLBR7EXT79eKstxf4wfTDaPKBCfTCsOWuMWHr7Genu37ew2/t7eiBGqCwwW12ylhml/OLHgNK3LOhmRABhtfpaFZSxfDVnlXfaLpY1xekVOj2oC0FpBtnoxVKLpIcyLw6dkfSil5ANd+hl59W/bpPA8KT90ii1fSNCo3+FcwQVx0YsPznJNA60XfFuVsme7zNcOst6393e1WriZxBanFpfB63zVQc9u1fjyfktx/yiUNxIlre+sz9OCc0AACn94iRhBYh4bbzdleUOTnM7lnD4Dj2FP+xeDIP8CA8wXUeq5+9kopSp2kAmlUEyFUdg4no7naIeu1SZnopfUg56PsVCp9JHiUK1SYAyWbdC+FbUECu5CvI=" + "type": "RsaSignature2017", + "nonce": "52c035e0a9e81dce8b486159204e97c22637e91f75cdfad5378de91de68e9117", + "creator": "https://apfed.club/channel/indio/public_key_pem", + "created": "2019-08-22T03:38:02Z", + "signatureValue": "oVliRCIqNIh6yUp851dYrF0y21aHp3Rz6VkIpW1pFMWfXuzExyWSfcELpyLseeRmsw5bUu9zJkH44B4G2LiJQKA9UoEQDjrDMZBmbeUpiQqq3DVUzkrBOI8bHZ7xyJ/CjSZcNHHh0MHhSKxswyxWMGi4zIqzkAZG3vRRgoPVHdjPm00sR3B8jBLw1cjoffv+KKeM/zEUpe13gqX9qHAWHHqZepxgSWmq+EKOkRvHUPBXiEJZfXzc5uW+vZ09F3WBYmaRoy8Y0e1P29fnRLqSy7EEINdrHaGclRqoUZyiawpkgy3lWWlynesV/HiLBR7EXT79eKstxf4wfTDaPKBCfTCsOWuMWHr7Genu37ew2/t7eiBGqCwwW12ylhml/OLHgNK3LOhmRABhtfpaFZSxfDVnlXfaLpY1xekVOj2oC0FpBtnoxVKLpIcyLw6dkfSil5ANd+hl59W/bpPA8KT90ii1fSNCo3+FcwQVx0YsPznJNA60XfFuVsme7zNcOst6393e1WriZxBanFpfB63zVQc9u1fjyfktx/yiUNxIlre+sz9OCc0AACn94iRhBYh4bbzdleUOTnM7lnD4Dj2FP+xeDIP8CA8wXUeq5+9kopSp2kAmlUEyFUdg4no7naIeu1SZnopfUg56PsVCp9JHiUK1SYAyWbdC+FbUECu5CvI=" } } diff --git a/test/fixtures/ostatus_incoming_post.xml b/test/fixtures/ostatus_incoming_post.xml deleted file mode 100644 index 7967e1b32..000000000 --- a/test/fixtures/ostatus_incoming_post.xml +++ /dev/null @@ -1,57 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:georss="http://www.georss.org/georss" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:media="http://purl.org/syndication/atommedia" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:statusnet="http://status.net/schema/api/1/"> - <generator uri="https://gnu.io/social" version="1.0.2-dev">GNU social</generator> - <id>https://social.heldscal.la/api/statuses/user_timeline/23211.atom</id> - <title>lambadalambda timeline</title> - <subtitle>Updates from lambadalambda on social.heldscal.la!</subtitle> - <logo>https://social.heldscal.la/avatar/23211-96-20170416114255.jpeg</logo> - <updated>2017-04-29T18:25:38+00:00</updated> -<author> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://social.heldscal.la/user/23211</uri> - <name>lambadalambda</name> - <summary>Call me Deacon Blues.</summary> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/lambadalambda"/> - <link rel="avatar" type="image/jpeg" media:width="236" media:height="236" href="https://social.heldscal.la/avatar/23211-original-20170416114255.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/23211-96-20170416114255.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="48" media:height="48" href="https://social.heldscal.la/avatar/23211-48-20170416114255.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="24" media:height="24" href="https://social.heldscal.la/avatar/23211-24-20170416114257.jpeg"/> - <poco:preferredUsername>lambadalambda</poco:preferredUsername> - <poco:displayName>Constance Variable</poco:displayName> - <poco:note>Call me Deacon Blues.</poco:note> - <poco:address> - <poco:formatted>Berlin</poco:formatted> - </poco:address> - <poco:urls> - <poco:type>homepage</poco:type> - <poco:value>https://heldscal.la</poco:value> - <poco:primary>true</poco:primary> - </poco:urls> - <followers url="https://social.heldscal.la/lambadalambda/subscribers"></followers> - <statusnet:profile_info local_id="23211"></statusnet:profile_info> -</author> - <link href="https://social.heldscal.la/lambadalambda" rel="alternate" type="text/html"/> - <link href="https://social.heldscal.la/main/sup" rel="http://api.friendfeed.com/2008/03#sup" type="application/json"/> - <link href="https://social.heldscal.la/main/push/hub" rel="hub"/> - <link href="https://social.heldscal.la/main/salmon/user/23211" rel="salmon"/> - <link href="https://social.heldscal.la/main/salmon/user/23211" rel="http://salmon-protocol.org/ns/salmon-replies"/> - <link href="https://social.heldscal.la/main/salmon/user/23211" rel="http://salmon-protocol.org/ns/salmon-mention"/> - <link href="https://social.heldscal.la/api/statuses/user_timeline/23211.atom" rel="self" type="application/atom+xml"/> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:social.heldscal.la,2017-04-29:noticeId=1967725:objectType=note</id> - <title>New note by lambadalambda</title> - <content type="html">Will it blend?</content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/1967725"/> - <status_net notice_id="1967725"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-04-29T18:25:38+00:00</published> - <updated>2017-04-29T18:25:38+00:00</updated> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1007861"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/1007861" local_id="1007861" ref="tag:social.heldscal.la,2017-04-29:objectType=thread:nonce=3f3a9dd83acc4e35">tag:social.heldscal.la,2017-04-29:objectType=thread:nonce=3f3a9dd83acc4e35</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1967725.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1967725.atom"/> - <statusnet:notice_info local_id="1967725" source="Pleroma FE"></statusnet:notice_info> -</entry> -</feed> diff --git a/test/fixtures/ostatus_incoming_post_tag.xml b/test/fixtures/ostatus_incoming_post_tag.xml deleted file mode 100644 index 0f99c4126..000000000 --- a/test/fixtures/ostatus_incoming_post_tag.xml +++ /dev/null @@ -1,59 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:georss="http://www.georss.org/georss" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:media="http://purl.org/syndication/atommedia" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:statusnet="http://status.net/schema/api/1/"> - <generator uri="https://gnu.io/social" version="1.0.2-dev">GNU social</generator> - <id>https://social.heldscal.la/api/statuses/user_timeline/23211.atom</id> - <title>lambadalambda timeline</title> - <subtitle>Updates from lambadalambda on social.heldscal.la!</subtitle> - <logo>https://social.heldscal.la/avatar/23211-96-20170416114255.jpeg</logo> - <updated>2017-04-29T18:25:38+00:00</updated> -<author> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://social.heldscal.la/user/23211</uri> - <name>lambadalambda</name> - <summary>Call me Deacon Blues.</summary> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/lambadalambda"/> - <link rel="avatar" type="image/jpeg" media:width="236" media:height="236" href="https://social.heldscal.la/avatar/23211-original-20170416114255.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/23211-96-20170416114255.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="48" media:height="48" href="https://social.heldscal.la/avatar/23211-48-20170416114255.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="24" media:height="24" href="https://social.heldscal.la/avatar/23211-24-20170416114257.jpeg"/> - <poco:preferredUsername>lambadalambda</poco:preferredUsername> - <poco:displayName>Constance Variable</poco:displayName> - <poco:note>Call me Deacon Blues.</poco:note> - <poco:address> - <poco:formatted>Berlin</poco:formatted> - </poco:address> - <poco:urls> - <poco:type>homepage</poco:type> - <poco:value>https://heldscal.la</poco:value> - <poco:primary>true</poco:primary> - </poco:urls> - <followers url="https://social.heldscal.la/lambadalambda/subscribers"></followers> - <statusnet:profile_info local_id="23211"></statusnet:profile_info> -</author> - <link href="https://social.heldscal.la/lambadalambda" rel="alternate" type="text/html"/> - <link href="https://social.heldscal.la/main/sup" rel="http://api.friendfeed.com/2008/03#sup" type="application/json"/> - <link href="https://social.heldscal.la/main/push/hub" rel="hub"/> - <link href="https://social.heldscal.la/main/salmon/user/23211" rel="salmon"/> - <link href="https://social.heldscal.la/main/salmon/user/23211" rel="http://salmon-protocol.org/ns/salmon-replies"/> - <link href="https://social.heldscal.la/main/salmon/user/23211" rel="http://salmon-protocol.org/ns/salmon-mention"/> - <link href="https://social.heldscal.la/api/statuses/user_timeline/23211.atom" rel="self" type="application/atom+xml"/> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:social.heldscal.la,2017-04-29:noticeId=1967725:objectType=note</id> - <title>New note by lambadalambda</title> - <content type="html">Will it blend?</content> - <category term="Nsfw"/> - <category term=""/> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/1967725"/> - <status_net notice_id="1967725"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-04-29T18:25:38+00:00</published> - <updated>2017-04-29T18:25:38+00:00</updated> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1007861"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/1007861" local_id="1007861" ref="tag:social.heldscal.la,2017-04-29:objectType=thread:nonce=3f3a9dd83acc4e35">tag:social.heldscal.la,2017-04-29:objectType=thread:nonce=3f3a9dd83acc4e35</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1967725.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1967725.atom"/> - <statusnet:notice_info local_id="1967725" source="Pleroma FE"></statusnet:notice_info> -</entry> -</feed> diff --git a/test/fixtures/ostatus_incoming_reply.xml b/test/fixtures/ostatus_incoming_reply.xml deleted file mode 100644 index 83a427a68..000000000 --- a/test/fixtures/ostatus_incoming_reply.xml +++ /dev/null @@ -1,60 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:georss="http://www.georss.org/georss" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:media="http://purl.org/syndication/atommedia" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:statusnet="http://status.net/schema/api/1/"> - <generator uri="https://gnu.io/social" version="1.0.2-dev">GNU social</generator> - <id>https://social.heldscal.la/api/statuses/user_timeline/23211.atom</id> - <title>lambadalambda timeline</title> - <subtitle>Updates from lambadalambda on social.heldscal.la!</subtitle> - <logo>https://social.heldscal.la/avatar/23211-96-20170416114255.jpeg</logo> - <updated>2017-04-30T09:30:32+00:00</updated> -<author> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://social.heldscal.la/user/23211</uri> - <name>lambadalambda</name> - <summary>Call me Deacon Blues.</summary> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/lambadalambda"/> - <link rel="avatar" type="image/jpeg" media:width="236" media:height="236" href="https://social.heldscal.la/avatar/23211-original-20170416114255.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/23211-96-20170416114255.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="48" media:height="48" href="https://social.heldscal.la/avatar/23211-48-20170416114255.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="24" media:height="24" href="https://social.heldscal.la/avatar/23211-24-20170416114257.jpeg"/> - <poco:preferredUsername>lambadalambda</poco:preferredUsername> - <poco:displayName>Constance Variable</poco:displayName> - <poco:note>Call me Deacon Blues.</poco:note> - <poco:address> - <poco:formatted>Berlin</poco:formatted> - </poco:address> - <poco:urls> - <poco:type>homepage</poco:type> - <poco:value>https://heldscal.la</poco:value> - <poco:primary>true</poco:primary> - </poco:urls> - <followers url="https://social.heldscal.la/lambadalambda/subscribers"></followers> - <statusnet:profile_info local_id="23211"></statusnet:profile_info> -</author> - <link href="https://social.heldscal.la/lambadalambda" rel="alternate" type="text/html"/> - <link href="https://social.heldscal.la/main/sup" rel="http://api.friendfeed.com/2008/03#sup" type="application/json"/> - <link href="https://social.heldscal.la/main/push/hub" rel="hub"/> - <link href="https://social.heldscal.la/main/salmon/user/23211" rel="salmon"/> - <link href="https://social.heldscal.la/main/salmon/user/23211" rel="http://salmon-protocol.org/ns/salmon-replies"/> - <link href="https://social.heldscal.la/main/salmon/user/23211" rel="http://salmon-protocol.org/ns/salmon-mention"/> - <link href="https://social.heldscal.la/api/statuses/user_timeline/23211.atom" rel="self" type="application/atom+xml"/> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>tag:social.heldscal.la,2017-04-30:noticeId=1978790:objectType=comment</id> - <title>New comment by lambadalambda</title> - <content type="html">@<a href="https://gs.archae.me/user/4687" class="h-card u-url p-nickname mention" title="shpbot">shpbot</a> why not indeed.</content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/1978790"/> - <status_net notice_id="1978790"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-04-30T09:30:32+00:00</published> - <updated>2017-04-30T09:30:32+00:00</updated> - <thr:in-reply-to ref="tag:gs.archae.me,2017-04-30:noticeId=778260:objectType=note" href="https://gs.archae.me/notice/778260"></thr:in-reply-to> - <link rel="related" href="https://gs.archae.me/notice/778260"/> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1013566"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/1013566" local_id="1013566" ref="https://gs.archae.me/conversation/327120">https://gs.archae.me/conversation/327120</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://gs.archae.me/user/4687"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1978790.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1978790.atom"/> - <statusnet:notice_info local_id="1978790" source="Pleroma FE"></statusnet:notice_info> -</entry> -</feed> diff --git a/test/fixtures/peertube/actor-person.json b/test/fixtures/peertube/actor-person.json new file mode 100644 index 000000000..8c387d455 --- /dev/null +++ b/test/fixtures/peertube/actor-person.json @@ -0,0 +1,121 @@ +{ + "type": "Person", + "id": "https://peertube.stream/accounts/createurs", + "following": "https://peertube.stream/accounts/createurs/following", + "followers": "https://peertube.stream/accounts/createurs/followers", + "playlists": "https://peertube.stream/accounts/createurs/playlists", + "inbox": "https://peertube.stream/accounts/createurs/inbox", + "outbox": "https://peertube.stream/accounts/createurs/outbox", + "preferredUsername": "createurs", + "url": "https://peertube.stream/accounts/createurs", + "name": "Créateurs", + "endpoints": { + "sharedInbox": "https://peertube.stream/inbox" + }, + "publicKey": { + "id": "https://peertube.stream/accounts/createurs#main-key", + "owner": "https://peertube.stream/accounts/createurs", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxqkQhbRYbA81+WTYjorR\n2lEMad3kYCnzDjGTLr4I92eanzFHxyELGnjzP6TpEvjOiB9NrCRrqU/iFPLdgrq2\nwIFcXPWdCq6Gcg7QLlaeMM0JoJmr0KTEhzg0XKCo96UsyTzaF4DISxqi8RyoyWeU\nEkgiOzlkdYTlouq3MlQH+p1PBAsNUQfIEUsU+l6k1vzbm8JRwlT+D1bNde4I/Lqs\n4uB5ru3zzInwZ2hz9+heiriNoGEBv74rZHYn966tZVX8iMGx2+m6okozEdEQbqCl\n0ekqDcd8P6CoFqqeeu8coh82OUtuFI/XsbetdWA55YQmSHyMiTsIwVbeoogIETbI\n4QIDAQAB\n-----END PUBLIC KEY-----" + }, + "icon": { + "type": "Image", + "mediaType": "image/png", + "url": "https://peertube.stream/lazy-static/avatars/c27b672d-ad8f-498a-adbe-553af8da56f9.png" + }, + "@context": [ + "https://www.w3.org/ns/activitystreams", + "https://w3id.org/security/v1", + { + "RsaSignature2017": "https://w3id.org/security#RsaSignature2017" + }, + { + "pt": "https://joinpeertube.org/ns#", + "sc": "http://schema.org#", + "Hashtag": "as:Hashtag", + "uuid": "sc:identifier", + "category": "sc:category", + "licence": "sc:license", + "subtitleLanguage": "sc:subtitleLanguage", + "sensitive": "as:sensitive", + "language": "sc:inLanguage", + "isLiveBroadcast": "sc:isLiveBroadcast", + "liveSaveReplay": { + "@type": "sc:Boolean", + "@id": "pt:liveSaveReplay" + }, + "permanentLive": { + "@type": "sc:Boolean", + "@id": "pt:permanentLive" + }, + "Infohash": "pt:Infohash", + "Playlist": "pt:Playlist", + "PlaylistElement": "pt:PlaylistElement", + "originallyPublishedAt": "sc:datePublished", + "views": { + "@type": "sc:Number", + "@id": "pt:views" + }, + "state": { + "@type": "sc:Number", + "@id": "pt:state" + }, + "size": { + "@type": "sc:Number", + "@id": "pt:size" + }, + "fps": { + "@type": "sc:Number", + "@id": "pt:fps" + }, + "startTimestamp": { + "@type": "sc:Number", + "@id": "pt:startTimestamp" + }, + "stopTimestamp": { + "@type": "sc:Number", + "@id": "pt:stopTimestamp" + }, + "position": { + "@type": "sc:Number", + "@id": "pt:position" + }, + "commentsEnabled": { + "@type": "sc:Boolean", + "@id": "pt:commentsEnabled" + }, + "downloadEnabled": { + "@type": "sc:Boolean", + "@id": "pt:downloadEnabled" + }, + "waitTranscoding": { + "@type": "sc:Boolean", + "@id": "pt:waitTranscoding" + }, + "support": { + "@type": "sc:Text", + "@id": "pt:support" + }, + "likes": { + "@id": "as:likes", + "@type": "@id" + }, + "dislikes": { + "@id": "as:dislikes", + "@type": "@id" + }, + "playlists": { + "@id": "pt:playlists", + "@type": "@id" + }, + "shares": { + "@id": "as:shares", + "@type": "@id" + }, + "comments": { + "@id": "as:comments", + "@type": "@id" + } + } + ], + "summary": null +} diff --git a/test/fixtures/peertube/video-object-mpegURL-only.json b/test/fixtures/peertube/video-object-mpegURL-only.json new file mode 100644 index 000000000..7f26e89bf --- /dev/null +++ b/test/fixtures/peertube/video-object-mpegURL-only.json @@ -0,0 +1,413 @@ +{ + "type": "Create", + "id": "https://peertube.stream/videos/watch/abece3c3-b9c6-47f4-8040-f3eed8c602e6/activity", + "actor": "https://peertube.stream/accounts/createurs", + "object": { + "type": "Video", + "id": "https://peertube.stream/videos/watch/abece3c3-b9c6-47f4-8040-f3eed8c602e6", + "name": "Vu du 20/02/21 : \"Planète Mars 2050\"", + "duration": "PT385S", + "uuid": "abece3c3-b9c6-47f4-8040-f3eed8c602e6", + "tag": [ + { + "type": "Hashtag", + "name": "France3" + }, + { + "type": "Hashtag", + "name": "lezapping" + } + ], + "category": { + "identifier": "11", + "name": "News & Politics" + }, + "language": { + "identifier": "fr", + "name": "French" + }, + "views": 5, + "sensitive": false, + "waitTranscoding": false, + "isLiveBroadcast": false, + "liveSaveReplay": null, + "permanentLive": null, + "state": 1, + "commentsEnabled": true, + "downloadEnabled": false, + "published": "2021-02-20T17:04:54.278Z", + "originallyPublishedAt": "2021-02-19T23:00:00.000Z", + "updated": "2021-02-21T20:01:11.189Z", + "mediaType": "text/markdown", + "content": "Un regard impertinent et libre, orchestré par Patrick Menais et son équipe, sur le monde de l’image.\r\n\r\nEn avant-première du lundi au samedi à 17h00 sur Facebook, Twitter et YouTube.\r\n\r\nDu lundi au samedi à 20h00 sur France 3.\r\n\r\nhttps://www.facebook.com/vufrancetv\r\nhttps://twitter.com/VuFrancetv", + "support": "Suivre VU :\r\n- Twitter : https://twitter.com/vufrancetv\r\n- Facebook :https://www.facebook.com/vufrancetv/\r\n- Site : https://www.france.tv/france-3/vu/", + "subtitleLanguage": [], + "icon": [ + { + "type": "Image", + "url": "https://peertube.stream/static/thumbnails/abece3c3-b9c6-47f4-8040-f3eed8c602e6.jpg", + "mediaType": "image/jpeg", + "width": 223, + "height": 122 + }, + { + "type": "Image", + "url": "https://peertube.stream/lazy-static/previews/abece3c3-b9c6-47f4-8040-f3eed8c602e6.jpg", + "mediaType": "image/jpeg", + "width": 850, + "height": 480 + } + ], + "url": [ + { + "type": "Link", + "mediaType": "text/html", + "href": "https://peertube.stream/videos/watch/abece3c3-b9c6-47f4-8040-f3eed8c602e6" + }, + { + "type": "Link", + "mediaType": "application/x-mpegURL", + "href": "https://peertube.stream/static/streaming-playlists/hls/abece3c3-b9c6-47f4-8040-f3eed8c602e6/master.m3u8", + "tag": [ + { + "type": "Infohash", + "name": "00bfce9595e1655d8696b60e19ca25c34be5fa63" + }, + { + "type": "Infohash", + "name": "256c21b65d5e0f944b4b79d8e0cbc55c9d906807" + }, + { + "type": "Infohash", + "name": "fcd981098c484d0e328927c8fb21ecf986880b7e" + }, + { + "type": "Infohash", + "name": "f7e01ac566e9fef91cd22514e6c3c256af7a9f5f" + }, + { + "type": "Infohash", + "name": "42b421fc44d0dceb45ac3f6f6419b07fd570a232" + }, + { + "type": "Infohash", + "name": "f876c6d6d49ce618a880ca223df54cb29f4b4bfd" + }, + { + "type": "Link", + "name": "sha256", + "mediaType": "application/json", + "href": "https://peertube.stream/static/streaming-playlists/hls/abece3c3-b9c6-47f4-8040-f3eed8c602e6/segments-sha256.json" + }, + { + "type": "Link", + "mediaType": "video/mp4", + "href": "https://peertube.stream/static/streaming-playlists/hls/abece3c3-b9c6-47f4-8040-f3eed8c602e6/abece3c3-b9c6-47f4-8040-f3eed8c602e6-1080-fragmented.mp4", + "height": 1080, + "size": 57888169, + "fps": 25 + }, + { + "type": "Link", + "rel": [ + "metadata", + "video/mp4" + ], + "mediaType": "application/json", + "href": "https://peertube.stream/api/v1/videos/abece3c3-b9c6-47f4-8040-f3eed8c602e6/metadata/570040", + "height": 1080, + "fps": 25 + }, + { + "type": "Link", + "mediaType": "application/x-bittorrent", + "href": "https://peertube.stream/static/torrents/abece3c3-b9c6-47f4-8040-f3eed8c602e6-1080-hls.torrent", + "height": 1080 + }, + { + "type": "Link", + "mediaType": "application/x-bittorrent;x-scheme-handler/magnet", + "href": "magnet:?xs=https%3A%2F%2Fpeertube.stream%2Fstatic%2Ftorrents%2Fabece3c3-b9c6-47f4-8040-f3eed8c602e6-1080-hls.torrent&xt=urn:btih:68af82ebcd9df8335e407b755f38f5fd39c8a6a4&dn=Vu+du+20%2F02%2F21+%3A+%22Plan%C3%A8te+Mars+2050%22&tr=wss%3A%2F%2Fpeertube.stream%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fpeertube.stream%2Ftracker%2Fannounce&ws=https%3A%2F%2Fpeertube.stream%2Fstatic%2Fstreaming-playlists%2Fhls%2Fabece3c3-b9c6-47f4-8040-f3eed8c602e6%2Fabece3c3-b9c6-47f4-8040-f3eed8c602e6-1080-fragmented.mp4", + "height": 1080 + }, + { + "type": "Link", + "mediaType": "video/mp4", + "href": "https://peertube.stream/static/streaming-playlists/hls/abece3c3-b9c6-47f4-8040-f3eed8c602e6/abece3c3-b9c6-47f4-8040-f3eed8c602e6-720-fragmented.mp4", + "height": 720, + "size": 45165123, + "fps": 25 + }, + { + "type": "Link", + "rel": [ + "metadata", + "video/mp4" + ], + "mediaType": "application/json", + "href": "https://peertube.stream/api/v1/videos/abece3c3-b9c6-47f4-8040-f3eed8c602e6/metadata/570056", + "height": 720, + "fps": 25 + }, + { + "type": "Link", + "mediaType": "application/x-bittorrent", + "href": "https://peertube.stream/static/torrents/abece3c3-b9c6-47f4-8040-f3eed8c602e6-720-hls.torrent", + "height": 720 + }, + { + "type": "Link", + "mediaType": "application/x-bittorrent;x-scheme-handler/magnet", + "href": "magnet:?xs=https%3A%2F%2Fpeertube.stream%2Fstatic%2Ftorrents%2Fabece3c3-b9c6-47f4-8040-f3eed8c602e6-720-hls.torrent&xt=urn:btih:8450928a4ffb2a4c5f927a163487c48c05f6e700&dn=Vu+du+20%2F02%2F21+%3A+%22Plan%C3%A8te+Mars+2050%22&tr=wss%3A%2F%2Fpeertube.stream%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fpeertube.stream%2Ftracker%2Fannounce&ws=https%3A%2F%2Fpeertube.stream%2Fstatic%2Fstreaming-playlists%2Fhls%2Fabece3c3-b9c6-47f4-8040-f3eed8c602e6%2Fabece3c3-b9c6-47f4-8040-f3eed8c602e6-720-fragmented.mp4", + "height": 720 + }, + { + "type": "Link", + "mediaType": "video/mp4", + "href": "https://peertube.stream/static/streaming-playlists/hls/abece3c3-b9c6-47f4-8040-f3eed8c602e6/abece3c3-b9c6-47f4-8040-f3eed8c602e6-480-fragmented.mp4", + "height": 480, + "size": 29618534, + "fps": 25 + }, + { + "type": "Link", + "rel": [ + "metadata", + "video/mp4" + ], + "mediaType": "application/json", + "href": "https://peertube.stream/api/v1/videos/abece3c3-b9c6-47f4-8040-f3eed8c602e6/metadata/570042", + "height": 480, + "fps": 25 + }, + { + "type": "Link", + "mediaType": "application/x-bittorrent", + "href": "https://peertube.stream/static/torrents/abece3c3-b9c6-47f4-8040-f3eed8c602e6-480-hls.torrent", + "height": 480 + }, + { + "type": "Link", + "mediaType": "application/x-bittorrent;x-scheme-handler/magnet", + "href": "magnet:?xs=https%3A%2F%2Fpeertube.stream%2Fstatic%2Ftorrents%2Fabece3c3-b9c6-47f4-8040-f3eed8c602e6-480-hls.torrent&xt=urn:btih:39e11181db5f376aa78c94bffcb9ccf2f4bca715&dn=Vu+du+20%2F02%2F21+%3A+%22Plan%C3%A8te+Mars+2050%22&tr=wss%3A%2F%2Fpeertube.stream%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fpeertube.stream%2Ftracker%2Fannounce&ws=https%3A%2F%2Fpeertube.stream%2Fstatic%2Fstreaming-playlists%2Fhls%2Fabece3c3-b9c6-47f4-8040-f3eed8c602e6%2Fabece3c3-b9c6-47f4-8040-f3eed8c602e6-480-fragmented.mp4", + "height": 480 + }, + { + "type": "Link", + "mediaType": "video/mp4", + "href": "https://peertube.stream/static/streaming-playlists/hls/abece3c3-b9c6-47f4-8040-f3eed8c602e6/abece3c3-b9c6-47f4-8040-f3eed8c602e6-360-fragmented.mp4", + "height": 360, + "size": 21771466, + "fps": 25 + }, + { + "type": "Link", + "rel": [ + "metadata", + "video/mp4" + ], + "mediaType": "application/json", + "href": "https://peertube.stream/api/v1/videos/abece3c3-b9c6-47f4-8040-f3eed8c602e6/metadata/570043", + "height": 360, + "fps": 25 + }, + { + "type": "Link", + "mediaType": "application/x-bittorrent", + "href": "https://peertube.stream/static/torrents/abece3c3-b9c6-47f4-8040-f3eed8c602e6-360-hls.torrent", + "height": 360 + }, + { + "type": "Link", + "mediaType": "application/x-bittorrent;x-scheme-handler/magnet", + "href": "magnet:?xs=https%3A%2F%2Fpeertube.stream%2Fstatic%2Ftorrents%2Fabece3c3-b9c6-47f4-8040-f3eed8c602e6-360-hls.torrent&xt=urn:btih:c33aa52822528e29ffd1a615ebe40450e4c61452&dn=Vu+du+20%2F02%2F21+%3A+%22Plan%C3%A8te+Mars+2050%22&tr=wss%3A%2F%2Fpeertube.stream%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fpeertube.stream%2Ftracker%2Fannounce&ws=https%3A%2F%2Fpeertube.stream%2Fstatic%2Fstreaming-playlists%2Fhls%2Fabece3c3-b9c6-47f4-8040-f3eed8c602e6%2Fabece3c3-b9c6-47f4-8040-f3eed8c602e6-360-fragmented.mp4", + "height": 360 + }, + { + "type": "Link", + "mediaType": "video/mp4", + "href": "https://peertube.stream/static/streaming-playlists/hls/abece3c3-b9c6-47f4-8040-f3eed8c602e6/abece3c3-b9c6-47f4-8040-f3eed8c602e6-240-fragmented.mp4", + "height": 240, + "size": 14856165, + "fps": 25 + }, + { + "type": "Link", + "rel": [ + "metadata", + "video/mp4" + ], + "mediaType": "application/json", + "href": "https://peertube.stream/api/v1/videos/abece3c3-b9c6-47f4-8040-f3eed8c602e6/metadata/570057", + "height": 240, + "fps": 25 + }, + { + "type": "Link", + "mediaType": "application/x-bittorrent", + "href": "https://peertube.stream/static/torrents/abece3c3-b9c6-47f4-8040-f3eed8c602e6-240-hls.torrent", + "height": 240 + }, + { + "type": "Link", + "mediaType": "application/x-bittorrent;x-scheme-handler/magnet", + "href": "magnet:?xs=https%3A%2F%2Fpeertube.stream%2Fstatic%2Ftorrents%2Fabece3c3-b9c6-47f4-8040-f3eed8c602e6-240-hls.torrent&xt=urn:btih:157e4cc3e9f15c06e995d6c3388539fdda312771&dn=Vu+du+20%2F02%2F21+%3A+%22Plan%C3%A8te+Mars+2050%22&tr=wss%3A%2F%2Fpeertube.stream%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fpeertube.stream%2Ftracker%2Fannounce&ws=https%3A%2F%2Fpeertube.stream%2Fstatic%2Fstreaming-playlists%2Fhls%2Fabece3c3-b9c6-47f4-8040-f3eed8c602e6%2Fabece3c3-b9c6-47f4-8040-f3eed8c602e6-240-fragmented.mp4", + "height": 240 + }, + { + "type": "Link", + "mediaType": "video/mp4", + "href": "https://peertube.stream/static/streaming-playlists/hls/abece3c3-b9c6-47f4-8040-f3eed8c602e6/abece3c3-b9c6-47f4-8040-f3eed8c602e6-0-fragmented.mp4", + "height": 0, + "size": 6248765, + "fps": 0 + }, + { + "type": "Link", + "rel": [ + "metadata", + "video/mp4" + ], + "mediaType": "application/json", + "href": "https://peertube.stream/api/v1/videos/abece3c3-b9c6-47f4-8040-f3eed8c602e6/metadata/570041", + "height": 0, + "fps": 0 + }, + { + "type": "Link", + "mediaType": "application/x-bittorrent", + "href": "https://peertube.stream/static/torrents/abece3c3-b9c6-47f4-8040-f3eed8c602e6-0-hls.torrent", + "height": 0 + }, + { + "type": "Link", + "mediaType": "application/x-bittorrent;x-scheme-handler/magnet", + "href": "magnet:?xs=https%3A%2F%2Fpeertube.stream%2Fstatic%2Ftorrents%2Fabece3c3-b9c6-47f4-8040-f3eed8c602e6-0-hls.torrent&xt=urn:btih:abc8dc58903d18cf7ec0c0cef92cc5ffe5cb0b5c&dn=Vu+du+20%2F02%2F21+%3A+%22Plan%C3%A8te+Mars+2050%22&tr=wss%3A%2F%2Fpeertube.stream%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fpeertube.stream%2Ftracker%2Fannounce&ws=https%3A%2F%2Fpeertube.stream%2Fstatic%2Fstreaming-playlists%2Fhls%2Fabece3c3-b9c6-47f4-8040-f3eed8c602e6%2Fabece3c3-b9c6-47f4-8040-f3eed8c602e6-0-fragmented.mp4", + "height": 0 + } + ] + } + ], + "likes": "https://peertube.stream/videos/watch/abece3c3-b9c6-47f4-8040-f3eed8c602e6/likes", + "dislikes": "https://peertube.stream/videos/watch/abece3c3-b9c6-47f4-8040-f3eed8c602e6/dislikes", + "shares": "https://peertube.stream/videos/watch/abece3c3-b9c6-47f4-8040-f3eed8c602e6/announces", + "comments": "https://peertube.stream/videos/watch/abece3c3-b9c6-47f4-8040-f3eed8c602e6/comments", + "attributedTo": [ + { + "type": "Person", + "id": "https://peertube.stream/accounts/createurs" + }, + { + "type": "Group", + "id": "https://peertube.stream/video-channels/vu" + } + ], + "to": [ + "https://www.w3.org/ns/activitystreams#Public" + ], + "cc": [ + "https://peertube.stream/accounts/createurs/followers" + ] + }, + "to": [ + "https://www.w3.org/ns/activitystreams#Public" + ], + "cc": [ + "https://peertube.stream/accounts/createurs/followers" + ], + "@context": [ + "https://www.w3.org/ns/activitystreams", + "https://w3id.org/security/v1", + { + "RsaSignature2017": "https://w3id.org/security#RsaSignature2017" + }, + { + "pt": "https://joinpeertube.org/ns#", + "sc": "http://schema.org#", + "Hashtag": "as:Hashtag", + "uuid": "sc:identifier", + "category": "sc:category", + "licence": "sc:license", + "subtitleLanguage": "sc:subtitleLanguage", + "sensitive": "as:sensitive", + "language": "sc:inLanguage", + "isLiveBroadcast": "sc:isLiveBroadcast", + "liveSaveReplay": { + "@type": "sc:Boolean", + "@id": "pt:liveSaveReplay" + }, + "permanentLive": { + "@type": "sc:Boolean", + "@id": "pt:permanentLive" + }, + "Infohash": "pt:Infohash", + "Playlist": "pt:Playlist", + "PlaylistElement": "pt:PlaylistElement", + "originallyPublishedAt": "sc:datePublished", + "views": { + "@type": "sc:Number", + "@id": "pt:views" + }, + "state": { + "@type": "sc:Number", + "@id": "pt:state" + }, + "size": { + "@type": "sc:Number", + "@id": "pt:size" + }, + "fps": { + "@type": "sc:Number", + "@id": "pt:fps" + }, + "startTimestamp": { + "@type": "sc:Number", + "@id": "pt:startTimestamp" + }, + "stopTimestamp": { + "@type": "sc:Number", + "@id": "pt:stopTimestamp" + }, + "position": { + "@type": "sc:Number", + "@id": "pt:position" + }, + "commentsEnabled": { + "@type": "sc:Boolean", + "@id": "pt:commentsEnabled" + }, + "downloadEnabled": { + "@type": "sc:Boolean", + "@id": "pt:downloadEnabled" + }, + "waitTranscoding": { + "@type": "sc:Boolean", + "@id": "pt:waitTranscoding" + }, + "support": { + "@type": "sc:Text", + "@id": "pt:support" + }, + "likes": { + "@id": "as:likes", + "@type": "@id" + }, + "dislikes": { + "@id": "as:dislikes", + "@type": "@id" + }, + "playlists": { + "@id": "pt:playlists", + "@type": "@id" + }, + "shares": { + "@id": "as:shares", + "@type": "@id" + }, + "comments": { + "@id": "as:comments", + "@type": "@id" + } + } + ] +} diff --git a/test/fixtures/share-gs-local.xml b/test/fixtures/share-gs-local.xml deleted file mode 100644 index 9d52eab7b..000000000 --- a/test/fixtures/share-gs-local.xml +++ /dev/null @@ -1,99 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:georss="http://www.georss.org/georss" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:media="http://purl.org/syndication/atommedia" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:statusnet="http://status.net/schema/api/1/"> - <generator uri="https://gnu.io/social" version="1.0.2-dev">GNU social</generator> - <id>https://social.heldscal.la/api/statuses/user_timeline/23211.atom</id> - <title>lambadalambda timeline</title> - <subtitle>Updates from lambadalambda on social.heldscal.la!</subtitle> - <logo>https://social.heldscal.la/avatar/23211-96-20170416114255.jpeg</logo> - <updated>2017-05-03T08:05:41+00:00</updated> -<author> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://social.heldscal.la/user/23211</uri> - <name>lambadalambda</name> - <summary>Call me Deacon Blues.</summary> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/lambadalambda"/> - <link rel="avatar" type="image/jpeg" media:width="236" media:height="236" href="https://social.heldscal.la/avatar/23211-original-20170416114255.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/23211-96-20170416114255.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="48" media:height="48" href="https://social.heldscal.la/avatar/23211-48-20170416114255.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="24" media:height="24" href="https://social.heldscal.la/avatar/23211-24-20170416114257.jpeg"/> - <poco:preferredUsername>lambadalambda</poco:preferredUsername> - <poco:displayName>Constance Variable</poco:displayName> - <poco:note>Call me Deacon Blues.</poco:note> - <poco:address> - <poco:formatted>Berlin</poco:formatted> - </poco:address> - <poco:urls> - <poco:type>homepage</poco:type> - <poco:value>https://heldscal.la</poco:value> - <poco:primary>true</poco:primary> - </poco:urls> - <followers url="https://social.heldscal.la/lambadalambda/subscribers"></followers> - <statusnet:profile_info local_id="23211"></statusnet:profile_info> -</author> - <link href="https://social.heldscal.la/lambadalambda" rel="alternate" type="text/html"/> - <link href="https://social.heldscal.la/main/sup" rel="http://api.friendfeed.com/2008/03#sup" type="application/json"/> - <link href="https://social.heldscal.la/main/push/hub" rel="hub"/> - <link href="https://social.heldscal.la/main/salmon/user/23211" rel="salmon"/> - <link href="https://social.heldscal.la/main/salmon/user/23211" rel="http://salmon-protocol.org/ns/salmon-replies"/> - <link href="https://social.heldscal.la/main/salmon/user/23211" rel="http://salmon-protocol.org/ns/salmon-mention"/> - <link href="https://social.heldscal.la/api/statuses/user_timeline/23211.atom" rel="self" type="application/atom+xml"/> -<entry> - <id>tag:social.heldscal.la,2017-05-03:noticeId=2028428:objectType=note</id> - <title>lambadalambda repeated a notice by lain</title> - <content type="html">RT @<a href="https://pleroma.soykaf.com/users/lain" class="h-card u-url p-nickname mention" title="Lain Iwakura">lain</a> Added returning the entries as xml... let's see if the mastodon hammering stops now.</content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2028428"/> - <activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb> - <published>2017-05-03T08:05:41+00:00</published> - <updated>2017-05-03T08:05:41+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type> - <id>LOCAL_ID</id> - <title></title> - <content type="html">Added returning the entries as xml... let's see if the mastodon hammering stops now.</content> - <link rel="alternate" type="text/html" href="https://pleroma.soykaf.com/objects/4c1bda26-902e-4525-9fcd-b9fd44925193"/> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-05-03T08:04:44+00:00</published> - <updated>2017-05-03T08:04:44+00:00</updated> - <author> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>LOCAL_USER</uri> - <name>lain</name> - <summary>Test account</summary> - <link rel="alternate" type="text/html" href="https://pleroma.soykaf.com/users/lain"/> - <link rel="avatar" type="image/jpeg" media:width="250" media:height="202" href="https://social.heldscal.la/avatar/43188-original-20170429171039.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/43188-96-20170429172422.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="48" media:height="48" href="https://social.heldscal.la/avatar/43188-48-20170429172422.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="24" media:height="24" href="https://social.heldscal.la/avatar/43188-24-20170429181411.jpeg"/> - <poco:preferredUsername>lain</poco:preferredUsername> - <poco:displayName>Lain Iwakura</poco:displayName> - <poco:note>Test account</poco:note> - <statusnet:profile_info local_id="43188"></statusnet:profile_info> - </author> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>https://pleroma.soykaf.com/objects/4c1bda26-902e-4525-9fcd-b9fd44925193</id> - <title>New note by lain</title> - <content type="html">Added returning the entries as xml... let's see if the mastodon hammering stops now.</content> - <link rel="alternate" type="text/html" href="https://pleroma.soykaf.com/objects/4c1bda26-902e-4525-9fcd-b9fd44925193"/> - <status_net notice_id="2028424"></status_net> - </activity:object> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1042737"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/1042737" local_id="1042737" ref="https://pleroma.soykaf.com/contexts/ede39a2b-7cf3-4fa4-8ccd-cb97431bcc22">https://pleroma.soykaf.com/contexts/ede39a2b-7cf3-4fa4-8ccd-cb97431bcc22</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <source> - <id>https://pleroma.soykaf.com/users/lain/feed.atom</id> - <title>Lain Iwakura</title> - <link rel="alternate" type="text/html" href="https://pleroma.soykaf.com/users/lain"/> - <link rel="self" type="application/atom+xml" href="https://pleroma.soykaf.com/users/lain/feed.atom"/> - <icon>https://social.heldscal.la/avatar/43188-96-20170429172422.jpeg</icon> - <updated>2017-05-03T08:04:44+00:00</updated> - </source> - </activity:object> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1042737"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/1042737" local_id="1042737" ref="https://pleroma.soykaf.com/contexts/ede39a2b-7cf3-4fa4-8ccd-cb97431bcc22">https://pleroma.soykaf.com/contexts/ede39a2b-7cf3-4fa4-8ccd-cb97431bcc22</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2028428.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2028428.atom"/> - <statusnet:notice_info local_id="2028428" source="api" repeat_of="2028424"></statusnet:notice_info> -</entry> -</feed> diff --git a/test/fixtures/share-gs.xml b/test/fixtures/share-gs.xml deleted file mode 100644 index ab5e488bd..000000000 --- a/test/fixtures/share-gs.xml +++ /dev/null @@ -1,99 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:georss="http://www.georss.org/georss" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:media="http://purl.org/syndication/atommedia" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:statusnet="http://status.net/schema/api/1/"> - <generator uri="https://gnu.io/social" version="1.0.2-dev">GNU social</generator> - <id>https://social.heldscal.la/api/statuses/user_timeline/23211.atom</id> - <title>lambadalambda timeline</title> - <subtitle>Updates from lambadalambda on social.heldscal.la!</subtitle> - <logo>https://social.heldscal.la/avatar/23211-96-20170416114255.jpeg</logo> - <updated>2017-05-03T08:05:41+00:00</updated> -<author> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://social.heldscal.la/user/23211</uri> - <name>lambadalambda</name> - <summary>Call me Deacon Blues.</summary> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/lambadalambda"/> - <link rel="avatar" type="image/jpeg" media:width="236" media:height="236" href="https://social.heldscal.la/avatar/23211-original-20170416114255.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/23211-96-20170416114255.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="48" media:height="48" href="https://social.heldscal.la/avatar/23211-48-20170416114255.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="24" media:height="24" href="https://social.heldscal.la/avatar/23211-24-20170416114257.jpeg"/> - <poco:preferredUsername>lambadalambda</poco:preferredUsername> - <poco:displayName>Constance Variable</poco:displayName> - <poco:note>Call me Deacon Blues.</poco:note> - <poco:address> - <poco:formatted>Berlin</poco:formatted> - </poco:address> - <poco:urls> - <poco:type>homepage</poco:type> - <poco:value>https://heldscal.la</poco:value> - <poco:primary>true</poco:primary> - </poco:urls> - <followers url="https://social.heldscal.la/lambadalambda/subscribers"></followers> - <statusnet:profile_info local_id="23211"></statusnet:profile_info> -</author> - <link href="https://social.heldscal.la/lambadalambda" rel="alternate" type="text/html"/> - <link href="https://social.heldscal.la/main/sup" rel="http://api.friendfeed.com/2008/03#sup" type="application/json"/> - <link href="https://social.heldscal.la/main/push/hub" rel="hub"/> - <link href="https://social.heldscal.la/main/salmon/user/23211" rel="salmon"/> - <link href="https://social.heldscal.la/main/salmon/user/23211" rel="http://salmon-protocol.org/ns/salmon-replies"/> - <link href="https://social.heldscal.la/main/salmon/user/23211" rel="http://salmon-protocol.org/ns/salmon-mention"/> - <link href="https://social.heldscal.la/api/statuses/user_timeline/23211.atom" rel="self" type="application/atom+xml"/> -<entry> - <id>tag:social.heldscal.la,2017-05-03:noticeId=2028428:objectType=note</id> - <title>lambadalambda repeated a notice by lain</title> - <content type="html">RT @<a href="https://pleroma.soykaf.com/users/lain" class="h-card u-url p-nickname mention" title="Lain Iwakura">lain</a> Added returning the entries as xml... let's see if the mastodon hammering stops now.</content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2028428"/> - <activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb> - <published>2017-05-03T08:05:41+00:00</published> - <updated>2017-05-03T08:05:41+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type> - <id>https://pleroma.soykaf.com/objects/4c1bda26-902e-4525-9fcd-b9fd44925193</id> - <title></title> - <content type="html">Added returning the entries as xml... let's see if the mastodon hammering stops now.</content> - <link rel="alternate" type="text/html" href="https://pleroma.soykaf.com/objects/4c1bda26-902e-4525-9fcd-b9fd44925193"/> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-05-03T08:04:44+00:00</published> - <updated>2017-05-03T08:04:44+00:00</updated> - <author> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://pleroma.soykaf.com/users/lain</uri> - <name>lain</name> - <summary>Test account</summary> - <link rel="alternate" type="text/html" href="https://pleroma.soykaf.com/users/lain"/> - <link rel="avatar" type="image/jpeg" media:width="250" media:height="202" href="https://social.heldscal.la/avatar/43188-original-20170429171039.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/43188-96-20170429172422.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="48" media:height="48" href="https://social.heldscal.la/avatar/43188-48-20170429172422.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="24" media:height="24" href="https://social.heldscal.la/avatar/43188-24-20170429181411.jpeg"/> - <poco:preferredUsername>lain</poco:preferredUsername> - <poco:displayName>Lain Iwakura</poco:displayName> - <poco:note>Test account</poco:note> - <statusnet:profile_info local_id="43188"></statusnet:profile_info> - </author> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>https://pleroma.soykaf.com/objects/4c1bda26-902e-4525-9fcd-b9fd44925193</id> - <title>New note by lain</title> - <content type="html">Added returning the entries as xml... let's see if the mastodon hammering stops now.</content> - <link rel="alternate" type="text/html" href="https://pleroma.soykaf.com/objects/4c1bda26-902e-4525-9fcd-b9fd44925193"/> - <status_net notice_id="2028424"></status_net> - </activity:object> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1042737"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/1042737" local_id="1042737" ref="https://pleroma.soykaf.com/contexts/ede39a2b-7cf3-4fa4-8ccd-cb97431bcc22">https://pleroma.soykaf.com/contexts/ede39a2b-7cf3-4fa4-8ccd-cb97431bcc22</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <source> - <id>https://pleroma.soykaf.com/users/lain/feed.atom</id> - <title>Lain Iwakura</title> - <link rel="alternate" type="text/html" href="https://pleroma.soykaf.com/users/lain"/> - <link rel="self" type="application/atom+xml" href="https://pleroma.soykaf.com/users/lain/feed.atom"/> - <icon>https://social.heldscal.la/avatar/43188-96-20170429172422.jpeg</icon> - <updated>2017-05-03T08:04:44+00:00</updated> - </source> - </activity:object> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1042737"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/1042737" local_id="1042737" ref="https://pleroma.soykaf.com/contexts/ede39a2b-7cf3-4fa4-8ccd-cb97431bcc22">https://pleroma.soykaf.com/contexts/ede39a2b-7cf3-4fa4-8ccd-cb97431bcc22</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2028428.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2028428.atom"/> - <statusnet:notice_info local_id="2028428" source="api" repeat_of="2028424"></statusnet:notice_info> -</entry> -</feed> diff --git a/test/fixtures/share.xml b/test/fixtures/share.xml deleted file mode 100644 index e07b88680..000000000 --- a/test/fixtures/share.xml +++ /dev/null @@ -1,54 +0,0 @@ -<?xml version="1.0"?> -<entry xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:media="http://purl.org/syndication/atommedia" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:mastodon="http://mastodon.social/schema/1.0"> - <id>tag:mastodon.social,2017-05-03:objectId=4934452:objectType=Status</id> - <published>2017-05-03T08:21:09Z</published> - <updated>2017-05-03T08:21:09Z</updated> - <title>lambadalambda shared a status by lain@pleroma.soykaf.com</title> - <author> - <id>https://mastodon.social/users/lambadalambda</id> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://mastodon.social/users/lambadalambda</uri> - <name>lambadalambda</name> - <email>lambadalambda@mastodon.social</email> - <link rel="alternate" type="text/html" href="https://mastodon.social/@lambadalambda"/> - <link rel="avatar" type="image/gif" media:width="120" media:height="120" href="https://files.mastodon.social/accounts/avatars/000/000/264/original/1429214160519.gif"/> - <link rel="header" type="" media:width="700" media:height="335" href="/headers/original/missing.png"/> - <poco:preferredUsername>lambadalambda</poco:preferredUsername> - <poco:displayName>Critical Value</poco:displayName> - <mastodon:scope>public</mastodon:scope> - </author> - <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb> - <activity:object> - <id>https://pleroma.soykaf.com/objects/4c1bda26-902e-4525-9fcd-b9fd44925193</id> - <published>2017-05-03T08:04:44Z</published> - <updated>2017-05-03T08:05:52Z</updated> - <title>New status by lain@pleroma.soykaf.com</title> - <author> - <id>https://pleroma.soykaf.com/users/lain</id> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://pleroma.soykaf.com/users/lain</uri> - <name>lain</name> - <email>lain@pleroma.soykaf.com</email> - <summary type="html">Test account</summary> - <link rel="alternate" type="text/html" href="https://pleroma.soykaf.com/users/lain"/> - <link rel="avatar" type="image/jpeg" media:width="120" media:height="120" href="https://files.mastodon.social/accounts/avatars/000/125/902/original/6B3AFC74ACA841B24CFB94DB9044C84EDE6AFF31C71718B023D413DAED09A68E.jpeg"/> - <link rel="header" type="" media:width="700" media:height="335" href="/headers/original/missing.png"/> - <poco:preferredUsername>lain</poco:preferredUsername> - <poco:displayName>Lain Iwakura</poco:displayName> - <poco:note>Test account</poco:note> - <mastodon:scope>public</mastodon:scope> - </author> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="en">Added returning the entries as xml... let's see if the mastodon hammering stops now.</content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href=""/> - </activity:object> - <content type="html" xml:lang="en">Added returning the entries as xml... let's see if the mastodon hammering stops now.</content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/2232660"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/2232660.atom"/> -</entry> diff --git a/test/fixtures/spoofed-object.json b/test/fixtures/spoofed-object.json new file mode 100644 index 000000000..91e34307d --- /dev/null +++ b/test/fixtures/spoofed-object.json @@ -0,0 +1,26 @@ +{ + "@context": [ + "https://www.w3.org/ns/activitystreams", + "https://patch.cx/schemas/litepub-0.1.jsonld", + { + "@language": "und" + } + ], + "actor": "https://patch.cx/users/rin", + "attachment": [], + "attributedTo": "https://patch.cx/users/rin", + "cc": [ + "https://patch.cx/users/rin/followers" + ], + "content": "Oracle Corporation (NYSE: ORCL) today announced that it has signed a definitive merger agreement to acquire Pleroma AG (FRA: PLA), for $26.50 per share (approximately $10.3 billion). The transaction has been approved by the boards of directors of both companies and should close by early January.", + "context": "https://patch.cx/contexts/spoof", + "id": "https://patch.cx/objects/spoof", + "published": "2020-10-23T18:02:06.038856Z", + "sensitive": false, + "summary": "Oracle buys Pleroma", + "tag": [], + "to": [ + "https://www.w3.org/ns/activitystreams#Public" + ], + "type": "Note" +} diff --git a/test/fixtures/statuses/masto-note.json b/test/fixtures/statuses/masto-note.json new file mode 100644 index 000000000..6b96de473 --- /dev/null +++ b/test/fixtures/statuses/masto-note.json @@ -0,0 +1,47 @@ +{ + "@context": [ + "https://www.w3.org/ns/activitystreams", + { + "ostatus": "http://ostatus.org#", + "atomUri": "ostatus:atomUri", + "inReplyToAtomUri": "ostatus:inReplyToAtomUri", + "conversation": "ostatus:conversation", + "sensitive": "as:sensitive", + "toot": "http://joinmastodon.org/ns#", + "votersCount": "toot:votersCount" + } + ], + "id": "https://example.com/users/{{nickname}}/statuses/{{status_id}}", + "type": "Note", + "summary": null, + "inReplyTo": null, + "published": "2021-02-24T12:40:49Z", + "url": "https://example.com/@{{nickname}}/{{status_id}}", + "attributedTo": "https://example.com/users/{{nickname}}", + "to": [ + "https://www.w3.org/ns/activitystreams#Public" + ], + "cc": [ + "https://example.com/users/{{nickname}}/followers" + ], + "sensitive": false, + "atomUri": "https://example.com/users/{{nickname}}/statuses/{{status_id}}", + "inReplyToAtomUri": null, + "conversation": "tag:example.com,2021-02-24:objectId=15:objectType=Conversation", + "content": "<p></p>", + "contentMap": { + "en": "<p></p>" + }, + "attachment": [], + "tag": [], + "replies": { + "id": "https://example.com/users/{{nickname}}/statuses/{{status_id}}/replies", + "type": "Collection", + "first": { + "type": "CollectionPage", + "next": "https://example.com/users/{{nickname}}/statuses/{{status_id}}/replies?only_other_accounts=true&page=true", + "partOf": "https://example.com/users/{{nickname}}/statuses/{{status_id}}/replies", + "items": [] + } + } +} diff --git a/test/fixtures/statuses/note.json b/test/fixtures/statuses/note.json new file mode 100644 index 000000000..41735cbc5 --- /dev/null +++ b/test/fixtures/statuses/note.json @@ -0,0 +1,27 @@ +{ + "@context": [ + "https://www.w3.org/ns/activitystreams", + "https://example.com/schemas/litepub-0.1.jsonld", + { + "@language": "und" + } + ], + "actor": "https://example.com/users/{{nickname}}", + "attachment": [], + "attributedTo": "https://example.com/users/{{nickname}}", + "cc": [ + "https://example.com/users/{{nickname}}/followers" + ], + "content": "Content", + "context": "https://example.com/contexts/e4b180e1-7403-477f-aeb4-de57e7a3fe7f", + "conversation": "https://example.com/contexts/e4b180e1-7403-477f-aeb4-de57e7a3fe7f", + "id": "https://example.com/objects/{{object_id}}", + "published": "2019-12-15T22:00:05.279583Z", + "sensitive": false, + "summary": "", + "tag": [], + "to": [ + "https://www.w3.org/ns/activitystreams#Public" + ], + "type": "Note" +} diff --git a/test/fixtures/tesla_mock/7369654.atom b/test/fixtures/tesla_mock/7369654.atom deleted file mode 100644 index 74fd9ce6b..000000000 --- a/test/fixtures/tesla_mock/7369654.atom +++ /dev/null @@ -1,44 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<entry xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:georss="http://www.georss.org/georss" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:media="http://purl.org/syndication/atommedia" xmlns:statusnet="http://status.net/schema/api/1/"> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>tag:shitposter.club,2018-02-22:noticeId=7369654:objectType=comment</id> - <title>New comment by shpuld</title> - <content type="html">@<a href="https://testing.pleroma.lol/users/lain" class="h-card mention" title="Rael Electric Razor">lain</a> me far right</content> - <link rel="alternate" type="text/html" href="https://shitposter.club/notice/7369654"/> - <status_net notice_id="7369654"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2018-02-22T09:20:12+00:00</published> - <updated>2018-02-22T09:20:12+00:00</updated> - <author> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://shitposter.club/user/5381</uri> - <name>shpuld</name> - <link rel="alternate" type="text/html" href="https://shitposter.club/shpuld"/> - <link rel="avatar" type="image/png" media:width="864" media:height="864" href="https://shitposter.club/avatar/5381-original-20171230093854.png"/> - <link rel="avatar" type="image/png" media:width="96" media:height="96" href="https://shitposter.club/avatar/5381-96-20171230093854.png"/> - <link rel="avatar" type="image/png" media:width="48" media:height="48" href="https://shitposter.club/avatar/5381-48-20171230093854.png"/> - <link rel="avatar" type="image/png" media:width="24" media:height="24" href="https://shitposter.club/avatar/5381-24-20171230093900.png"/> - <poco:preferredUsername>shpuld</poco:preferredUsername> - <poco:displayName>shp</poco:displayName> - <followers url="https://shitposter.club/shpuld/subscribers"></followers> - <statusnet:profile_info local_id="5381"></statusnet:profile_info> - </author> - <thr:in-reply-to ref="https://testing.pleroma.lol/objects/b319022a-4946-44c5-9de9-34801f95507b" href="https://testing.pleroma.lol/objects/b319022a-4946-44c5-9de9-34801f95507b"></thr:in-reply-to> - <link rel="related" href="https://testing.pleroma.lol/objects/b319022a-4946-44c5-9de9-34801f95507b"/> - <link rel="ostatus:conversation" href="https://shitposter.club/conversation/4378601"/> - <ostatus:conversation href="https://shitposter.club/conversation/4378601" local_id="4378601" ref="tag:shitposter.club,2018-02-22:objectType=thread:nonce=e5a7c72d60a9c0e4">tag:shitposter.club,2018-02-22:objectType=thread:nonce=e5a7c72d60a9c0e4</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://testing.pleroma.lol/users/lain"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <source> - <id>https://shitposter.club/api/statuses/user_timeline/5381.atom</id> - <title>shp</title> - <link rel="alternate" type="text/html" href="https://shitposter.club/shpuld"/> - <link rel="self" type="application/atom+xml" href="https://shitposter.club/api/statuses/user_timeline/5381.atom"/> - <link rel="license" href="https://shitposter.club/doc/tos"/> - <icon>https://shitposter.club/avatar/5381-96-20171230093854.png</icon> - <updated>2018-02-23T13:30:15+00:00</updated> - </source> - <link rel="self" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7369654.atom"/> - <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7369654.atom"/> - <statusnet:notice_info local_id="7369654" source="Pleroma FE"></statusnet:notice_info> -</entry> diff --git a/test/fixtures/tesla_mock/admin@mastdon.example.org.json b/test/fixtures/tesla_mock/admin@mastdon.example.org.json index a911b979a..f961ccb36 100644 --- a/test/fixtures/tesla_mock/admin@mastdon.example.org.json +++ b/test/fixtures/tesla_mock/admin@mastdon.example.org.json @@ -1,20 +1,24 @@ { - "@context": ["https://www.w3.org/ns/activitystreams", "https://w3id.org/security/v1", { - "manuallyApprovesFollowers": "as:manuallyApprovesFollowers", - "sensitive": "as:sensitive", - "movedTo": "as:movedTo", - "Hashtag": "as:Hashtag", - "ostatus": "http://ostatus.org#", - "atomUri": "ostatus:atomUri", - "inReplyToAtomUri": "ostatus:inReplyToAtomUri", - "conversation": "ostatus:conversation", - "toot": "http://joinmastodon.org/ns#", - "Emoji": "toot:Emoji", - "alsoKnownAs": { - "@id": "as:alsoKnownAs", - "@type": "@id" + "@context": [ + "https://www.w3.org/ns/activitystreams", + "https://w3id.org/security/v1", + { + "manuallyApprovesFollowers": "as:manuallyApprovesFollowers", + "sensitive": "as:sensitive", + "movedTo": "as:movedTo", + "Hashtag": "as:Hashtag", + "ostatus": "http://ostatus.org#", + "atomUri": "ostatus:atomUri", + "inReplyToAtomUri": "ostatus:inReplyToAtomUri", + "conversation": "ostatus:conversation", + "toot": "http://joinmastodon.org/ns#", + "Emoji": "toot:Emoji", + "alsoKnownAs": { + "@id": "as:alsoKnownAs", + "@type": "@id" + } } - }], + ], "id": "http://mastodon.example.org/users/admin", "type": "Person", "following": "http://mastodon.example.org/users/admin/following", @@ -23,6 +27,7 @@ "outbox": "http://mastodon.example.org/users/admin/outbox", "preferredUsername": "admin", "name": null, + "discoverable": "true", "summary": "\u003cp\u003e\u003c/p\u003e", "url": "http://mastodon.example.org/@admin", "manuallyApprovesFollowers": false, @@ -34,7 +39,8 @@ "owner": "http://mastodon.example.org/users/admin", "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtc4Tir+3ADhSNF6VKrtW\nOU32T01w7V0yshmQei38YyiVwVvFu8XOP6ACchkdxbJ+C9mZud8qWaRJKVbFTMUG\nNX4+6Q+FobyuKrwN7CEwhDALZtaN2IPbaPd6uG1B7QhWorrY+yFa8f2TBM3BxnUy\nI4T+bMIZIEYG7KtljCBoQXuTQmGtuffO0UwJksidg2ffCF5Q+K//JfQagJ3UzrR+\nZXbKMJdAw4bCVJYs4Z5EhHYBwQWiXCyMGTd7BGlmMkY6Av7ZqHKC/owp3/0EWDNz\nNqF09Wcpr3y3e8nA10X40MJqp/wR+1xtxp+YGbq/Cj5hZGBG7etFOmIpVBrDOhry\nBwIDAQAB\n-----END PUBLIC KEY-----\n" }, - "attachment": [{ + "attachment": [ + { "type": "PropertyValue", "name": "foo", "value": "bar" @@ -58,5 +64,7 @@ "mediaType": "image/png", "url": "https://cdn.niu.moe/accounts/headers/000/033/323/original/850b3448fa5fd477.png" }, - "alsoKnownAs": ["http://example.org/users/foo"] -} + "alsoKnownAs": [ + "http://example.org/users/foo" + ] +}
\ No newline at end of file diff --git a/test/fixtures/tesla_mock/atarifrosch_feed.xml b/test/fixtures/tesla_mock/atarifrosch_feed.xml deleted file mode 100644 index e00df782e..000000000 --- a/test/fixtures/tesla_mock/atarifrosch_feed.xml +++ /dev/null @@ -1,473 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:georss="http://www.georss.org/georss" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:media="http://purl.org/syndication/atommedia" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:statusnet="http://status.net/schema/api/1/"> - <generator uri="https://gnu.io/social" version="1.2.0-alpha2">GNU social</generator> - <id>https://social.stopwatchingus-heidelberg.de/api/statuses/user_timeline/18330.atom</id> - <title>atarifrosch-Zeitleiste</title> - <subtitle>Aktualisierungen von atarifrosch auf social.stopwatchingus-heidelberg.de!</subtitle> - <logo>https://social.stopwatchingus-heidelberg.de/avatar/18330-96-20150628163706.png</logo> - <updated>2017-08-24T12:06:55+02:00</updated> -<author> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://social.stopwatchingus-heidelberg.de/user/18330</uri> - <name>atarifrosch</name> - <summary>Nerd, Pirat, Debian user, CAcert assurer, Geocacher, Freifunker. Autismus/Depression, agender. GnuPG Key-ID: 0xBCF81ADE</summary> - <link rel="alternate" type="text/html" href="https://social.stopwatchingus-heidelberg.de/atarifrosch"/> - <link rel="avatar" type="image/png" media:width="480" media:height="480" href="https://social.stopwatchingus-heidelberg.de/avatar/18330-480-20150628163705.png"/> - <link rel="avatar" type="image/png" media:width="96" media:height="96" href="https://social.stopwatchingus-heidelberg.de/avatar/18330-96-20150628163706.png"/> - <link rel="avatar" type="image/png" media:width="48" media:height="48" href="https://social.stopwatchingus-heidelberg.de/avatar/18330-48-20150628163713.png"/> - <link rel="avatar" type="image/png" media:width="24" media:height="24" href="https://social.stopwatchingus-heidelberg.de/avatar/18330-24-20150628163714.png"/> - <poco:preferredUsername>atarifrosch</poco:preferredUsername> - <poco:displayName>Atari-Frosch</poco:displayName> - <poco:note>Nerd, Pirat, Debian user, CAcert assurer, Geocacher, Freifunker. Autismus/Depression, agender. GnuPG Key-ID: 0xBCF81ADE</poco:note> - <poco:address> - <poco:formatted>Düsseldorf, NRW, Germany</poco:formatted> - </poco:address> - <poco:urls> - <poco:type>homepage</poco:type> - <poco:value>https://www.atari-frosch.de/</poco:value> - <poco:primary>true</poco:primary> - </poco:urls> - <followers url="https://social.stopwatchingus-heidelberg.de/atarifrosch/subscribers"></followers> - <statusnet:profile_info local_id="18330"></statusnet:profile_info> -</author> - <link href="https://social.stopwatchingus-heidelberg.de/atarifrosch" rel="alternate" type="text/html"/> - <link href="https://social.stopwatchingus-heidelberg.de/main/sup" rel="http://api.friendfeed.com/2008/03#sup" type="application/json"/> - <link href="https://social.stopwatchingus-heidelberg.de/api/statuses/user_timeline/18330.atom?max_id=976980" rel="next" type="application/atom+xml"/> - <link href="https://social.stopwatchingus-heidelberg.de/main/push/hub" rel="hub"/> - <link href="https://social.stopwatchingus-heidelberg.de/main/salmon/user/18330" rel="salmon"/> - <link href="https://social.stopwatchingus-heidelberg.de/main/salmon/user/18330" rel="http://salmon-protocol.org/ns/salmon-replies"/> - <link href="https://social.stopwatchingus-heidelberg.de/main/salmon/user/18330" rel="http://salmon-protocol.org/ns/salmon-mention"/> - <link href="https://social.stopwatchingus-heidelberg.de/api/statuses/user_timeline/18330.atom" rel="self" type="application/atom+xml"/> -<entry> - <id>tag:social.stopwatchingus-heidelberg.de,2017-08-24:noticeId=978735:objectType=note</id> - <title>atarifrosch repeated a notice by hoergen</title> - <content type="html">RT @<a href="https://social.hoergen.org/hoergen" class="h-card mention" title="hoergen">hoergen</a> Das falsche Bild der Tagesschau &quot;Auffallend &quot;erfolgreich&quot; - Andrea Nahles und Manuela Schwesig&quot; #<span class="tag"><a href="https://social.stopwatchingus-heidelberg.de/tag/geringverdiener" rel="tag">Geringverdiener</a></span> #<span class="tag"><a href="https://social.stopwatchingus-heidelberg.de/tag/mindestlohn" rel="tag">Mindestlohn</a></span> #<span class="tag"><a href="https://social.stopwatchingus-heidelberg.de/tag/mannxismus" rel="tag">mannxismus</a></span> #<span class="tag"><a href="https://social.stopwatchingus-heidelberg.de/tag/erwerbsminderungsrente" rel="tag">Erwerbsminderungsrente</a></span> #<span class="tag"><a href="https://social.stopwatchingus-heidelberg.de/tag/arbeitnehmerflexibilisierung" rel="tag">ArbeitnehmerFlexibilisierung</a></span> #<span class="tag"><a href="https://social.stopwatchingus-heidelberg.de/tag/altersarmut" rel="tag">AltersArmut</a></span> ..... <a href="http://www.tagesschau.de/inland/btw17/bilanz-schwesig-nahles-101.html" title="http://www.tagesschau.de/inland/btw17/bilanz-schwesig-nahles-101.html" class="attachment" id="attachment-450858" rel="nofollow external">http://www.tagesschau.de/inland/btw17/bilanz-schwesig-nahles-101.html</a></content> - <link rel="alternate" type="text/html">https://social.stopwatchingus-heidelberg.de/notice/978735</link> - <activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb> - <published>2017-08-24T09:18:25+00:00</published> - <updated>2017-08-24T09:18:25+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type> - <id>tag:social.hoergen.org,2017-08-24:noticeId=222320:objectType=note</id> - <title></title> - <content type="html">Das falsche Bild der Tagesschau <br /> &quot;Auffallend &quot;erfolgreich&quot; - Andrea Nahles und Manuela Schwesig&quot; #<span class="tag"><a href="https://social.hoergen.org/tag/geringverdiener" rel="tag">Geringverdiener</a></span> #<span class="tag"><a href="https://social.hoergen.org/tag/mindestlohn" rel="tag">Mindestlohn</a></span> #<span class="tag"><a href="https://social.hoergen.org/tag/mannxismus" rel="tag">mannxismus</a></span> #<span class="tag"><a href="https://social.hoergen.org/tag/erwerbsminderungsrente" rel="tag">Erwerbsminderungsrente</a></span> #<span class="tag"><a href="https://social.hoergen.org/tag/arbeitnehmerflexibilisierung" rel="tag">ArbeitnehmerFlexibilisierung</a></span> #<span class="tag"><a href="https://social.hoergen.org/tag/altersarmut" rel="tag">AltersArmut</a></span> ..... <br /> <br /> <a href="http://www.tagesschau.de/inland/btw17/bilanz-schwesig-nahles-101.html" title="http://www.tagesschau.de/inland/btw17/bilanz-schwesig-nahles-101.html" rel="nofollow external noreferrer" class="attachment">http://www.tagesschau.de/inland/btw17/bilanz-schwesig-nahles-101.html</a></content> - <link rel="alternate" type="text/html">https://social.hoergen.org/notice/222320</link> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-08-24T07:36:31+00:00</published> - <updated>2017-08-24T07:36:31+00:00</updated> - <author> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://social.hoergen.org/user/2</uri> - <name>hoergen</name> - <summary>aka Andi Memyself #humanist #nerd Menschen liebhabender Misanthrop und auch sonst sehr vielseitig interessiert.</summary> - <link rel="alternate" type="text/html" href="https://social.hoergen.org/hoergen"/> - <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.stopwatchingus-heidelberg.de/avatar/54316-original-20170824072526.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.stopwatchingus-heidelberg.de/avatar/54316-original-20170824072526.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="48" media:height="48" href="https://social.stopwatchingus-heidelberg.de/avatar/54316-48-20170824072544.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="24" media:height="24" href="https://social.stopwatchingus-heidelberg.de/avatar/54316-24-20170824074851.jpeg"/> - <poco:preferredUsername>hoergen</poco:preferredUsername> - <poco:displayName>hoergen</poco:displayName> - <poco:note>aka Andi Memyself #humanist #nerd Menschen liebhabender Misanthrop und auch sonst sehr vielseitig interessiert.</poco:note> - <poco:address> - <poco:formatted>Berlin</poco:formatted> - </poco:address> - <poco:urls> - <poco:type>homepage</poco:type> - <poco:value>https://hyperblog.de/hoergen/</poco:value> - <poco:primary>true</poco:primary> - </poco:urls> - <statusnet:profile_info local_id="54316"></statusnet:profile_info> - </author> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:social.hoergen.org,2017-08-24:noticeId=222320:objectType=note</id> - <title>New note by hoergen</title> - <content type="html">Das falsche Bild der Tagesschau <br /> &quot;Auffallend &quot;erfolgreich&quot; - Andrea Nahles und Manuela Schwesig&quot; #<span class="tag"><a href="https://social.hoergen.org/tag/geringverdiener" rel="tag">Geringverdiener</a></span> #<span class="tag"><a href="https://social.hoergen.org/tag/mindestlohn" rel="tag">Mindestlohn</a></span> #<span class="tag"><a href="https://social.hoergen.org/tag/mannxismus" rel="tag">mannxismus</a></span> #<span class="tag"><a href="https://social.hoergen.org/tag/erwerbsminderungsrente" rel="tag">Erwerbsminderungsrente</a></span> #<span class="tag"><a href="https://social.hoergen.org/tag/arbeitnehmerflexibilisierung" rel="tag">ArbeitnehmerFlexibilisierung</a></span> #<span class="tag"><a href="https://social.hoergen.org/tag/altersarmut" rel="tag">AltersArmut</a></span> ..... <br /> <br /> <a href="http://www.tagesschau.de/inland/btw17/bilanz-schwesig-nahles-101.html" title="http://www.tagesschau.de/inland/btw17/bilanz-schwesig-nahles-101.html" rel="nofollow external noreferrer" class="attachment">http://www.tagesschau.de/inland/btw17/bilanz-schwesig-nahles-101.html</a></content> - <link rel="alternate" type="text/html" href="https://social.hoergen.org/notice/222320"/> - <status_net notice_id="978711"></status_net> - </activity:object> - <link rel="ostatus:conversation" href="https://social.hoergen.org/conversation/98616"/> - <ostatus:conversation>https://social.hoergen.org/conversation/98616</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <category term="altersarmut"></category> - <category term="arbeitnehmerflexibilisierung"></category> - <category term="erwerbsminderungsrente"></category> - <category term="geringverdiener"></category> - <category term="mannxismus"></category> - <category term="mindestlohn"></category> - <source> - <id>https://social.hoergen.org/api/statuses/user_timeline/2.atom</id> - <title>hoergen</title> - <link rel="alternate" type="text/html" href="https://social.hoergen.org/hoergen"/> - <link rel="self" type="application/atom+xml" href="https://social.hoergen.org/api/statuses/user_timeline/2.atom"/> - <icon>https://social.stopwatchingus-heidelberg.de/avatar/54316-original-20170824072526.jpeg</icon> - <updated>2017-08-24T09:48:30+00:00</updated> - </source> - </activity:object> - <link rel="ostatus:conversation" href="https://social.hoergen.org/conversation/98616"/> - <ostatus:conversation>https://social.hoergen.org/conversation/98616</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <category term="altersarmut"></category> - <category term="arbeitnehmerflexibilisierung"></category> - <category term="erwerbsminderungsrente"></category> - <category term="geringverdiener"></category> - <category term="mannxismus"></category> - <category term="mindestlohn"></category> - <link rel="self" type="application/atom+xml" href="https://social.stopwatchingus-heidelberg.de/api/statuses/show/978735.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.stopwatchingus-heidelberg.de/api/statuses/show/978735.atom"/> - <statusnet:notice_info local_id="978735" source="web" repeat_of="978711"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>tag:social.stopwatchingus-heidelberg.de,2017-08-24:noticeId=978734:objectType=comment</id> - <title>New comment by atarifrosch</title> - <content type="html">Jo, die Anzahl der Hartz-IV-Sanktionen nennt sie genausowenig wie die Anzahl der Menschen, die von den Repressionsbehörden in Obdachlosigkeit und Suizid getrieben wurden. Das würde die Erfolgszahlen dann doch ein wenig trüben, nech?</content> - <link rel="alternate" type="text/html" href="https://social.stopwatchingus-heidelberg.de/notice/978734"/> - <status_net notice_id="978734"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-08-24T09:18:13+00:00</published> - <updated>2017-08-24T09:18:13+00:00</updated> - <thr:in-reply-to ref="tag:social.hoergen.org,2017-08-24:noticeId=222320:objectType=note" href="https://social.hoergen.org/notice/222320"></thr:in-reply-to> - <link rel="related" href="https://social.hoergen.org/notice/222320"/> - <link rel="ostatus:conversation" href="https://social.hoergen.org/conversation/98616"/> - <ostatus:conversation>https://social.hoergen.org/conversation/98616</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://social.hoergen.org/user/2"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.stopwatchingus-heidelberg.de/api/statuses/show/978734.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.stopwatchingus-heidelberg.de/api/statuses/show/978734.atom"/> - <statusnet:notice_info local_id="978734" source="web"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:social.stopwatchingus-heidelberg.de,2017-08-24:noticeId=978732:objectType=note</id> - <title>New note by atarifrosch</title> - <content type="html">Moin-quak.</content> - <link rel="alternate" type="text/html" href="https://social.stopwatchingus-heidelberg.de/notice/978732"/> - <status_net notice_id="978732"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-08-24T09:09:39+00:00</published> - <updated>2017-08-24T09:09:39+00:00</updated> - <link rel="ostatus:conversation" href="tag:social.stopwatchingus-heidelberg.de,2017-08-24:noticeId=978732:objectType=thread:crc32=2f92b7b6"/> - <ostatus:conversation>tag:social.stopwatchingus-heidelberg.de,2017-08-24:noticeId=978732:objectType=thread:crc32=2f92b7b6</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.stopwatchingus-heidelberg.de/api/statuses/show/978732.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.stopwatchingus-heidelberg.de/api/statuses/show/978732.atom"/> - <statusnet:notice_info local_id="978732" source="web"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:social.stopwatchingus-heidelberg.de,2017-08-23:noticeId=978594:objectType=note</id> - <title>New note by atarifrosch</title> - <content type="html">n8-quak!</content> - <link rel="alternate" type="text/html" href="https://social.stopwatchingus-heidelberg.de/notice/978594"/> - <status_net notice_id="978594"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-08-23T21:39:54+00:00</published> - <updated>2017-08-23T21:39:54+00:00</updated> - <link rel="ostatus:conversation" href="tag:social.stopwatchingus-heidelberg.de,2017-08-23:noticeId=978594:objectType=thread:crc32=9bdb0ac9"/> - <ostatus:conversation>tag:social.stopwatchingus-heidelberg.de,2017-08-23:noticeId=978594:objectType=thread:crc32=9bdb0ac9</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.stopwatchingus-heidelberg.de/api/statuses/show/978594.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.stopwatchingus-heidelberg.de/api/statuses/show/978594.atom"/> - <statusnet:notice_info local_id="978594" source="web"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:social.stopwatchingus-heidelberg.de,2017-08-23:noticeId=978503:objectType=note</id> - <title>New note by atarifrosch</title> - <content type="html">2017-08-16 Michal Špaček: Post a boarding pass on Facebook, get your account stolen – Post a boarding pass on Facebook, get your account stolen (gilt übrinx nicht nur für Facebook)</content> - <link rel="alternate" type="text/html" href="https://social.stopwatchingus-heidelberg.de/notice/978503"/> - <status_net notice_id="978503"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-08-23T15:14:29+00:00</published> - <updated>2017-08-23T15:14:29+00:00</updated> - <link rel="ostatus:conversation" href="tag:social.stopwatchingus-heidelberg.de,2017-08-23:noticeId=978503:objectType=thread:crc32=3de05c3a"/> - <ostatus:conversation>tag:social.stopwatchingus-heidelberg.de,2017-08-23:noticeId=978503:objectType=thread:crc32=3de05c3a</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.stopwatchingus-heidelberg.de/api/statuses/show/978503.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.stopwatchingus-heidelberg.de/api/statuses/show/978503.atom"/> - <statusnet:notice_info local_id="978503" source="web"></statusnet:notice_info> -</entry> -<entry> - <id>tag:social.stopwatchingus-heidelberg.de,2017-08-23:fave:18330:activity:978458:2017-08-23T15:18:19+02:00</id> - <title>Favorite</title> - <content type="html">atarifrosch favorited something by einebiene: Haha, große Überraschung. <a href="http://www.sueddeutsche.de/wirtschaft/abgasaffaere-software-updates-fuer-dieselautos-helfen-kaum-1.3637636" title="http://www.sueddeutsche.de/wirtschaft/abgasaffaere-software-updates-fuer-dieselautos-helfen-kaum-1.3637636" rel="nofollow noreferrer" class="attachment">https://quitter.is/url/1122672</a><br /> Was ich an all diesen Artikeln schade finde, ist, daß immer nur auf den Umstieg von Auto zu anderem Auto gesprochen wird. Öffis werden nicht erwähnt, Carsharing nicht, radeln nicht, und in der Stadt wäre ne Vespa auch deutlich besser als ein SUV.</content> - <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb> - <published>2017-08-23T13:18:19+00:00</published> - <updated>2017-08-23T13:18:19+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:quitter.is,2017-08-23:noticeId=4032910:objectType=note</id> - <title>New note by einebiene</title> - <content type="html">Haha, große Überraschung. <a href="http://www.sueddeutsche.de/wirtschaft/abgasaffaere-software-updates-fuer-dieselautos-helfen-kaum-1.3637636" title="http://www.sueddeutsche.de/wirtschaft/abgasaffaere-software-updates-fuer-dieselautos-helfen-kaum-1.3637636" rel="nofollow noreferrer" class="attachment">https://quitter.is/url/1122672</a><br /> Was ich an all diesen Artikeln schade finde, ist, daß immer nur auf den Umstieg von Auto zu anderem Auto gesprochen wird. Öffis werden nicht erwähnt, Carsharing nicht, radeln nicht, und in der Stadt wäre ne Vespa auch deutlich besser als ein SUV.</content> - <link rel="alternate" type="text/html" href="https://quitter.is/notice/4032910"/> - <status_net notice_id="978458"></status_net> - </activity:object> - <thr:in-reply-to ref="tag:quitter.is,2017-08-23:noticeId=4032910:objectType=note" href="https://quitter.is/notice/4032910"></thr:in-reply-to> - <link rel="related" href="https://quitter.is/notice/4032910"/> - <link rel="ostatus:conversation" href="https://quitter.is/conversation/2535246"/> - <ostatus:conversation>https://quitter.is/conversation/2535246</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://quitter.is/user/8380"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <statusnet:notice_info local_id="978464" source="unknown"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:social.stopwatchingus-heidelberg.de,2017-08-23:noticeId=978402:objectType=note</id> - <title>New note by atarifrosch</title> - <content type="html">moin-quak</content> - <link rel="alternate" type="text/html" href="https://social.stopwatchingus-heidelberg.de/notice/978402"/> - <status_net notice_id="978402"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-08-23T10:57:26+00:00</published> - <updated>2017-08-23T10:57:26+00:00</updated> - <link rel="ostatus:conversation" href="tag:social.stopwatchingus-heidelberg.de,2017-08-23:noticeId=978402:objectType=thread:crc32=7050c397"/> - <ostatus:conversation>tag:social.stopwatchingus-heidelberg.de,2017-08-23:noticeId=978402:objectType=thread:crc32=7050c397</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.stopwatchingus-heidelberg.de/api/statuses/show/978402.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.stopwatchingus-heidelberg.de/api/statuses/show/978402.atom"/> - <statusnet:notice_info local_id="978402" source="web"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:social.stopwatchingus-heidelberg.de,2017-08-22:noticeId=978164:objectType=note</id> - <title>New note by atarifrosch</title> - <content type="html">n8-quak</content> - <link rel="alternate" type="text/html" href="https://social.stopwatchingus-heidelberg.de/notice/978164"/> - <status_net notice_id="978164"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-08-22T19:54:30+00:00</published> - <updated>2017-08-22T19:54:30+00:00</updated> - <link rel="ostatus:conversation" href="tag:social.stopwatchingus-heidelberg.de,2017-08-22:noticeId=978164:objectType=thread:crc32=b0a209c7"/> - <ostatus:conversation>tag:social.stopwatchingus-heidelberg.de,2017-08-22:noticeId=978164:objectType=thread:crc32=b0a209c7</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.stopwatchingus-heidelberg.de/api/statuses/show/978164.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.stopwatchingus-heidelberg.de/api/statuses/show/978164.atom"/> - <statusnet:notice_info local_id="978164" source="web"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:social.stopwatchingus-heidelberg.de,2017-08-22:noticeId=978072:objectType=note</id> - <title>New note by atarifrosch</title> - <content type="html">2017-08-22 Bundesverfassungsgericht: Erfolgreiche Verfassungsbeschwerde gegen die Versagung vorläufiger Leistungen für Kosten der Unterkunft und Heizung – <a href="https://www.bundesverfassungsgericht.de/SharedDocs/Pressemitteilungen/DE/2017/bvg17-072.html" title="https://www.bundesverfassungsgericht.de/SharedDocs/Pressemitteilungen/DE/2017/bvg17-072.html" class="attachment" id="attachment-450768" rel="nofollow external">https://www.bundesverfassungsgericht.de/SharedDocs/Pressemitteilungen/DE/2017/bvg17-072.html</a> !<a href="http://quitter.se/group/2184/id" class="h-card group" title="HartzIV (hartziv)">hartziv</a></content> - <link rel="alternate" type="text/html" href="https://social.stopwatchingus-heidelberg.de/notice/978072"/> - <status_net notice_id="978072"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-08-22T12:00:21+00:00</published> - <updated>2017-08-22T12:00:21+00:00</updated> - <link rel="ostatus:conversation" href="tag:social.stopwatchingus-heidelberg.de,2017-08-22:noticeId=978072:objectType=thread:crc32=28a35f44"/> - <ostatus:conversation>tag:social.stopwatchingus-heidelberg.de,2017-08-22:noticeId=978072:objectType=thread:crc32=28a35f44</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href=""/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/group" href="http://quitter.se/group/2184/id"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.stopwatchingus-heidelberg.de/api/statuses/show/978072.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.stopwatchingus-heidelberg.de/api/statuses/show/978072.atom"/> - <statusnet:notice_info local_id="978072" source="web"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:social.stopwatchingus-heidelberg.de,2017-08-22:noticeId=978042:objectType=note</id> - <title>New note by atarifrosch</title> - <content type="html">moin-quak!</content> - <link rel="alternate" type="text/html" href="https://social.stopwatchingus-heidelberg.de/notice/978042"/> - <status_net notice_id="978042"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-08-22T07:55:27+00:00</published> - <updated>2017-08-22T07:55:27+00:00</updated> - <link rel="ostatus:conversation" href="tag:social.stopwatchingus-heidelberg.de,2017-08-22:noticeId=978042:objectType=thread:crc32=f070a9f7"/> - <ostatus:conversation>tag:social.stopwatchingus-heidelberg.de,2017-08-22:noticeId=978042:objectType=thread:crc32=f070a9f7</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.stopwatchingus-heidelberg.de/api/statuses/show/978042.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.stopwatchingus-heidelberg.de/api/statuses/show/978042.atom"/> - <statusnet:notice_info local_id="978042" source="web"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:social.stopwatchingus-heidelberg.de,2017-08-21:noticeId=977914:objectType=note</id> - <title>New note by atarifrosch</title> - <content type="html">So, morgen geht's weiter. n8-quak!</content> - <link rel="alternate" type="text/html" href="https://social.stopwatchingus-heidelberg.de/notice/977914"/> - <status_net notice_id="977914"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-08-21T22:09:53+00:00</published> - <updated>2017-08-21T22:09:53+00:00</updated> - <link rel="ostatus:conversation" href="tag:social.stopwatchingus-heidelberg.de,2017-08-21:noticeId=977914:objectType=thread:crc32=c0a9f7fa"/> - <ostatus:conversation>tag:social.stopwatchingus-heidelberg.de,2017-08-21:noticeId=977914:objectType=thread:crc32=c0a9f7fa</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.stopwatchingus-heidelberg.de/api/statuses/show/977914.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.stopwatchingus-heidelberg.de/api/statuses/show/977914.atom"/> - <statusnet:notice_info local_id="977914" source="web"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:social.stopwatchingus-heidelberg.de,2017-08-21:noticeId=977710:objectType=note</id> - <title>New note by atarifrosch</title> - <content type="html">moin-quak.</content> - <link rel="alternate" type="text/html" href="https://social.stopwatchingus-heidelberg.de/notice/977710"/> - <status_net notice_id="977710"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-08-21T08:58:26+00:00</published> - <updated>2017-08-21T08:58:26+00:00</updated> - <link rel="ostatus:conversation" href="tag:social.stopwatchingus-heidelberg.de,2017-08-21:noticeId=977710:objectType=thread:crc32=60cfb466"/> - <ostatus:conversation>tag:social.stopwatchingus-heidelberg.de,2017-08-21:noticeId=977710:objectType=thread:crc32=60cfb466</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.stopwatchingus-heidelberg.de/api/statuses/show/977710.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.stopwatchingus-heidelberg.de/api/statuses/show/977710.atom"/> - <statusnet:notice_info local_id="977710" source="web"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:social.stopwatchingus-heidelberg.de,2017-08-20:noticeId=977526:objectType=note</id> - <title>New note by atarifrosch</title> - <content type="html">Meine Augen meinen, für heute sei es genug. Nun denn. n8-quak.</content> - <link rel="alternate" type="text/html" href="https://social.stopwatchingus-heidelberg.de/notice/977526"/> - <status_net notice_id="977526"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-08-20T19:58:16+00:00</published> - <updated>2017-08-20T19:58:16+00:00</updated> - <link rel="ostatus:conversation" href="tag:social.stopwatchingus-heidelberg.de,2017-08-20:noticeId=977526:objectType=thread:crc32=ce79634"/> - <ostatus:conversation>tag:social.stopwatchingus-heidelberg.de,2017-08-20:noticeId=977526:objectType=thread:crc32=ce79634</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.stopwatchingus-heidelberg.de/api/statuses/show/977526.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.stopwatchingus-heidelberg.de/api/statuses/show/977526.atom"/> - <statusnet:notice_info local_id="977526" source="web"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:social.stopwatchingus-heidelberg.de,2017-08-20:noticeId=977369:objectType=note</id> - <title>New note by atarifrosch</title> - <content type="html">[Blog] Im Netz aufgefischt #<span class="tag"><a href="https://social.stopwatchingus-heidelberg.de/tag/330" rel="tag">330</a></span> – <a href="https://blog.atari-frosch.de/2017/08/20/im-netz-aufgefischt-330/" title="https://blog.atari-frosch.de/2017/08/20/im-netz-aufgefischt-330/" class="attachment" id="attachment-450668" rel="nofollow external">https://blog.atari-frosch.de/2017/08/20/im-netz-aufgefischt-330/</a> (was ich diese Woche so gelesen habe)</content> - <link rel="alternate" type="text/html" href="https://social.stopwatchingus-heidelberg.de/notice/977369"/> - <status_net notice_id="977369"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-08-20T09:14:07+00:00</published> - <updated>2017-08-20T09:14:07+00:00</updated> - <link rel="ostatus:conversation" href="tag:social.stopwatchingus-heidelberg.de,2017-08-20:noticeId=977369:objectType=thread:crc32=2f800b86"/> - <ostatus:conversation>tag:social.stopwatchingus-heidelberg.de,2017-08-20:noticeId=977369:objectType=thread:crc32=2f800b86</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <category term="330"></category> - <link rel="self" type="application/atom+xml" href="https://social.stopwatchingus-heidelberg.de/api/statuses/show/977369.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.stopwatchingus-heidelberg.de/api/statuses/show/977369.atom"/> - <statusnet:notice_info local_id="977369" source="web"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:social.stopwatchingus-heidelberg.de,2017-08-19:noticeId=977268:objectType=note</id> - <title>New note by atarifrosch</title> - <content type="html">Fast ständig husten müssen ist echt anstrengend … naja, n8-quak.</content> - <link rel="alternate" type="text/html" href="https://social.stopwatchingus-heidelberg.de/notice/977268"/> - <status_net notice_id="977268"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-08-19T21:59:20+00:00</published> - <updated>2017-08-19T21:59:20+00:00</updated> - <link rel="ostatus:conversation" href="tag:social.stopwatchingus-heidelberg.de,2017-08-19:noticeId=977268:objectType=thread:crc32=deda767a"/> - <ostatus:conversation>tag:social.stopwatchingus-heidelberg.de,2017-08-19:noticeId=977268:objectType=thread:crc32=deda767a</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.stopwatchingus-heidelberg.de/api/statuses/show/977268.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.stopwatchingus-heidelberg.de/api/statuses/show/977268.atom"/> - <statusnet:notice_info local_id="977268" source="web"></statusnet:notice_info> -</entry> -<entry> - <id>tag:social.stopwatchingus-heidelberg.de,2017-08-19:fave:18330:activity:977146:2017-08-19T21:39:26+02:00</id> - <title>Favorite</title> - <content type="html">atarifrosch favorited something by einebienezwo: Ich mach gerade Kompetenztraining.<br /> Ich trainiere die Kompetenz, eine halb aufgegessene Gummibärchentüte nicht ganz aufzuessen.</content> - <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb> - <published>2017-08-19T19:39:26+00:00</published> - <updated>2017-08-19T19:39:26+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:gnusocial.de,2017-08-19:noticeId=11011264:objectType=note</id> - <title>New note by einebienezwo</title> - <content type="html">Ich mach gerade Kompetenztraining.<br /> Ich trainiere die Kompetenz, eine halb aufgegessene Gummibärchentüte nicht ganz aufzuessen.</content> - <link rel="alternate" type="text/html" href="https://gnusocial.de/notice/11011264"/> - <status_net notice_id="977146"></status_net> - </activity:object> - <thr:in-reply-to ref="tag:gnusocial.de,2017-08-19:noticeId=11011264:objectType=note" href="https://gnusocial.de/notice/11011264"></thr:in-reply-to> - <link rel="related" href="https://gnusocial.de/notice/11011264"/> - <link rel="ostatus:conversation" href="https://gnusocial.de/conversation/9363945"/> - <ostatus:conversation>https://gnusocial.de/conversation/9363945</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://gnusocial.de/user/219865"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <statusnet:notice_info local_id="977243" source="unknown"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>tag:social.stopwatchingus-heidelberg.de,2017-08-19:noticeId=977242:objectType=comment</id> - <title>New comment by atarifrosch</title> - <content type="html">Wir hatten hier schon Ordnungsdienst auf'm Radweg. Fotografisch dokumentiert (nicht von mir, Bekannter hatte es gesehen). Da hatte grad 'ne Pizzeria neu eröffnet …</content> - <link rel="alternate" type="text/html" href="https://social.stopwatchingus-heidelberg.de/notice/977242"/> - <status_net notice_id="977242"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-08-19T19:38:53+00:00</published> - <updated>2017-08-19T19:38:53+00:00</updated> - <thr:in-reply-to ref="tag:gnusocial.de,2017-08-19:noticeId=11010978:objectType=note" href="https://gnusocial.de/notice/11010978"></thr:in-reply-to> - <link rel="related" href="https://gnusocial.de/notice/11010978"/> - <link rel="ostatus:conversation" href="https://gnusocial.de/conversation/9363813"/> - <ostatus:conversation>https://gnusocial.de/conversation/9363813</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://gnusocial.de/user/219865"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.stopwatchingus-heidelberg.de/api/statuses/show/977242.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.stopwatchingus-heidelberg.de/api/statuses/show/977242.atom"/> - <statusnet:notice_info local_id="977242" source="web"></statusnet:notice_info> -</entry> -<entry> - <id>tag:social.stopwatchingus-heidelberg.de,2017-08-19:fave:18330:activity:977180:2017-08-19T21:37:36+02:00</id> - <title>Favorite</title> - <content type="html">atarifrosch favorited something by jcaktiv: BTW Hallo zusammen &lt;3, wo ich schon mal wieder hier bin</content> - <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb> - <published>2017-08-19T19:37:36+00:00</published> - <updated>2017-08-19T19:37:36+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:quitter.se,2017-08-19:noticeId=17372467:objectType=note</id> - <title>New note by jcaktiv</title> - <content type="html">BTW Hallo zusammen &lt;3, wo ich schon mal wieder hier bin</content> - <link rel="alternate" type="text/html" href="http://quitter.se/notice/17372467"/> - <status_net notice_id="977180"></status_net> - </activity:object> - <thr:in-reply-to ref="tag:quitter.se,2017-08-19:noticeId=17372467:objectType=note" href="http://quitter.se/notice/17372467"></thr:in-reply-to> - <link rel="related" href="http://quitter.se/notice/17372467"/> - <link rel="ostatus:conversation" href="tag:quitter.se,2017-08-19:objectType=thread:nonce=46c1c433d88aaa9f"/> - <ostatus:conversation>tag:quitter.se,2017-08-19:objectType=thread:nonce=46c1c433d88aaa9f</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="http://quitter.se/user/149873"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <statusnet:notice_info local_id="977240" source="unknown"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>tag:social.stopwatchingus-heidelberg.de,2017-08-19:noticeId=976985:objectType=comment</id> - <title>New comment by atarifrosch</title> - <content type="html">Jo, oder einfach mal nachfragen, so als Realitätsabgleich.</content> - <link rel="alternate" type="text/html" href="https://social.stopwatchingus-heidelberg.de/notice/976985"/> - <status_net notice_id="976985"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-08-19T10:34:50+00:00</published> - <updated>2017-08-19T10:34:50+00:00</updated> - <thr:in-reply-to ref="tag:status.pirati.ca,2017-08-19:noticeId=2310317:objectType=note" href="https://status.pirati.ca/notice/2310317"></thr:in-reply-to> - <link rel="related" href="https://status.pirati.ca/notice/2310317"/> - <link rel="ostatus:conversation" href="https://gnusocial.de/conversation/9362516"/> - <ostatus:conversation>https://gnusocial.de/conversation/9362516</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="http://status.pirati.ca/user/2092"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.stopwatchingus-heidelberg.de/api/statuses/show/976985.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.stopwatchingus-heidelberg.de/api/statuses/show/976985.atom"/> - <statusnet:notice_info local_id="976985" source="web"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:social.stopwatchingus-heidelberg.de,2017-08-19:noticeId=976983:objectType=note</id> - <title>New note by atarifrosch</title> - <content type="html">Schöne Alternative zu mit Werbung überladenen kommerziellen Anbietern: <a href="http://ifconfig.at/" title="http://ifconfig.at/" class="attachment" id="attachment-450636" rel="nofollow external">http://ifconfig.at/</a> – eigene IP, Hostname etc. abfragen, mit curl dann auch in Textform zur lokalen Weiterverarbeitung in Scripten etc. Leider (noch?) kein https.</content> - <link rel="alternate" type="text/html" href="https://social.stopwatchingus-heidelberg.de/notice/976983"/> - <status_net notice_id="976983"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-08-19T10:33:04+00:00</published> - <updated>2017-08-19T10:33:04+00:00</updated> - <link rel="ostatus:conversation" href="tag:social.stopwatchingus-heidelberg.de,2017-08-19:noticeId=976983:objectType=thread:crc32=4a3593c0"/> - <ostatus:conversation>tag:social.stopwatchingus-heidelberg.de,2017-08-19:noticeId=976983:objectType=thread:crc32=4a3593c0</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.stopwatchingus-heidelberg.de/api/statuses/show/976983.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.stopwatchingus-heidelberg.de/api/statuses/show/976983.atom"/> - <statusnet:notice_info local_id="976983" source="web"></statusnet:notice_info> -</entry> -</feed> diff --git a/test/fixtures/tesla_mock/emelie.atom b/test/fixtures/tesla_mock/emelie.atom deleted file mode 100644 index ddaa1c6ca..000000000 --- a/test/fixtures/tesla_mock/emelie.atom +++ /dev/null @@ -1,306 +0,0 @@ -<?xml version="1.0"?> -<feed xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:media="http://purl.org/syndication/atommedia" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:mastodon="http://mastodon.social/schema/1.0"> - <id>https://mastodon.social/users/emelie.atom</id> - <title>emelie 🎨</title> - <subtitle>23 / #Sweden / #Artist / #Equestrian / #GameDev - -If I ain't spending time with my pets, I'm probably drawing. 🐴 🐱 🐰</subtitle> - <updated>2019-02-04T20:22:19Z</updated> - <logo>https://files.mastodon.social/accounts/avatars/000/015/657/original/e7163f98280da1a4.png</logo> - <author> - <id>https://mastodon.social/users/emelie</id> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://mastodon.social/users/emelie</uri> - <name>emelie</name> - <email>emelie@mastodon.social</email> - <summary type="html"><p>23 / <a href="https://mastodon.social/tags/sweden" class="mention hashtag" rel="tag">#<span>Sweden</span></a> / <a href="https://mastodon.social/tags/artist" class="mention hashtag" rel="tag">#<span>Artist</span></a> / <a href="https://mastodon.social/tags/equestrian" class="mention hashtag" rel="tag">#<span>Equestrian</span></a> / <a href="https://mastodon.social/tags/gamedev" class="mention hashtag" rel="tag">#<span>GameDev</span></a></p><p>If I ain&apos;t spending time with my pets, I&apos;m probably drawing. 🐴 🐱 🐰</p></summary> - <link rel="alternate" type="text/html" href="https://mastodon.social/@emelie"/> - <link rel="avatar" type="image/png" media:width="120" media:height="120" href="https://files.mastodon.social/accounts/avatars/000/015/657/original/e7163f98280da1a4.png"/> - <link rel="header" type="image/png" media:width="700" media:height="335" href="https://files.mastodon.social/accounts/headers/000/015/657/original/847f331f3dd9e38b.png"/> - <poco:preferredUsername>emelie</poco:preferredUsername> - <poco:displayName>emelie 🎨</poco:displayName> - <poco:note>23 / #Sweden / #Artist / #Equestrian / #GameDev - -If I ain't spending time with my pets, I'm probably drawing. 🐴 🐱 🐰</poco:note> - <mastodon:scope>public</mastodon:scope> - </author> - <link rel="alternate" type="text/html" href="https://mastodon.social/@emelie"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/emelie.atom"/> - <link rel="hub" href="https://mastodon.social/api/push"/> - <link rel="salmon" href="https://mastodon.social/api/salmon/15657"/> - <entry> - <id>https://mastodon.social/users/emelie/statuses/101850331907006641</id> - <published>2019-04-01T09:58:50Z</published> - <updated>2019-04-01T09:58:50Z</updated> - <title>New status by emelie</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <link rel="alternate" type="application/activity+json" href="https://mastodon.social/users/emelie/statuses/101850331907006641"/> - <content type="html" xml:lang="en"><p>Me: I&apos;m going to make this vital change to my world building in the morning, no way I&apos;ll forget this, it&apos;s too big of a deal<br />Also me: forgets</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/@emelie/101850331907006641"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/emelie/updates/17854598.atom"/> - <ostatus:conversation ref="tag:mastodon.social,2019-04-01:objectId=94383214:objectType=Conversation"/> - </entry> - <entry> - <id>https://mastodon.social/users/emelie/statuses/101849626603073336</id> - <published>2019-04-01T06:59:28Z</published> - <updated>2019-04-01T06:59:28Z</updated> - <title>New status by emelie</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <link rel="alternate" type="application/activity+json" href="https://mastodon.social/users/emelie/statuses/101849626603073336"/> - <content type="html" xml:lang="sv"><p><span class="h-card"><a href="https://mastodon.social/@Fergant" class="u-url mention">@<span>Fergant</span></a></span> Dom är i stort sett religiös skrift vid det här laget 👏👏</p><p>har dock bara läst svenska översättningen, kanske är dags att jag läser dom på engelska</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.social/users/Fergant"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/@emelie/101849626603073336"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/emelie/updates/17852590.atom"/> - <thr:in-reply-to ref="https://mastodon.social/users/Fergant/statuses/101849606513357387" href="https://mastodon.social/@Fergant/101849606513357387"/> - <ostatus:conversation ref="tag:mastodon.social,2019-04-01:objectId=94362529:objectType=Conversation"/> - </entry> - <entry> - <id>https://mastodon.social/users/emelie/statuses/101849580030237068</id> - <published>2019-04-01T06:47:37Z</published> - <updated>2019-04-01T06:47:37Z</updated> - <title>New status by emelie</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <link rel="alternate" type="application/activity+json" href="https://mastodon.social/users/emelie/statuses/101849580030237068"/> - <content type="html" xml:lang="en"><p>What&apos;s you people&apos;s favourite fantasy books? Give me some hot tips 🌞</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/@emelie/101849580030237068"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/emelie/updates/17852464.atom"/> - <ostatus:conversation ref="tag:mastodon.social,2019-04-01:objectId=94362529:objectType=Conversation"/> - </entry> - <entry> - <id>https://mastodon.social/users/emelie/statuses/101849550599949363</id> - <published>2019-04-01T06:40:08Z</published> - <updated>2019-04-01T06:40:08Z</updated> - <title>New status by emelie</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <link rel="alternate" type="application/activity+json" href="https://mastodon.social/users/emelie/statuses/101849550599949363"/> - <content type="html" xml:lang="en"><p>Stick them legs out 💃 <a href="https://mastodon.social/tags/mastocats" class="mention hashtag" rel="tag">#<span>mastocats</span></a></p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <category term="mastocats"/> - <link rel="enclosure" type="image/jpeg" length="516384" href="https://files.mastodon.social/media_attachments/files/013/051/707/original/125a310abe9a34aa.jpeg"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/@emelie/101849550599949363"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/emelie/updates/17852407.atom"/> - <ostatus:conversation ref="tag:mastodon.social,2019-04-01:objectId=94361580:objectType=Conversation"/> - </entry> - <entry> - <id>https://mastodon.social/users/emelie/statuses/101849191533152720</id> - <published>2019-04-01T05:08:49Z</published> - <updated>2019-04-01T05:08:49Z</updated> - <title>New status by emelie</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <link rel="alternate" type="application/activity+json" href="https://mastodon.social/users/emelie/statuses/101849191533152720"/> - <content type="html" xml:lang="en"><p>long 🐱 <a href="https://mastodon.social/tags/mastocats" class="mention hashtag" rel="tag">#<span>mastocats</span></a></p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <category term="mastocats"/> - <link rel="enclosure" type="image/jpeg" length="305208" href="https://files.mastodon.social/media_attachments/files/013/049/940/original/f2dbbfe7de3a17d2.jpeg"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/@emelie/101849191533152720"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/emelie/updates/17851663.atom"/> - <ostatus:conversation ref="tag:mastodon.social,2019-04-01:objectId=94351141:objectType=Conversation"/> - </entry> - <entry> - <id>https://mastodon.social/users/emelie/statuses/101849165031453009</id> - <published>2019-04-01T05:02:05Z</published> - <updated>2019-04-01T05:02:05Z</updated> - <title>New status by emelie</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <link rel="alternate" type="application/activity+json" href="https://mastodon.social/users/emelie/statuses/101849165031453009"/> - <content type="html" xml:lang="en"><p>You gotta take whatever bellyrubbing opportunity you can get before she changes her mind 🦁 <a href="https://mastodon.social/tags/mastocats" class="mention hashtag" rel="tag">#<span>mastocats</span></a></p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <category term="mastocats"/> - <link rel="enclosure" type="video/mp4" length="9838915" href="https://files.mastodon.social/media_attachments/files/013/049/816/original/e7831178a5e0d6d4.mp4"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/@emelie/101849165031453009"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/emelie/updates/17851558.atom"/> - <ostatus:conversation ref="tag:mastodon.social,2019-04-01:objectId=94350309:objectType=Conversation"/> - </entry> - <entry> - <id>https://mastodon.social/users/emelie/statuses/101846512530748693</id> - <published>2019-03-31T17:47:31Z</published> - <updated>2019-03-31T17:47:31Z</updated> - <title>New status by emelie</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <link rel="alternate" type="application/activity+json" href="https://mastodon.social/users/emelie/statuses/101846512530748693"/> - <content type="html" xml:lang="en"><p>Hello look at this boy having a decent haircut for once <a href="https://mastodon.social/tags/mastohorses" class="mention hashtag" rel="tag">#<span>mastohorses</span></a> <a href="https://mastodon.social/tags/equestrian" class="mention hashtag" rel="tag">#<span>equestrian</span></a></p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <category term="equestrian"/> - <category term="mastohorses"/> - <link rel="enclosure" type="image/jpeg" length="461632" href="https://files.mastodon.social/media_attachments/files/013/033/387/original/301e8ab668cd61d2.jpeg"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/@emelie/101846512530748693"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/emelie/updates/17842424.atom"/> - <ostatus:conversation ref="tag:mastodon.social,2019-03-31:objectId=94256415:objectType=Conversation"/> - </entry> - <entry> - <id>https://mastodon.social/users/emelie/statuses/101846181093805500</id> - <published>2019-03-31T16:23:14Z</published> - <updated>2019-03-31T16:23:14Z</updated> - <title>New status by emelie</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <link rel="alternate" type="application/activity+json" href="https://mastodon.social/users/emelie/statuses/101846181093805500"/> - <content type="html" xml:lang="en"><p>Sorry did I disturb the who-is-the-longest-cat competition ? <a href="https://mastodon.social/tags/mastocats" class="mention hashtag" rel="tag">#<span>mastocats</span></a></p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <category term="mastocats"/> - <link rel="enclosure" type="image/jpeg" length="211384" href="https://files.mastodon.social/media_attachments/files/013/030/725/original/5b4886730cbbd25c.jpeg"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/@emelie/101846181093805500"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/emelie/updates/17841108.atom"/> - <ostatus:conversation ref="tag:mastodon.social,2019-03-31:objectId=94245239:objectType=Conversation"/> - </entry> - <entry> - <id>https://mastodon.social/users/emelie/statuses/101845897513133849</id> - <published>2019-03-31T15:11:07Z</published> - <updated>2019-03-31T15:11:07Z</updated> - <title>New status by emelie</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <link rel="alternate" type="application/activity+json" href="https://mastodon.social/users/emelie/statuses/101845897513133849"/> - <summary xml:lang="en">more earthsea ramblings</summary> - <content type="html" xml:lang="en"><p>I&apos;m re-watching Tales from Earthsea for the first time since I read the books, and that Therru doesn&apos;t squash Cob like a spider, as Orm Embar did is a wasted opportunity tbh</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/@emelie/101845897513133849"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/emelie/updates/17840088.atom"/> - <ostatus:conversation ref="tag:mastodon.social,2019-03-31:objectId=94232455:objectType=Conversation"/> - </entry> - <entry> - <id>https://mastodon.social/users/emelie/statuses/101841219051533307</id> - <published>2019-03-30T19:21:19Z</published> - <updated>2019-03-30T19:21:19Z</updated> - <title>New status by emelie</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <link rel="alternate" type="application/activity+json" href="https://mastodon.social/users/emelie/statuses/101841219051533307"/> - <content type="html" xml:lang="en"><p>I gave my cats some mackerel and they ate it all in 0.3 seconds, and now they won&apos;t stop meowing for more, and I&apos;m tired plz shut up</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/@emelie/101841219051533307"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/emelie/updates/17826587.atom"/> - <ostatus:conversation ref="tag:mastodon.social,2019-03-30:objectId=94075000:objectType=Conversation"/> - </entry> - <entry> - <id>https://mastodon.social/users/emelie/statuses/101839949762341381</id> - <published>2019-03-30T13:58:31Z</published> - <updated>2019-03-30T13:58:31Z</updated> - <title>New status by emelie</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <link rel="alternate" type="application/activity+json" href="https://mastodon.social/users/emelie/statuses/101839949762341381"/> - <content type="html" xml:lang="en"><p>yet I&apos;m confused about this american dude with a gun, like the heck r ya doin in mah ghibli</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/@emelie/101839949762341381"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/emelie/updates/17821757.atom"/> - <thr:in-reply-to ref="https://mastodon.social/users/emelie/statuses/101839928677863590" href="https://mastodon.social/@emelie/101839928677863590"/> - <ostatus:conversation ref="tag:mastodon.social,2019-03-30:objectId=94026360:objectType=Conversation"/> - </entry> - <entry> - <id>https://mastodon.social/users/emelie/statuses/101839928677863590</id> - <published>2019-03-30T13:53:09Z</published> - <updated>2019-03-30T13:53:09Z</updated> - <title>New status by emelie</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <link rel="alternate" type="application/activity+json" href="https://mastodon.social/users/emelie/statuses/101839928677863590"/> - <content type="html" xml:lang="en"><p>2 hours into Ni no Kuni 2 and I&apos;ve already sold my soul to this game</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/@emelie/101839928677863590"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/emelie/updates/17821713.atom"/> - <ostatus:conversation ref="tag:mastodon.social,2019-03-30:objectId=94026360:objectType=Conversation"/> - </entry> - <entry> - <id>https://mastodon.social/users/emelie/statuses/101836329521599438</id> - <published>2019-03-29T22:37:51Z</published> - <updated>2019-03-29T22:37:51Z</updated> - <title>New status by emelie</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <link rel="alternate" type="application/activity+json" href="https://mastodon.social/users/emelie/statuses/101836329521599438"/> - <content type="html" xml:lang="en"><p>Pippi Longstocking the original one-punch /man</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/@emelie/101836329521599438"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/emelie/updates/17811608.atom"/> - <ostatus:conversation ref="tag:mastodon.social,2019-03-29:objectId=93907854:objectType=Conversation"/> - </entry> - <entry> - <id>https://mastodon.social/users/emelie/statuses/101835905282948341</id> - <published>2019-03-29T20:49:57Z</published> - <updated>2019-03-29T20:49:57Z</updated> - <title>New status by emelie</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <link rel="alternate" type="application/activity+json" href="https://mastodon.social/users/emelie/statuses/101835905282948341"/> - <content type="html" xml:lang="en"><p>I&apos;ve had so much wine I thought I had a 3rd brother</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/@emelie/101835905282948341"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/emelie/updates/17809862.atom"/> - <ostatus:conversation ref="tag:mastodon.social,2019-03-29:objectId=93892966:objectType=Conversation"/> - </entry> - <entry> - <id>https://mastodon.social/users/emelie/statuses/101835878059204660</id> - <published>2019-03-29T20:43:02Z</published> - <updated>2019-03-29T20:43:02Z</updated> - <title>New status by emelie</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <link rel="alternate" type="application/activity+json" href="https://mastodon.social/users/emelie/statuses/101835878059204660"/> - <content type="html" xml:lang="en"><p>ååååhhh booi</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/@emelie/101835878059204660"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/emelie/updates/17809734.atom"/> - <ostatus:conversation ref="tag:mastodon.social,2019-03-29:objectId=93892010:objectType=Conversation"/> - </entry> - <entry> - <id>https://mastodon.social/users/emelie/statuses/101835848050598939</id> - <published>2019-03-29T20:35:24Z</published> - <updated>2019-03-29T20:35:24Z</updated> - <title>New status by emelie</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <link rel="alternate" type="application/activity+json" href="https://mastodon.social/users/emelie/statuses/101835848050598939"/> - <content type="html" xml:lang="en"><p><span class="h-card"><a href="https://thraeryn.net/@thraeryn" class="u-url mention">@<span>thraeryn</span></a></span> if I spent 1 hour and a half watching this monstrosity, I need to</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://thraeryn.net/users/thraeryn"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/@emelie/101835848050598939"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/emelie/updates/17809591.atom"/> - <thr:in-reply-to ref="https://thraeryn.net/users/thraeryn/statuses/101835839202826007" href="https://thraeryn.net/@thraeryn/101835839202826007"/> - <ostatus:conversation ref="tag:mastodon.social,2019-03-29:objectId=93888827:objectType=Conversation"/> - </entry> - <entry> - <id>https://mastodon.social/users/emelie/statuses/101835823138262290</id> - <published>2019-03-29T20:29:04Z</published> - <updated>2019-03-29T20:29:04Z</updated> - <title>New status by emelie</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <link rel="alternate" type="application/activity+json" href="https://mastodon.social/users/emelie/statuses/101835823138262290"/> - <summary xml:lang="en">medical, fluids mention</summary> - <content type="html" xml:lang="en"><p><span class="h-card"><a href="https://icosahedron.website/@Trev" class="u-url mention">@<span>Trev</span></a></span> *hugs* ✨</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://icosahedron.website/users/Trev"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/@emelie/101835823138262290"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/emelie/updates/17809468.atom"/> - <thr:in-reply-to ref="https://icosahedron.website/users/Trev/statuses/101835812250051801" href="https://icosahedron.website/@Trev/101835812250051801"/> - <ostatus:conversation ref="tag:icosahedron.website,2019-03-29:objectId=12220882:objectType=Conversation"/> - </entry> -</feed> diff --git a/test/fixtures/tesla_mock/emoji-in-summary.json b/test/fixtures/tesla_mock/emoji-in-summary.json new file mode 100644 index 000000000..f77c6e2e8 --- /dev/null +++ b/test/fixtures/tesla_mock/emoji-in-summary.json @@ -0,0 +1,49 @@ +{ + "@context": [ + "https://www.w3.org/ns/activitystreams", + "https://patch.cx/schemas/litepub-0.1.jsonld", + { + "@language": "und" + } + ], + "actor": "https://patch.cx/users/rin", + "attachment": [], + "attributedTo": "https://patch.cx/users/rin", + "cc": [ + "https://patch.cx/users/rin/followers" + ], + "content": ":joker_disapprove: <br><br>just grabbing a test fixture, nevermind me", + "context": "https://patch.cx/contexts/2c3ce4b4-18b1-4b1a-8965-3932027b5326", + "conversation": "https://patch.cx/contexts/2c3ce4b4-18b1-4b1a-8965-3932027b5326", + "id": "https://patch.cx/objects/a399c28e-c821-4820-bc3e-4afeb044c16f", + "published": "2021-03-22T16:54:46.461939Z", + "sensitive": null, + "source": ":joker_disapprove: \r\n\r\njust grabbing a test fixture, nevermind me", + "summary": ":joker_smile: ", + "tag": [ + { + "icon": { + "type": "Image", + "url": "https://patch.cx/emoji/custom/joker_disapprove.png" + }, + "id": "https://patch.cx/emoji/custom/joker_disapprove.png", + "name": ":joker_disapprove:", + "type": "Emoji", + "updated": "1970-01-01T00:00:00Z" + }, + { + "icon": { + "type": "Image", + "url": "https://patch.cx/emoji/custom/joker_smile.png" + }, + "id": "https://patch.cx/emoji/custom/joker_smile.png", + "name": ":joker_smile:", + "type": "Emoji", + "updated": "1970-01-01T00:00:00Z" + } + ], + "to": [ + "https://www.w3.org/ns/activitystreams#Public" + ], + "type": "Note" +} diff --git a/test/fixtures/tesla_mock/framatube.org-video.json b/test/fixtures/tesla_mock/framatube.org-video.json index 3d53f0c97..1fa529886 100644 --- a/test/fixtures/tesla_mock/framatube.org-video.json +++ b/test/fixtures/tesla_mock/framatube.org-video.json @@ -1 +1 @@ -{"type":"Video","id":"https://framatube.org/videos/watch/6050732a-8a7a-43d4-a6cd-809525a1d206","name":"Déframasoftisons Internet [Framasoft]","duration":"PT3622S","uuid":"6050732a-8a7a-43d4-a6cd-809525a1d206","tag":[{"type":"Hashtag","name":"déframasoftisons"},{"type":"Hashtag","name":"EPN23"},{"type":"Hashtag","name":"framaconf"},{"type":"Hashtag","name":"Framasoft"},{"type":"Hashtag","name":"pyg"}],"category":{"identifier":"15","name":"Science & Technology"},"views":122,"sensitive":false,"waitTranscoding":false,"state":1,"commentsEnabled":true,"downloadEnabled":true,"published":"2020-05-24T18:34:31.569Z","originallyPublishedAt":"2019-11-30T23:00:00.000Z","updated":"2020-07-05T09:01:01.720Z","mediaType":"text/markdown","content":"Après avoir mené avec un certain succès la campagne « Dégooglisons Internet » en 2014, l’association Framasoft annonce fin 2019 arrêter progressivement un certain nombre de ses services alternatifs aux GAFAM. Pourquoi ?\r\n\r\nTranscription par @april...","support":null,"subtitleLanguage":[],"icon":{"type":"Image","url":"https://framatube.org/static/thumbnails/6050732a-8a7a-43d4-a6cd-809525a1d206.jpg","mediaType":"image/jpeg","width":223,"height":122},"url":[{"type":"Link","mediaType":"text/html","href":"https://framatube.org/videos/watch/6050732a-8a7a-43d4-a6cd-809525a1d206"},{"type":"Link","mediaType":"video/mp4","href":"https://framatube.org/static/webseed/6050732a-8a7a-43d4-a6cd-809525a1d206-1080.mp4","height":1080,"size":1157359410,"fps":25},{"type":"Link","rel":["metadata","video/mp4"],"mediaType":"application/json","href":"https://framatube.org/api/v1/videos/6050732a-8a7a-43d4-a6cd-809525a1d206/metadata/1309939","height":1080,"fps":25},{"type":"Link","mediaType":"application/x-bittorrent","href":"https://framatube.org/static/torrents/6050732a-8a7a-43d4-a6cd-809525a1d206-1080.torrent","height":1080},{"type":"Link","mediaType":"application/x-bittorrent;x-scheme-handler/magnet","href":"magnet:?xs=https%3A%2F%2Fframatube.org%2Fstatic%2Ftorrents%2F6050732a-8a7a-43d4-a6cd-809525a1d206-1080.torrent&xt=urn:btih:381c9429900552e23a4eb506318f1fa01e4d63a8&dn=D%C3%A9framasoftisons+Internet+%5BFramasoft%5D&tr=wss%3A%2F%2Fframatube.org%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fframatube.org%2Ftracker%2Fannounce&ws=https%3A%2F%2Fframatube.org%2Fstatic%2Fwebseed%2F6050732a-8a7a-43d4-a6cd-809525a1d206-1080.mp4&ws=https%3A%2F%2Fpeertube.iselfhost.com%2Fstatic%2Fredundancy%2F6050732a-8a7a-43d4-a6cd-809525a1d206-1080.mp4&ws=https%3A%2F%2Ftube.privacytools.io%2Fstatic%2Fredundancy%2F6050732a-8a7a-43d4-a6cd-809525a1d206-1080.mp4&ws=https%3A%2F%2Fpeertube.live%2Fstatic%2Fredundancy%2F6050732a-8a7a-43d4-a6cd-809525a1d206-1080.mp4","height":1080},{"type":"Link","mediaType":"video/mp4","href":"https://framatube.org/static/webseed/6050732a-8a7a-43d4-a6cd-809525a1d206-480.mp4","height":480,"size":250095131,"fps":25},{"type":"Link","rel":["metadata","video/mp4"],"mediaType":"application/json","href":"https://framatube.org/api/v1/videos/6050732a-8a7a-43d4-a6cd-809525a1d206/metadata/1309941","height":480,"fps":25},{"type":"Link","mediaType":"application/x-bittorrent","href":"https://framatube.org/static/torrents/6050732a-8a7a-43d4-a6cd-809525a1d206-480.torrent","height":480},{"type":"Link","mediaType":"application/x-bittorrent;x-scheme-handler/magnet","href":"magnet:?xs=https%3A%2F%2Fframatube.org%2Fstatic%2Ftorrents%2F6050732a-8a7a-43d4-a6cd-809525a1d206-480.torrent&xt=urn:btih:a181dcbb5368ab5c31cc9ff07634becb72c344ee&dn=D%C3%A9framasoftisons+Internet+%5BFramasoft%5D&tr=wss%3A%2F%2Fframatube.org%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fframatube.org%2Ftracker%2Fannounce&ws=https%3A%2F%2Fframatube.org%2Fstatic%2Fwebseed%2F6050732a-8a7a-43d4-a6cd-809525a1d206-480.mp4&ws=https%3A%2F%2Fpeertube.iselfhost.com%2Fstatic%2Fredundancy%2F6050732a-8a7a-43d4-a6cd-809525a1d206-480.mp4&ws=https%3A%2F%2Ftube.privacytools.io%2Fstatic%2Fredundancy%2F6050732a-8a7a-43d4-a6cd-809525a1d206-480.mp4&ws=https%3A%2F%2Fpeertube.live%2Fstatic%2Fredundancy%2F6050732a-8a7a-43d4-a6cd-809525a1d206-480.mp4","height":480},{"type":"Link","mediaType":"video/mp4","href":"https://framatube.org/static/webseed/6050732a-8a7a-43d4-a6cd-809525a1d206-360.mp4","height":360,"size":171357733,"fps":25},{"type":"Link","rel":["metadata","video/mp4"],"mediaType":"application/json","href":"https://framatube.org/api/v1/videos/6050732a-8a7a-43d4-a6cd-809525a1d206/metadata/1309942","height":360,"fps":25},{"type":"Link","mediaType":"application/x-bittorrent","href":"https://framatube.org/static/torrents/6050732a-8a7a-43d4-a6cd-809525a1d206-360.torrent","height":360},{"type":"Link","mediaType":"application/x-bittorrent;x-scheme-handler/magnet","href":"magnet:?xs=https%3A%2F%2Fframatube.org%2Fstatic%2Ftorrents%2F6050732a-8a7a-43d4-a6cd-809525a1d206-360.torrent&xt=urn:btih:aedfa9479ea04a175eee0b0bd0bda64076308746&dn=D%C3%A9framasoftisons+Internet+%5BFramasoft%5D&tr=wss%3A%2F%2Fframatube.org%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fframatube.org%2Ftracker%2Fannounce&ws=https%3A%2F%2Fframatube.org%2Fstatic%2Fwebseed%2F6050732a-8a7a-43d4-a6cd-809525a1d206-360.mp4&ws=https%3A%2F%2Fpeertube.iselfhost.com%2Fstatic%2Fredundancy%2F6050732a-8a7a-43d4-a6cd-809525a1d206-360.mp4&ws=https%3A%2F%2Ftube.privacytools.io%2Fstatic%2Fredundancy%2F6050732a-8a7a-43d4-a6cd-809525a1d206-360.mp4&ws=https%3A%2F%2Fpeertube.live%2Fstatic%2Fredundancy%2F6050732a-8a7a-43d4-a6cd-809525a1d206-360.mp4","height":360},{"type":"Link","mediaType":"video/mp4","href":"https://framatube.org/static/webseed/6050732a-8a7a-43d4-a6cd-809525a1d206-720.mp4","height":720,"size":497100839,"fps":25},{"type":"Link","rel":["metadata","video/mp4"],"mediaType":"application/json","href":"https://framatube.org/api/v1/videos/6050732a-8a7a-43d4-a6cd-809525a1d206/metadata/1309943","height":720,"fps":25},{"type":"Link","mediaType":"application/x-bittorrent","href":"https://framatube.org/static/torrents/6050732a-8a7a-43d4-a6cd-809525a1d206-720.torrent","height":720},{"type":"Link","mediaType":"application/x-bittorrent;x-scheme-handler/magnet","href":"magnet:?xs=https%3A%2F%2Fframatube.org%2Fstatic%2Ftorrents%2F6050732a-8a7a-43d4-a6cd-809525a1d206-720.torrent&xt=urn:btih:71971668f82a3b24ac71bc3a982848dd8dc5a5f5&dn=D%C3%A9framasoftisons+Internet+%5BFramasoft%5D&tr=wss%3A%2F%2Fframatube.org%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fframatube.org%2Ftracker%2Fannounce&ws=https%3A%2F%2Fframatube.org%2Fstatic%2Fwebseed%2F6050732a-8a7a-43d4-a6cd-809525a1d206-720.mp4&ws=https%3A%2F%2Fpeertube.iselfhost.com%2Fstatic%2Fredundancy%2F6050732a-8a7a-43d4-a6cd-809525a1d206-720.mp4&ws=https%3A%2F%2Ftube.privacytools.io%2Fstatic%2Fredundancy%2F6050732a-8a7a-43d4-a6cd-809525a1d206-720.mp4&ws=https%3A%2F%2Fpeertube.live%2Fstatic%2Fredundancy%2F6050732a-8a7a-43d4-a6cd-809525a1d206-720.mp4","height":720},{"type":"Link","mediaType":"video/mp4","href":"https://framatube.org/static/webseed/6050732a-8a7a-43d4-a6cd-809525a1d206-240.mp4","height":240,"size":113038439,"fps":25},{"type":"Link","rel":["metadata","video/mp4"],"mediaType":"application/json","href":"https://framatube.org/api/v1/videos/6050732a-8a7a-43d4-a6cd-809525a1d206/metadata/1309944","height":240,"fps":25},{"type":"Link","mediaType":"application/x-bittorrent","href":"https://framatube.org/static/torrents/6050732a-8a7a-43d4-a6cd-809525a1d206-240.torrent","height":240},{"type":"Link","mediaType":"application/x-bittorrent;x-scheme-handler/magnet","href":"magnet:?xs=https%3A%2F%2Fframatube.org%2Fstatic%2Ftorrents%2F6050732a-8a7a-43d4-a6cd-809525a1d206-240.torrent&xt=urn:btih:c42aa6c95efb28d9f114ebd98537f7b00fa72246&dn=D%C3%A9framasoftisons+Internet+%5BFramasoft%5D&tr=wss%3A%2F%2Fframatube.org%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fframatube.org%2Ftracker%2Fannounce&ws=https%3A%2F%2Fframatube.org%2Fstatic%2Fwebseed%2F6050732a-8a7a-43d4-a6cd-809525a1d206-240.mp4&ws=https%3A%2F%2Fpeertube.iselfhost.com%2Fstatic%2Fredundancy%2F6050732a-8a7a-43d4-a6cd-809525a1d206-240.mp4&ws=https%3A%2F%2Ftube.privacytools.io%2Fstatic%2Fredundancy%2F6050732a-8a7a-43d4-a6cd-809525a1d206-240.mp4","height":240},{"type":"Link","mediaType":"application/x-mpegURL","href":"https://framatube.org/static/streaming-playlists/hls/6050732a-8a7a-43d4-a6cd-809525a1d206/master.m3u8","tag":[{"type":"Infohash","name":"f7428214539626e062f300f2ca4cf9154575144e"},{"type":"Infohash","name":"46e236dffb1ea6b9123a5396cbe88e97dd94cc6c"},{"type":"Infohash","name":"11f1045830b5d786c788f2594d19f128764e7d87"},{"type":"Infohash","name":"4327ad3e0d84de100130a27e9ab6fe40c4284f0e"},{"type":"Infohash","name":"41e2eee8e7b23a63c23a77c40a46de11492a4831"},{"type":"Link","name":"sha256","mediaType":"application/json","href":"https://framatube.org/static/streaming-playlists/hls/6050732a-8a7a-43d4-a6cd-809525a1d206/segments-sha256.json"},{"type":"Link","mediaType":"video/mp4","href":"https://framatube.org/static/streaming-playlists/hls/6050732a-8a7a-43d4-a6cd-809525a1d206/6050732a-8a7a-43d4-a6cd-809525a1d206-1080-fragmented.mp4","height":1080,"size":1156777472,"fps":25},{"type":"Link","rel":["metadata","video/mp4"],"mediaType":"application/json","href":"https://framatube.org/api/v1/videos/6050732a-8a7a-43d4-a6cd-809525a1d206/metadata/1309940","height":1080,"fps":25},{"type":"Link","mediaType":"application/x-bittorrent","href":"https://framatube.org/static/torrents/6050732a-8a7a-43d4-a6cd-809525a1d206-1080-hls.torrent","height":1080},{"type":"Link","mediaType":"application/x-bittorrent;x-scheme-handler/magnet","href":"magnet:?xs=https%3A%2F%2Fframatube.org%2Fstatic%2Ftorrents%2F6050732a-8a7a-43d4-a6cd-809525a1d206-1080-hls.torrent&xt=urn:btih:0204d780ebfab0d5d9d3476a038e812ad792deeb&dn=D%C3%A9framasoftisons+Internet+%5BFramasoft%5D&tr=wss%3A%2F%2Fframatube.org%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fframatube.org%2Ftracker%2Fannounce&ws=https%3A%2F%2Fframatube.org%2Fstatic%2Fstreaming-playlists%2Fhls%2F6050732a-8a7a-43d4-a6cd-809525a1d206%2F6050732a-8a7a-43d4-a6cd-809525a1d206-1080-fragmented.mp4","height":1080},{"type":"Link","mediaType":"video/mp4","href":"https://framatube.org/static/streaming-playlists/hls/6050732a-8a7a-43d4-a6cd-809525a1d206/6050732a-8a7a-43d4-a6cd-809525a1d206-480-fragmented.mp4","height":480,"size":249562889,"fps":25},{"type":"Link","rel":["metadata","video/mp4"],"mediaType":"application/json","href":"https://framatube.org/api/v1/videos/6050732a-8a7a-43d4-a6cd-809525a1d206/metadata/1309945","height":480,"fps":25},{"type":"Link","mediaType":"application/x-bittorrent","href":"https://framatube.org/static/torrents/6050732a-8a7a-43d4-a6cd-809525a1d206-480-hls.torrent","height":480},{"type":"Link","mediaType":"application/x-bittorrent;x-scheme-handler/magnet","href":"magnet:?xs=https%3A%2F%2Fframatube.org%2Fstatic%2Ftorrents%2F6050732a-8a7a-43d4-a6cd-809525a1d206-480-hls.torrent&xt=urn:btih:5d14f38ded29de629668fe1cfc61a75f4cce2628&dn=D%C3%A9framasoftisons+Internet+%5BFramasoft%5D&tr=wss%3A%2F%2Fframatube.org%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fframatube.org%2Ftracker%2Fannounce&ws=https%3A%2F%2Fframatube.org%2Fstatic%2Fstreaming-playlists%2Fhls%2F6050732a-8a7a-43d4-a6cd-809525a1d206%2F6050732a-8a7a-43d4-a6cd-809525a1d206-480-fragmented.mp4","height":480},{"type":"Link","mediaType":"video/mp4","href":"https://framatube.org/static/streaming-playlists/hls/6050732a-8a7a-43d4-a6cd-809525a1d206/6050732a-8a7a-43d4-a6cd-809525a1d206-360-fragmented.mp4","height":360,"size":170836415,"fps":25},{"type":"Link","rel":["metadata","video/mp4"],"mediaType":"application/json","href":"https://framatube.org/api/v1/videos/6050732a-8a7a-43d4-a6cd-809525a1d206/metadata/1309946","height":360,"fps":25},{"type":"Link","mediaType":"application/x-bittorrent","href":"https://framatube.org/static/torrents/6050732a-8a7a-43d4-a6cd-809525a1d206-360-hls.torrent","height":360},{"type":"Link","mediaType":"application/x-bittorrent;x-scheme-handler/magnet","href":"magnet:?xs=https%3A%2F%2Fframatube.org%2Fstatic%2Ftorrents%2F6050732a-8a7a-43d4-a6cd-809525a1d206-360-hls.torrent&xt=urn:btih:30125488789080ad405ebcee6c214945f31b8f30&dn=D%C3%A9framasoftisons+Internet+%5BFramasoft%5D&tr=wss%3A%2F%2Fframatube.org%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fframatube.org%2Ftracker%2Fannounce&ws=https%3A%2F%2Fframatube.org%2Fstatic%2Fstreaming-playlists%2Fhls%2F6050732a-8a7a-43d4-a6cd-809525a1d206%2F6050732a-8a7a-43d4-a6cd-809525a1d206-360-fragmented.mp4","height":360},{"type":"Link","mediaType":"video/mp4","href":"https://framatube.org/static/streaming-playlists/hls/6050732a-8a7a-43d4-a6cd-809525a1d206/6050732a-8a7a-43d4-a6cd-809525a1d206-720-fragmented.mp4","height":720,"size":496533741,"fps":25},{"type":"Link","rel":["metadata","video/mp4"],"mediaType":"application/json","href":"https://framatube.org/api/v1/videos/6050732a-8a7a-43d4-a6cd-809525a1d206/metadata/1309947","height":720,"fps":25},{"type":"Link","mediaType":"application/x-bittorrent","href":"https://framatube.org/static/torrents/6050732a-8a7a-43d4-a6cd-809525a1d206-720-hls.torrent","height":720},{"type":"Link","mediaType":"application/x-bittorrent;x-scheme-handler/magnet","href":"magnet:?xs=https%3A%2F%2Fframatube.org%2Fstatic%2Ftorrents%2F6050732a-8a7a-43d4-a6cd-809525a1d206-720-hls.torrent&xt=urn:btih:8ed1e8bccde709901c26e315fc8f53bfd26d1ba6&dn=D%C3%A9framasoftisons+Internet+%5BFramasoft%5D&tr=wss%3A%2F%2Fframatube.org%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fframatube.org%2Ftracker%2Fannounce&ws=https%3A%2F%2Fframatube.org%2Fstatic%2Fstreaming-playlists%2Fhls%2F6050732a-8a7a-43d4-a6cd-809525a1d206%2F6050732a-8a7a-43d4-a6cd-809525a1d206-720-fragmented.mp4","height":720},{"type":"Link","mediaType":"video/mp4","href":"https://framatube.org/static/streaming-playlists/hls/6050732a-8a7a-43d4-a6cd-809525a1d206/6050732a-8a7a-43d4-a6cd-809525a1d206-240-fragmented.mp4","height":240,"size":112529249,"fps":25},{"type":"Link","rel":["metadata","video/mp4"],"mediaType":"application/json","href":"https://framatube.org/api/v1/videos/6050732a-8a7a-43d4-a6cd-809525a1d206/metadata/1309948","height":240,"fps":25},{"type":"Link","mediaType":"application/x-bittorrent","href":"https://framatube.org/static/torrents/6050732a-8a7a-43d4-a6cd-809525a1d206-240-hls.torrent","height":240},{"type":"Link","mediaType":"application/x-bittorrent;x-scheme-handler/magnet","href":"magnet:?xs=https%3A%2F%2Fframatube.org%2Fstatic%2Ftorrents%2F6050732a-8a7a-43d4-a6cd-809525a1d206-240-hls.torrent&xt=urn:btih:8b452bf4e70b9078d4e74ca8b5523cc9dc70d10a&dn=D%C3%A9framasoftisons+Internet+%5BFramasoft%5D&tr=wss%3A%2F%2Fframatube.org%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fframatube.org%2Ftracker%2Fannounce&ws=https%3A%2F%2Fframatube.org%2Fstatic%2Fstreaming-playlists%2Fhls%2F6050732a-8a7a-43d4-a6cd-809525a1d206%2F6050732a-8a7a-43d4-a6cd-809525a1d206-240-fragmented.mp4","height":240}]}],"likes":"https://framatube.org/videos/watch/6050732a-8a7a-43d4-a6cd-809525a1d206/likes","dislikes":"https://framatube.org/videos/watch/6050732a-8a7a-43d4-a6cd-809525a1d206/dislikes","shares":"https://framatube.org/videos/watch/6050732a-8a7a-43d4-a6cd-809525a1d206/announces","comments":"https://framatube.org/videos/watch/6050732a-8a7a-43d4-a6cd-809525a1d206/comments","attributedTo":[{"type":"Person","id":"https://framatube.org/accounts/framasoft"},{"type":"Group","id":"https://framatube.org/video-channels/bf54d359-cfad-4935-9d45-9d6be93f63e8"}],"to":["https://www.w3.org/ns/activitystreams#Public"],"cc":["https://framatube.org/accounts/framasoft/followers"],"@context":["https://www.w3.org/ns/activitystreams","https://w3id.org/security/v1",{"RsaSignature2017":"https://w3id.org/security#RsaSignature2017"},{"pt":"https://joinpeertube.org/ns#","sc":"http://schema.org#","Hashtag":"as:Hashtag","uuid":"sc:identifier","category":"sc:category","licence":"sc:license","subtitleLanguage":"sc:subtitleLanguage","sensitive":"as:sensitive","language":"sc:inLanguage","Infohash":"pt:Infohash","Playlist":"pt:Playlist","PlaylistElement":"pt:PlaylistElement","originallyPublishedAt":"sc:datePublished","views":{"@type":"sc:Number","@id":"pt:views"},"state":{"@type":"sc:Number","@id":"pt:state"},"size":{"@type":"sc:Number","@id":"pt:size"},"fps":{"@type":"sc:Number","@id":"pt:fps"},"startTimestamp":{"@type":"sc:Number","@id":"pt:startTimestamp"},"stopTimestamp":{"@type":"sc:Number","@id":"pt:stopTimestamp"},"position":{"@type":"sc:Number","@id":"pt:position"},"commentsEnabled":{"@type":"sc:Boolean","@id":"pt:commentsEnabled"},"downloadEnabled":{"@type":"sc:Boolean","@id":"pt:downloadEnabled"},"waitTranscoding":{"@type":"sc:Boolean","@id":"pt:waitTranscoding"},"support":{"@type":"sc:Text","@id":"pt:support"},"likes":{"@id":"as:likes","@type":"@id"},"dislikes":{"@id":"as:dislikes","@type":"@id"},"playlists":{"@id":"pt:playlists","@type":"@id"},"shares":{"@id":"as:shares","@type":"@id"},"comments":{"@id":"as:comments","@type":"@id"}}]}
\ No newline at end of file +{"type":"Create","id":"https://framatube.org/videos/watch/6050732a-8a7a-43d4-a6cd-809525a1d206/activity","actor":"https://framatube.org/accounts/framasoft","object":{"type":"Video","id":"https://framatube.org/videos/watch/6050732a-8a7a-43d4-a6cd-809525a1d206","name":"Déframasoftisons Internet [Framasoft]","duration":"PT3622S","uuid":"6050732a-8a7a-43d4-a6cd-809525a1d206","tag":[{"type":"Hashtag","name":"déframasoftisons"},{"type":"Hashtag","name":"EPN23"},{"type":"Hashtag","name":"framaconf"},{"type":"Hashtag","name":"Framasoft"},{"type":"Hashtag","name":"pyg"}],"category":{"identifier":"15","name":"Science & Technology"},"views":154,"sensitive":false,"waitTranscoding":false,"state":1,"commentsEnabled":true,"downloadEnabled":true,"published":"2020-05-24T18:34:31.569Z","originallyPublishedAt":"2019-11-30T23:00:00.000Z","updated":"2020-08-17T11:01:02.994Z","mediaType":"text/markdown","content":"Après avoir mené avec un certain succès la campagne « Dégooglisons Internet » en 2014, l’association Framasoft annonce fin 2019 arrêter progressivement un certain nombre de ses services alternatifs aux GAFAM. Pourquoi ?\r\n\r\nTranscription par @aprilorg ici : https://www.april.org/deframasoftisons-internet-pierre-yves-gosset-framasoft","support":null,"subtitleLanguage":[],"icon":[{"type":"Image","url":"https://framatube.org/static/thumbnails/6050732a-8a7a-43d4-a6cd-809525a1d206.jpg","mediaType":"image/jpeg","width":223,"height":122},{"type":"Image","url":"https://framatube.org/static/previews/6050732a-8a7a-43d4-a6cd-809525a1d206.jpg","mediaType":"image/jpeg","width":850,"height":480}],"url":[{"type":"Link","mediaType":"text/html","href":"https://framatube.org/videos/watch/6050732a-8a7a-43d4-a6cd-809525a1d206"},{"type":"Link","mediaType":"video/mp4","href":"https://framatube.org/static/webseed/6050732a-8a7a-43d4-a6cd-809525a1d206-1080.mp4","height":1080,"size":1157359410,"fps":25},{"type":"Link","rel":["metadata","video/mp4"],"mediaType":"application/json","href":"https://framatube.org/api/v1/videos/6050732a-8a7a-43d4-a6cd-809525a1d206/metadata/1309939","height":1080,"fps":25},{"type":"Link","mediaType":"application/x-bittorrent","href":"https://framatube.org/static/torrents/6050732a-8a7a-43d4-a6cd-809525a1d206-1080.torrent","height":1080},{"type":"Link","mediaType":"application/x-bittorrent;x-scheme-handler/magnet","href":"magnet:?xs=https%3A%2F%2Fframatube.org%2Fstatic%2Ftorrents%2F6050732a-8a7a-43d4-a6cd-809525a1d206-1080.torrent&xt=urn:btih:381c9429900552e23a4eb506318f1fa01e4d63a8&dn=D%C3%A9framasoftisons+Internet+%5BFramasoft%5D&tr=wss%3A%2F%2Fframatube.org%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fframatube.org%2Ftracker%2Fannounce&ws=https%3A%2F%2Fframatube.org%2Fstatic%2Fwebseed%2F6050732a-8a7a-43d4-a6cd-809525a1d206-1080.mp4&ws=https%3A%2F%2Fpeertube.iselfhost.com%2Fstatic%2Fredundancy%2F6050732a-8a7a-43d4-a6cd-809525a1d206-1080.mp4&ws=https%3A%2F%2Ftube.privacytools.io%2Fstatic%2Fredundancy%2F6050732a-8a7a-43d4-a6cd-809525a1d206-1080.mp4&ws=https%3A%2F%2Fpeertube.live%2Fstatic%2Fredundancy%2F6050732a-8a7a-43d4-a6cd-809525a1d206-1080.mp4","height":1080},{"type":"Link","mediaType":"video/mp4","href":"https://framatube.org/static/webseed/6050732a-8a7a-43d4-a6cd-809525a1d206-720.mp4","height":720,"size":497100839,"fps":25},{"type":"Link","rel":["metadata","video/mp4"],"mediaType":"application/json","href":"https://framatube.org/api/v1/videos/6050732a-8a7a-43d4-a6cd-809525a1d206/metadata/1309943","height":720,"fps":25},{"type":"Link","mediaType":"application/x-bittorrent","href":"https://framatube.org/static/torrents/6050732a-8a7a-43d4-a6cd-809525a1d206-720.torrent","height":720},{"type":"Link","mediaType":"application/x-bittorrent;x-scheme-handler/magnet","href":"magnet:?xs=https%3A%2F%2Fframatube.org%2Fstatic%2Ftorrents%2F6050732a-8a7a-43d4-a6cd-809525a1d206-720.torrent&xt=urn:btih:71971668f82a3b24ac71bc3a982848dd8dc5a5f5&dn=D%C3%A9framasoftisons+Internet+%5BFramasoft%5D&tr=wss%3A%2F%2Fframatube.org%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fframatube.org%2Ftracker%2Fannounce&ws=https%3A%2F%2Fframatube.org%2Fstatic%2Fwebseed%2F6050732a-8a7a-43d4-a6cd-809525a1d206-720.mp4&ws=https%3A%2F%2Ftube.privacytools.io%2Fstatic%2Fredundancy%2F6050732a-8a7a-43d4-a6cd-809525a1d206-720.mp4&ws=https%3A%2F%2Fpeertube.iselfhost.com%2Fstatic%2Fredundancy%2F6050732a-8a7a-43d4-a6cd-809525a1d206-720.mp4&ws=https%3A%2F%2Fpeertube.live%2Fstatic%2Fredundancy%2F6050732a-8a7a-43d4-a6cd-809525a1d206-720.mp4","height":720},{"type":"Link","mediaType":"video/mp4","href":"https://framatube.org/static/webseed/6050732a-8a7a-43d4-a6cd-809525a1d206-480.mp4","height":480,"size":250095131,"fps":25},{"type":"Link","rel":["metadata","video/mp4"],"mediaType":"application/json","href":"https://framatube.org/api/v1/videos/6050732a-8a7a-43d4-a6cd-809525a1d206/metadata/1309941","height":480,"fps":25},{"type":"Link","mediaType":"application/x-bittorrent","href":"https://framatube.org/static/torrents/6050732a-8a7a-43d4-a6cd-809525a1d206-480.torrent","height":480},{"type":"Link","mediaType":"application/x-bittorrent;x-scheme-handler/magnet","href":"magnet:?xs=https%3A%2F%2Fframatube.org%2Fstatic%2Ftorrents%2F6050732a-8a7a-43d4-a6cd-809525a1d206-480.torrent&xt=urn:btih:a181dcbb5368ab5c31cc9ff07634becb72c344ee&dn=D%C3%A9framasoftisons+Internet+%5BFramasoft%5D&tr=wss%3A%2F%2Fframatube.org%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fframatube.org%2Ftracker%2Fannounce&ws=https%3A%2F%2Fframatube.org%2Fstatic%2Fwebseed%2F6050732a-8a7a-43d4-a6cd-809525a1d206-480.mp4&ws=https%3A%2F%2Fpeertube.iselfhost.com%2Fstatic%2Fredundancy%2F6050732a-8a7a-43d4-a6cd-809525a1d206-480.mp4&ws=https%3A%2F%2Ftube.privacytools.io%2Fstatic%2Fredundancy%2F6050732a-8a7a-43d4-a6cd-809525a1d206-480.mp4&ws=https%3A%2F%2Fpeertube.live%2Fstatic%2Fredundancy%2F6050732a-8a7a-43d4-a6cd-809525a1d206-480.mp4","height":480},{"type":"Link","mediaType":"video/mp4","href":"https://framatube.org/static/webseed/6050732a-8a7a-43d4-a6cd-809525a1d206-360.mp4","height":360,"size":171357733,"fps":25},{"type":"Link","rel":["metadata","video/mp4"],"mediaType":"application/json","href":"https://framatube.org/api/v1/videos/6050732a-8a7a-43d4-a6cd-809525a1d206/metadata/1309942","height":360,"fps":25},{"type":"Link","mediaType":"application/x-bittorrent","href":"https://framatube.org/static/torrents/6050732a-8a7a-43d4-a6cd-809525a1d206-360.torrent","height":360},{"type":"Link","mediaType":"application/x-bittorrent;x-scheme-handler/magnet","href":"magnet:?xs=https%3A%2F%2Fframatube.org%2Fstatic%2Ftorrents%2F6050732a-8a7a-43d4-a6cd-809525a1d206-360.torrent&xt=urn:btih:aedfa9479ea04a175eee0b0bd0bda64076308746&dn=D%C3%A9framasoftisons+Internet+%5BFramasoft%5D&tr=wss%3A%2F%2Fframatube.org%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fframatube.org%2Ftracker%2Fannounce&ws=https%3A%2F%2Fframatube.org%2Fstatic%2Fwebseed%2F6050732a-8a7a-43d4-a6cd-809525a1d206-360.mp4&ws=https%3A%2F%2Fpeertube.iselfhost.com%2Fstatic%2Fredundancy%2F6050732a-8a7a-43d4-a6cd-809525a1d206-360.mp4&ws=https%3A%2F%2Ftube.privacytools.io%2Fstatic%2Fredundancy%2F6050732a-8a7a-43d4-a6cd-809525a1d206-360.mp4&ws=https%3A%2F%2Fpeertube.live%2Fstatic%2Fredundancy%2F6050732a-8a7a-43d4-a6cd-809525a1d206-360.mp4","height":360},{"type":"Link","mediaType":"video/mp4","href":"https://framatube.org/static/webseed/6050732a-8a7a-43d4-a6cd-809525a1d206-240.mp4","height":240,"size":113038439,"fps":25},{"type":"Link","rel":["metadata","video/mp4"],"mediaType":"application/json","href":"https://framatube.org/api/v1/videos/6050732a-8a7a-43d4-a6cd-809525a1d206/metadata/1309944","height":240,"fps":25},{"type":"Link","mediaType":"application/x-bittorrent","href":"https://framatube.org/static/torrents/6050732a-8a7a-43d4-a6cd-809525a1d206-240.torrent","height":240},{"type":"Link","mediaType":"application/x-bittorrent;x-scheme-handler/magnet","href":"magnet:?xs=https%3A%2F%2Fframatube.org%2Fstatic%2Ftorrents%2F6050732a-8a7a-43d4-a6cd-809525a1d206-240.torrent&xt=urn:btih:c42aa6c95efb28d9f114ebd98537f7b00fa72246&dn=D%C3%A9framasoftisons+Internet+%5BFramasoft%5D&tr=wss%3A%2F%2Fframatube.org%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fframatube.org%2Ftracker%2Fannounce&ws=https%3A%2F%2Fframatube.org%2Fstatic%2Fwebseed%2F6050732a-8a7a-43d4-a6cd-809525a1d206-240.mp4&ws=https%3A%2F%2Fpeertube.iselfhost.com%2Fstatic%2Fredundancy%2F6050732a-8a7a-43d4-a6cd-809525a1d206-240.mp4&ws=https%3A%2F%2Ftube.privacytools.io%2Fstatic%2Fredundancy%2F6050732a-8a7a-43d4-a6cd-809525a1d206-240.mp4","height":240},{"type":"Link","mediaType":"application/x-mpegURL","href":"https://framatube.org/static/streaming-playlists/hls/6050732a-8a7a-43d4-a6cd-809525a1d206/master.m3u8","tag":[{"type":"Infohash","name":"f7428214539626e062f300f2ca4cf9154575144e"},{"type":"Infohash","name":"46e236dffb1ea6b9123a5396cbe88e97dd94cc6c"},{"type":"Infohash","name":"11f1045830b5d786c788f2594d19f128764e7d87"},{"type":"Infohash","name":"4327ad3e0d84de100130a27e9ab6fe40c4284f0e"},{"type":"Infohash","name":"41e2eee8e7b23a63c23a77c40a46de11492a4831"},{"type":"Link","name":"sha256","mediaType":"application/json","href":"https://framatube.org/static/streaming-playlists/hls/6050732a-8a7a-43d4-a6cd-809525a1d206/segments-sha256.json"},{"type":"Link","mediaType":"video/mp4","href":"https://framatube.org/static/streaming-playlists/hls/6050732a-8a7a-43d4-a6cd-809525a1d206/6050732a-8a7a-43d4-a6cd-809525a1d206-1080-fragmented.mp4","height":1080,"size":1156777472,"fps":25},{"type":"Link","rel":["metadata","video/mp4"],"mediaType":"application/json","href":"https://framatube.org/api/v1/videos/6050732a-8a7a-43d4-a6cd-809525a1d206/metadata/1309940","height":1080,"fps":25},{"type":"Link","mediaType":"application/x-bittorrent","href":"https://framatube.org/static/torrents/6050732a-8a7a-43d4-a6cd-809525a1d206-1080-hls.torrent","height":1080},{"type":"Link","mediaType":"application/x-bittorrent;x-scheme-handler/magnet","href":"magnet:?xs=https%3A%2F%2Fframatube.org%2Fstatic%2Ftorrents%2F6050732a-8a7a-43d4-a6cd-809525a1d206-1080-hls.torrent&xt=urn:btih:0204d780ebfab0d5d9d3476a038e812ad792deeb&dn=D%C3%A9framasoftisons+Internet+%5BFramasoft%5D&tr=wss%3A%2F%2Fframatube.org%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fframatube.org%2Ftracker%2Fannounce&ws=https%3A%2F%2Fframatube.org%2Fstatic%2Fstreaming-playlists%2Fhls%2F6050732a-8a7a-43d4-a6cd-809525a1d206%2F6050732a-8a7a-43d4-a6cd-809525a1d206-1080-fragmented.mp4","height":1080},{"type":"Link","mediaType":"video/mp4","href":"https://framatube.org/static/streaming-playlists/hls/6050732a-8a7a-43d4-a6cd-809525a1d206/6050732a-8a7a-43d4-a6cd-809525a1d206-720-fragmented.mp4","height":720,"size":496533741,"fps":25},{"type":"Link","rel":["metadata","video/mp4"],"mediaType":"application/json","href":"https://framatube.org/api/v1/videos/6050732a-8a7a-43d4-a6cd-809525a1d206/metadata/1309947","height":720,"fps":25},{"type":"Link","mediaType":"application/x-bittorrent","href":"https://framatube.org/static/torrents/6050732a-8a7a-43d4-a6cd-809525a1d206-720-hls.torrent","height":720},{"type":"Link","mediaType":"application/x-bittorrent;x-scheme-handler/magnet","href":"magnet:?xs=https%3A%2F%2Fframatube.org%2Fstatic%2Ftorrents%2F6050732a-8a7a-43d4-a6cd-809525a1d206-720-hls.torrent&xt=urn:btih:8ed1e8bccde709901c26e315fc8f53bfd26d1ba6&dn=D%C3%A9framasoftisons+Internet+%5BFramasoft%5D&tr=wss%3A%2F%2Fframatube.org%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fframatube.org%2Ftracker%2Fannounce&ws=https%3A%2F%2Fframatube.org%2Fstatic%2Fstreaming-playlists%2Fhls%2F6050732a-8a7a-43d4-a6cd-809525a1d206%2F6050732a-8a7a-43d4-a6cd-809525a1d206-720-fragmented.mp4","height":720},{"type":"Link","mediaType":"video/mp4","href":"https://framatube.org/static/streaming-playlists/hls/6050732a-8a7a-43d4-a6cd-809525a1d206/6050732a-8a7a-43d4-a6cd-809525a1d206-480-fragmented.mp4","height":480,"size":249562889,"fps":25},{"type":"Link","rel":["metadata","video/mp4"],"mediaType":"application/json","href":"https://framatube.org/api/v1/videos/6050732a-8a7a-43d4-a6cd-809525a1d206/metadata/1309945","height":480,"fps":25},{"type":"Link","mediaType":"application/x-bittorrent","href":"https://framatube.org/static/torrents/6050732a-8a7a-43d4-a6cd-809525a1d206-480-hls.torrent","height":480},{"type":"Link","mediaType":"application/x-bittorrent;x-scheme-handler/magnet","href":"magnet:?xs=https%3A%2F%2Fframatube.org%2Fstatic%2Ftorrents%2F6050732a-8a7a-43d4-a6cd-809525a1d206-480-hls.torrent&xt=urn:btih:5d14f38ded29de629668fe1cfc61a75f4cce2628&dn=D%C3%A9framasoftisons+Internet+%5BFramasoft%5D&tr=wss%3A%2F%2Fframatube.org%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fframatube.org%2Ftracker%2Fannounce&ws=https%3A%2F%2Fframatube.org%2Fstatic%2Fstreaming-playlists%2Fhls%2F6050732a-8a7a-43d4-a6cd-809525a1d206%2F6050732a-8a7a-43d4-a6cd-809525a1d206-480-fragmented.mp4","height":480},{"type":"Link","mediaType":"video/mp4","href":"https://framatube.org/static/streaming-playlists/hls/6050732a-8a7a-43d4-a6cd-809525a1d206/6050732a-8a7a-43d4-a6cd-809525a1d206-360-fragmented.mp4","height":360,"size":170836415,"fps":25},{"type":"Link","rel":["metadata","video/mp4"],"mediaType":"application/json","href":"https://framatube.org/api/v1/videos/6050732a-8a7a-43d4-a6cd-809525a1d206/metadata/1309946","height":360,"fps":25},{"type":"Link","mediaType":"application/x-bittorrent","href":"https://framatube.org/static/torrents/6050732a-8a7a-43d4-a6cd-809525a1d206-360-hls.torrent","height":360},{"type":"Link","mediaType":"application/x-bittorrent;x-scheme-handler/magnet","href":"magnet:?xs=https%3A%2F%2Fframatube.org%2Fstatic%2Ftorrents%2F6050732a-8a7a-43d4-a6cd-809525a1d206-360-hls.torrent&xt=urn:btih:30125488789080ad405ebcee6c214945f31b8f30&dn=D%C3%A9framasoftisons+Internet+%5BFramasoft%5D&tr=wss%3A%2F%2Fframatube.org%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fframatube.org%2Ftracker%2Fannounce&ws=https%3A%2F%2Fframatube.org%2Fstatic%2Fstreaming-playlists%2Fhls%2F6050732a-8a7a-43d4-a6cd-809525a1d206%2F6050732a-8a7a-43d4-a6cd-809525a1d206-360-fragmented.mp4","height":360},{"type":"Link","mediaType":"video/mp4","href":"https://framatube.org/static/streaming-playlists/hls/6050732a-8a7a-43d4-a6cd-809525a1d206/6050732a-8a7a-43d4-a6cd-809525a1d206-240-fragmented.mp4","height":240,"size":112529249,"fps":25},{"type":"Link","rel":["metadata","video/mp4"],"mediaType":"application/json","href":"https://framatube.org/api/v1/videos/6050732a-8a7a-43d4-a6cd-809525a1d206/metadata/1309948","height":240,"fps":25},{"type":"Link","mediaType":"application/x-bittorrent","href":"https://framatube.org/static/torrents/6050732a-8a7a-43d4-a6cd-809525a1d206-240-hls.torrent","height":240},{"type":"Link","mediaType":"application/x-bittorrent;x-scheme-handler/magnet","href":"magnet:?xs=https%3A%2F%2Fframatube.org%2Fstatic%2Ftorrents%2F6050732a-8a7a-43d4-a6cd-809525a1d206-240-hls.torrent&xt=urn:btih:8b452bf4e70b9078d4e74ca8b5523cc9dc70d10a&dn=D%C3%A9framasoftisons+Internet+%5BFramasoft%5D&tr=wss%3A%2F%2Fframatube.org%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fframatube.org%2Ftracker%2Fannounce&ws=https%3A%2F%2Fframatube.org%2Fstatic%2Fstreaming-playlists%2Fhls%2F6050732a-8a7a-43d4-a6cd-809525a1d206%2F6050732a-8a7a-43d4-a6cd-809525a1d206-240-fragmented.mp4","height":240}]}],"likes":"https://framatube.org/videos/watch/6050732a-8a7a-43d4-a6cd-809525a1d206/likes","dislikes":"https://framatube.org/videos/watch/6050732a-8a7a-43d4-a6cd-809525a1d206/dislikes","shares":"https://framatube.org/videos/watch/6050732a-8a7a-43d4-a6cd-809525a1d206/announces","comments":"https://framatube.org/videos/watch/6050732a-8a7a-43d4-a6cd-809525a1d206/comments","attributedTo":[{"type":"Person","id":"https://framatube.org/accounts/framasoft"},{"type":"Group","id":"https://framatube.org/video-channels/bf54d359-cfad-4935-9d45-9d6be93f63e8"}],"to":["https://www.w3.org/ns/activitystreams#Public"],"cc":["https://framatube.org/accounts/framasoft/followers"]},"to":["https://www.w3.org/ns/activitystreams#Public"],"cc":["https://framatube.org/accounts/framasoft/followers"],"@context":["https://www.w3.org/ns/activitystreams","https://w3id.org/security/v1",{"RsaSignature2017":"https://w3id.org/security#RsaSignature2017"},{"pt":"https://joinpeertube.org/ns#","sc":"http://schema.org#","Hashtag":"as:Hashtag","uuid":"sc:identifier","category":"sc:category","licence":"sc:license","subtitleLanguage":"sc:subtitleLanguage","sensitive":"as:sensitive","language":"sc:inLanguage","Infohash":"pt:Infohash","Playlist":"pt:Playlist","PlaylistElement":"pt:PlaylistElement","originallyPublishedAt":"sc:datePublished","views":{"@type":"sc:Number","@id":"pt:views"},"state":{"@type":"sc:Number","@id":"pt:state"},"size":{"@type":"sc:Number","@id":"pt:size"},"fps":{"@type":"sc:Number","@id":"pt:fps"},"startTimestamp":{"@type":"sc:Number","@id":"pt:startTimestamp"},"stopTimestamp":{"@type":"sc:Number","@id":"pt:stopTimestamp"},"position":{"@type":"sc:Number","@id":"pt:position"},"commentsEnabled":{"@type":"sc:Boolean","@id":"pt:commentsEnabled"},"downloadEnabled":{"@type":"sc:Boolean","@id":"pt:downloadEnabled"},"waitTranscoding":{"@type":"sc:Boolean","@id":"pt:waitTranscoding"},"support":{"@type":"sc:Text","@id":"pt:support"},"likes":{"@id":"as:likes","@type":"@id"},"dislikes":{"@id":"as:dislikes","@type":"@id"},"playlists":{"@id":"pt:playlists","@type":"@id"},"shares":{"@id":"as:shares","@type":"@id"},"comments":{"@id":"as:comments","@type":"@id"}}]}
\ No newline at end of file diff --git a/test/fixtures/tesla_mock/http__gs.example.org_index.php_api_statuses_user_timeline_1.atom.xml b/test/fixtures/tesla_mock/http__gs.example.org_index.php_api_statuses_user_timeline_1.atom.xml deleted file mode 100644 index 490467708..000000000 --- a/test/fixtures/tesla_mock/http__gs.example.org_index.php_api_statuses_user_timeline_1.atom.xml +++ /dev/null @@ -1,460 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:georss="http://www.georss.org/georss" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:media="http://purl.org/syndication/atommedia" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:statusnet="http://status.net/schema/api/1/"> - <generator uri="https://gnu.io/social" version="1.2.0-beta4">GNU social</generator> - <id>http://gs.example.org/index.php/api/statuses/user_timeline/1.atom</id> - <title>lambda timeline</title> - <subtitle>Updates from lambda on gs.example.org!</subtitle> - <logo>http://gs.example.org/theme/neo-gnu/default-avatar-profile.png</logo> - <updated>2017-05-05T12:09:57+00:00</updated> -<author> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>http://gs.example.org:4040/index.php/user/1</uri> - <name>lambda</name> - <link rel="alternate" type="text/html" href="http://gs.example.org/index.php/lambda"/> - <link rel="avatar" type="image/png" media:width="96" media:height="96" href="http://gs.example.org/theme/neo-gnu/default-avatar-profile.png"/> - <link rel="avatar" type="image/png" media:width="48" media:height="48" href="http://gs.example.org/theme/neo-gnu/default-avatar-stream.png"/> - <link rel="avatar" type="image/png" media:width="24" media:height="24" href="http://gs.example.org/theme/neo-gnu/default-avatar-mini.png"/> - <poco:preferredUsername>lambda</poco:preferredUsername> - <poco:displayName>lambda</poco:displayName> - <followers url="http://gs.example.org/index.php/lambda/subscribers"></followers> - <statusnet:profile_info local_id="1"></statusnet:profile_info> -</author> - <link href="http://gs.example.org/index.php/lambda" rel="alternate" type="text/html"/> - <link href="http://gs.example.org/index.php/main/sup" rel="http://api.friendfeed.com/2008/03#sup" type="application/json"/> - <link href="http://gs.example.org/index.php/api/statuses/user_timeline/1.atom?max_id=34" rel="next" type="application/atom+xml"/> - <link href="http://gs.example.org/index.php/main/push/hub" rel="hub"/> - <link href="http://gs.example.org/index.php/main/salmon/user/1" rel="salmon"/> - <link href="http://gs.example.org/index.php/main/salmon/user/1" rel="http://salmon-protocol.org/ns/salmon-replies"/> - <link href="http://gs.example.org/index.php/main/salmon/user/1" rel="http://salmon-protocol.org/ns/salmon-mention"/> - <link href="http://gs.example.org/index.php/api/statuses/user_timeline/1.atom" rel="self" type="application/atom+xml"/> -<entry> - <id>tag:gs.example.org,2017-05-04:noticeId=84:objectType=note</id> - <title>lambda repeated a notice by lambda2</title> - <content type="html">RT @<a href="http://gs.example.org/index.php/user/7" class="h-card mention">lambda2</a> Hello!</content> - <link rel="alternate" type="text/html" href="http://gs.example.org/index.php/notice/84"/> - <activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb> - <published>2017-05-04T16:38:50+00:00</published> - <updated>2017-05-04T16:38:50+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type> - <id>tag:gs.example.org,2017-05-01:noticeId=67:objectType=note</id> - <title></title> - <content type="html">Hello!</content> - <link rel="alternate" type="text/html" href="http://gs.example.org/index.php/notice/67"/> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-05-01T08:41:04+00:00</published> - <updated>2017-05-01T08:41:04+00:00</updated> - <author> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>http://gs.example.org/index.php/user/7</uri> - <name>lambda2</name> - <link rel="alternate" type="text/html" href="http://gs.example.org/index.php/lambda2"/> - <link rel="avatar" type="image/png" media:width="270" media:height="270" href="http://gs.example.org/avatar/7-270-20170501084053.png"/> - <link rel="avatar" type="image/png" media:width="96" media:height="96" href="http://gs.example.org/avatar/7-96-20170501084054.png"/> - <link rel="avatar" type="image/png" media:width="48" media:height="48" href="http://gs.example.org/avatar/7-48-20170501084104.png"/> - <link rel="avatar" type="image/png" media:width="24" media:height="24" href="http://gs.example.org/avatar/7-24-20170501084104.png"/> - <poco:preferredUsername>lambda2</poco:preferredUsername> - <poco:displayName>lambda2</poco:displayName> - <followers url="http://gs.example.org/index.php/lambda2/subscribers"></followers> - <statusnet:profile_info local_id="7"></statusnet:profile_info> - </author> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:gs.example.org,2017-05-01:noticeId=67:objectType=note</id> - <title>New note by lambda2</title> - <content type="html">Hello!</content> - <link rel="alternate" type="text/html" href="http://gs.example.org/index.php/notice/67"/> - <status_net notice_id="67"></status_net> - </activity:object> - <link rel="ostatus:conversation" href="tag:gs.example.org,2017-05-01:objectType=thread:nonce=cffa792cb95fe417"/> - <ostatus:conversation>tag:gs.example.org,2017-05-01:objectType=thread:nonce=cffa792cb95fe417</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <source> - <id>http://gs.example.org/index.php/api/statuses/user_timeline/7.atom</id> - <title>lambda2</title> - <link rel="alternate" type="text/html" href="http://gs.example.org/index.php/lambda2"/> - <link rel="self" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/user_timeline/7.atom"/> - <link rel="license" href="https://creativecommons.org/licenses/by/3.0/"/> - <icon>http://gs.example.org/avatar/7-96-20170501084054.png</icon> - <updated>2017-05-01T16:33:10+00:00</updated> - </source> - <link rel="self" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/67.atom"/> - <link rel="edit" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/67.atom"/> - </activity:object> - <link rel="ostatus:conversation" href="tag:gs.example.org,2017-05-01:objectType=thread:nonce=cffa792cb95fe417"/> - <ostatus:conversation>tag:gs.example.org,2017-05-01:objectType=thread:nonce=cffa792cb95fe417</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/84.atom"/> - <link rel="edit" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/84.atom"/> - <statusnet:notice_info local_id="84" source="web" repeat_of="67"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:gs.example.org,2017-04-30:noticeId=63:objectType=note</id> - <title>New note by lambda</title> - <content type="html">what now?</content> - <link rel="alternate" type="text/html" href="http://gs.example.org/index.php/notice/63"/> - <status_net notice_id="63"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-04-30T10:09:57+00:00</published> - <updated>2017-04-30T10:09:57+00:00</updated> - <thr:in-reply-to ref="http://pleroma.example.org:4000/objects/477d8933-7591-4755-ba7a-2c34073ddc3c" href="http://pleroma.example.org:4000/objects/477d8933-7591-4755-ba7a-2c34073ddc3c"></thr:in-reply-to> - <link rel="related" href="http://pleroma.example.org:4000/objects/477d8933-7591-4755-ba7a-2c34073ddc3c"/> - <link rel="ostatus:conversation" href="tag:gs.example.org,2017-04-30:objectType=thread:nonce=1bbb60991ae9874b"/> - <ostatus:conversation>tag:gs.example.org,2017-04-30:objectType=thread:nonce=1bbb60991ae9874b</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="http://pleroma.example.org:4000/users/lain5"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/63.atom"/> - <link rel="edit" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/63.atom"/> - <statusnet:notice_info local_id="63" source="web"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:gs.example.org,2017-04-30:noticeId=61:objectType=note</id> - <title>New note by lambda</title> - <content type="html">@<a href="http://pleroma.example.org:4000/users/lain5" class="h-card mention">lain5</a> Hello!</content> - <link rel="alternate" type="text/html" href="http://gs.example.org/index.php/notice/61"/> - <status_net notice_id="61"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-04-30T10:07:26+00:00</published> - <updated>2017-04-30T10:07:26+00:00</updated> - <link rel="ostatus:conversation" href="tag:gs.example.org,2017-04-30:objectType=thread:nonce=1bbb60991ae9874b"/> - <ostatus:conversation>tag:gs.example.org,2017-04-30:objectType=thread:nonce=1bbb60991ae9874b</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="http://pleroma.example.org:4000/users/lain5"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/61.atom"/> - <link rel="edit" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/61.atom"/> - <statusnet:notice_info local_id="61" source="web"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:gs.example.org,2017-04-29:noticeId=59:objectType=note</id> - <title>New note by lambda</title> - <content type="html">ey</content> - <link rel="alternate" type="text/html" href="http://gs.example.org/index.php/notice/59"/> - <status_net notice_id="59"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-04-29T17:04:59+00:00</published> - <updated>2017-04-29T17:04:59+00:00</updated> - <link rel="ostatus:conversation" href="tag:gs.example.org,2017-04-29:objectType=thread:nonce=4cc42c2c61a0f4bd"/> - <ostatus:conversation>tag:gs.example.org,2017-04-29:objectType=thread:nonce=4cc42c2c61a0f4bd</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/59.atom"/> - <link rel="edit" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/59.atom"/> - <statusnet:notice_info local_id="59" source="web"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:gs.example.org,2017-04-29:noticeId=58:objectType=note</id> - <title>New note by lambda</title> - <content type="html">Another one.</content> - <link rel="alternate" type="text/html" href="http://gs.example.org/index.php/notice/58"/> - <status_net notice_id="58"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-04-29T17:02:47+00:00</published> - <updated>2017-04-29T17:02:47+00:00</updated> - <link rel="ostatus:conversation" href="tag:gs.example.org,2017-04-29:objectType=thread:nonce=53e9b8f1d6d38d13"/> - <ostatus:conversation>tag:gs.example.org,2017-04-29:objectType=thread:nonce=53e9b8f1d6d38d13</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/58.atom"/> - <link rel="edit" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/58.atom"/> - <statusnet:notice_info local_id="58" source="web"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:gs.example.org,2017-04-29:noticeId=57:objectType=note</id> - <title>New note by lambda</title> - <content type="html">Let's see if this comes over.</content> - <link rel="alternate" type="text/html" href="http://gs.example.org/index.php/notice/57"/> - <status_net notice_id="57"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-04-29T17:01:39+00:00</published> - <updated>2017-04-29T17:01:39+00:00</updated> - <link rel="ostatus:conversation" href="tag:gs.example.org,2017-04-29:objectType=thread:nonce=238a7bd3ffc7c9cc"/> - <ostatus:conversation>tag:gs.example.org,2017-04-29:objectType=thread:nonce=238a7bd3ffc7c9cc</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/57.atom"/> - <link rel="edit" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/57.atom"/> - <statusnet:notice_info local_id="57" source="web"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:gs.example.org,2017-04-29:noticeId=56:objectType=note</id> - <title>New note by lambda</title> - <content type="html">@<a href="http://pleroma.example.org:4000/users/lain5" class="h-card mention">lain5</a> Hey!</content> - <link rel="alternate" type="text/html" href="http://gs.example.org/index.php/notice/56"/> - <status_net notice_id="56"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-04-29T16:38:13+00:00</published> - <updated>2017-04-29T16:38:13+00:00</updated> - <link rel="ostatus:conversation" href="tag:gs.example.org,2017-04-29:objectType=thread:nonce=2629d3a398171b0f"/> - <ostatus:conversation>tag:gs.example.org,2017-04-29:objectType=thread:nonce=2629d3a398171b0f</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="http://pleroma.example.org:4000/users/lain5"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/56.atom"/> - <link rel="edit" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/56.atom"/> - <statusnet:notice_info local_id="56" source="web"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:gs.example.org:4040,2017-04-25:noticeId=55:objectType=note</id> - <title>New note by lambda</title> - <content type="html">hey.</content> - <link rel="alternate" type="text/html" href="http://gs.example.org/index.php/notice/55"/> - <status_net notice_id="55"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-04-25T18:16:13+00:00</published> - <updated>2017-04-25T18:16:13+00:00</updated> - <thr:in-reply-to ref="http://pleroma.example.org:4000/objects/55bce8fc-b423-46b1-af71-3759ab4670bc" href="http://pleroma.example.org:4000/objects/55bce8fc-b423-46b1-af71-3759ab4670bc"></thr:in-reply-to> - <link rel="related" href="http://pleroma.example.org:4000/objects/55bce8fc-b423-46b1-af71-3759ab4670bc"/> - <link rel="ostatus:conversation" href="http://pleroma.example.org:4000/contexts/8f6f45d4-8e4d-4e1a-a2de-09f27367d2d0"/> - <ostatus:conversation>http://pleroma.example.org:4000/contexts/8f6f45d4-8e4d-4e1a-a2de-09f27367d2d0</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="http://pleroma.example.org:4000/users/lain5"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/55.atom"/> - <link rel="edit" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/55.atom"/> - <statusnet:notice_info local_id="55" source="web"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:gs.example.org:4040,2017-04-25:noticeId=53:objectType=note</id> - <title>New note by lambda</title> - <content type="html">and this?</content> - <link rel="alternate" type="text/html" href="http://gs.example.org/index.php/notice/53"/> - <status_net notice_id="53"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-04-25T18:14:34+00:00</published> - <updated>2017-04-25T18:14:34+00:00</updated> - <thr:in-reply-to ref="http://pleroma.example.org:4000/objects/875b219f-8ced-4948-832e-137a06a88031" href="http://pleroma.example.org:4000/objects/875b219f-8ced-4948-832e-137a06a88031"></thr:in-reply-to> - <link rel="related" href="http://pleroma.example.org:4000/objects/875b219f-8ced-4948-832e-137a06a88031"/> - <link rel="ostatus:conversation" href="http://pleroma.example.org:4000/contexts/24779b0e-91ad-487e-81bd-6cf5bb437b09"/> - <ostatus:conversation>http://pleroma.example.org:4000/contexts/24779b0e-91ad-487e-81bd-6cf5bb437b09</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="http://pleroma.example.org:4000/users/lain5"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/53.atom"/> - <link rel="edit" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/53.atom"/> - <statusnet:notice_info local_id="53" source="web"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:gs.example.org:4040,2017-04-25:noticeId=52:objectType=note</id> - <title>New note by lambda</title> - <content type="html">yeah it does :)</content> - <link rel="alternate" type="text/html" href="http://gs.example.org/index.php/notice/52"/> - <status_net notice_id="52"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-04-25T18:13:31+00:00</published> - <updated>2017-04-25T18:13:31+00:00</updated> - <thr:in-reply-to ref="http://pleroma.example.org:4000/objects/9c0430b4-ccb3-4e2c-9c50-ee345ebe18fc" href="http://pleroma.example.org:4000/objects/9c0430b4-ccb3-4e2c-9c50-ee345ebe18fc"></thr:in-reply-to> - <link rel="related" href="http://pleroma.example.org:4000/objects/9c0430b4-ccb3-4e2c-9c50-ee345ebe18fc"/> - <link rel="ostatus:conversation" href="tag:gs.example.org:4040,2017-04-25:objectType=thread:nonce=e0dc24b1a93ab6b3"/> - <ostatus:conversation>tag:gs.example.org:4040,2017-04-25:objectType=thread:nonce=e0dc24b1a93ab6b3</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="http://pleroma.example.org:4000/users/lain5"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/52.atom"/> - <link rel="edit" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/52.atom"/> - <statusnet:notice_info local_id="52" source="web"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:gs.example.org:4040,2017-04-25:noticeId=50:objectType=note</id> - <title>New note by lambda</title> - <content type="html">@<a href="http://pleroma.example.org:4000/users/lain5" class="h-card mention">lain5</a> Let's try with one that originates here!</content> - <link rel="alternate" type="text/html" href="http://gs.example.org/index.php/notice/50"/> - <status_net notice_id="50"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-04-25T18:10:28+00:00</published> - <updated>2017-04-25T18:10:28+00:00</updated> - <link rel="ostatus:conversation" href="tag:gs.example.org:4040,2017-04-25:objectType=thread:nonce=e0dc24b1a93ab6b3"/> - <ostatus:conversation>tag:gs.example.org:4040,2017-04-25:objectType=thread:nonce=e0dc24b1a93ab6b3</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="http://pleroma.example.org:4000/users/lain5"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/50.atom"/> - <link rel="edit" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/50.atom"/> - <statusnet:notice_info local_id="50" source="web"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:gs.example.org:4040,2017-04-25:noticeId=48:objectType=note</id> - <title>New note by lambda</title> - <content type="html">works?</content> - <link rel="alternate" type="text/html" href="http://gs.example.org/index.php/notice/48"/> - <status_net notice_id="48"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-04-25T18:08:44+00:00</published> - <updated>2017-04-25T18:08:44+00:00</updated> - <thr:in-reply-to ref="http://pleroma.example.org:4000/objects/8664caae-1cd6-4c1f-b1d7-27bd4ce76966" href="http://pleroma.example.org:4000/objects/8664caae-1cd6-4c1f-b1d7-27bd4ce76966"></thr:in-reply-to> - <link rel="related" href="http://pleroma.example.org:4000/objects/8664caae-1cd6-4c1f-b1d7-27bd4ce76966"/> - <link rel="ostatus:conversation" href="http://pleroma.example.org:4000/contexts/24779b0e-91ad-487e-81bd-6cf5bb437b09"/> - <ostatus:conversation>http://pleroma.example.org:4000/contexts/24779b0e-91ad-487e-81bd-6cf5bb437b09</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="http://pleroma.example.org:4000/users/lain5"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/48.atom"/> - <link rel="edit" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/48.atom"/> - <statusnet:notice_info local_id="48" source="web"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:gs.example.org:4040,2017-04-25:noticeId=46:objectType=note</id> - <title>New note by lambda</title> - <content type="html">Let's send you an answer.</content> - <link rel="alternate" type="text/html" href="http://gs.example.org/index.php/notice/46"/> - <status_net notice_id="46"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-04-25T18:05:31+00:00</published> - <updated>2017-04-25T18:05:31+00:00</updated> - <thr:in-reply-to ref="http://pleroma.example.org:4000/objects/89ec2578-3f05-4b04-99b8-3e40f1282491" href="http://pleroma.example.org:4000/objects/89ec2578-3f05-4b04-99b8-3e40f1282491"></thr:in-reply-to> - <link rel="related" href="http://pleroma.example.org:4000/objects/89ec2578-3f05-4b04-99b8-3e40f1282491"/> - <link rel="ostatus:conversation" href="tag:gs.example.org:4040,2017-04-25:objectType=thread:nonce=73c7bcf6658f7ce3"/> - <ostatus:conversation>tag:gs.example.org:4040,2017-04-25:objectType=thread:nonce=73c7bcf6658f7ce3</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="http://pleroma.example.org:4000/users/lain5"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/46.atom"/> - <link rel="edit" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/46.atom"/> - <statusnet:notice_info local_id="46" source="web"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:gs.example.org:4040,2017-04-25:noticeId=44:objectType=note</id> - <title>New note by lambda</title> - <content type="html">Hey.</content> - <link rel="alternate" type="text/html" href="http://gs.example.org/index.php/notice/44"/> - <status_net notice_id="44"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-04-25T18:01:09+00:00</published> - <updated>2017-04-25T18:01:09+00:00</updated> - <thr:in-reply-to ref="http://pleroma.example.org:4000/objects/5047e0a8-2302-483a-a420-ae835f5ca5a1" href="http://pleroma.example.org:4000/objects/5047e0a8-2302-483a-a420-ae835f5ca5a1"></thr:in-reply-to> - <link rel="related" href="http://pleroma.example.org:4000/objects/5047e0a8-2302-483a-a420-ae835f5ca5a1"/> - <link rel="ostatus:conversation" href="tag:gs.example.org:4040,2017-04-25:objectType=thread:nonce=6e7c8fc2823380b4"/> - <ostatus:conversation>tag:gs.example.org:4040,2017-04-25:objectType=thread:nonce=6e7c8fc2823380b4</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="http://pleroma.example.org:4000/users/lain5"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/44.atom"/> - <link rel="edit" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/44.atom"/> - <statusnet:notice_info local_id="44" source="web"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:gs.example.org:4040,2017-04-25:noticeId=43:objectType=note</id> - <title>New note by lambda</title> - <content type="html">What's coming to you?</content> - <link rel="alternate" type="text/html" href="http://gs.example.org/index.php/notice/43"/> - <status_net notice_id="43"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-04-25T17:58:41+00:00</published> - <updated>2017-04-25T17:58:41+00:00</updated> - <thr:in-reply-to ref="http://pleroma.example.org:4000/objects/5047e0a8-2302-483a-a420-ae835f5ca5a1" href="http://pleroma.example.org:4000/objects/5047e0a8-2302-483a-a420-ae835f5ca5a1"></thr:in-reply-to> - <link rel="related" href="http://pleroma.example.org:4000/objects/5047e0a8-2302-483a-a420-ae835f5ca5a1"/> - <link rel="ostatus:conversation" href="tag:gs.example.org:4040,2017-04-25:objectType=thread:nonce=6e7c8fc2823380b4"/> - <ostatus:conversation>tag:gs.example.org:4040,2017-04-25:objectType=thread:nonce=6e7c8fc2823380b4</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="http://pleroma.example.org:4000/users/lain5"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/43.atom"/> - <link rel="edit" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/43.atom"/> - <statusnet:notice_info local_id="43" source="web"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:gs.example.org:4040,2017-04-25:noticeId=42:objectType=note</id> - <title>New note by lambda</title> - <content type="html">Now this is podracing.</content> - <link rel="alternate" type="text/html" href="http://gs.example.org/index.php/notice/42"/> - <status_net notice_id="42"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-04-25T17:57:40+00:00</published> - <updated>2017-04-25T17:57:40+00:00</updated> - <thr:in-reply-to ref="http://pleroma.example.org:4000/objects/5047e0a8-2302-483a-a420-ae835f5ca5a1" href="http://pleroma.example.org:4000/objects/5047e0a8-2302-483a-a420-ae835f5ca5a1"></thr:in-reply-to> - <link rel="related" href="http://pleroma.example.org:4000/objects/5047e0a8-2302-483a-a420-ae835f5ca5a1"/> - <link rel="ostatus:conversation" href="tag:gs.example.org:4040,2017-04-25:objectType=thread:nonce=6e7c8fc2823380b4"/> - <ostatus:conversation>tag:gs.example.org:4040,2017-04-25:objectType=thread:nonce=6e7c8fc2823380b4</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="http://pleroma.example.org:4000/users/lain5"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/42.atom"/> - <link rel="edit" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/42.atom"/> - <statusnet:notice_info local_id="42" source="web"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:gs.example.org:4040,2017-04-25:noticeId=39:objectType=note</id> - <title>New note by lambda</title> - <content type="html">Sure looks like it!</content> - <link rel="alternate" type="text/html" href="http://gs.example.org/index.php/notice/39"/> - <status_net notice_id="39"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-04-25T17:48:27+00:00</published> - <updated>2017-04-25T17:48:27+00:00</updated> - <thr:in-reply-to ref="http://pleroma.example.org:4000/objects/c9fe09c2-7504-46d2-a4f6-44a708455e6f" href="http://pleroma.example.org:4000/objects/c9fe09c2-7504-46d2-a4f6-44a708455e6f"></thr:in-reply-to> - <link rel="related" href="http://pleroma.example.org:4000/objects/c9fe09c2-7504-46d2-a4f6-44a708455e6f"/> - <link rel="ostatus:conversation" href="tag:gs.example.org:4040,2017-04-25:objectType=thread:nonce=4c6114a75bb4cea5"/> - <ostatus:conversation>tag:gs.example.org:4040,2017-04-25:objectType=thread:nonce=4c6114a75bb4cea5</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="http://pleroma.example.org:4000/users/lain5"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/39.atom"/> - <link rel="edit" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/39.atom"/> - <statusnet:notice_info local_id="39" source="web"></statusnet:notice_info> -</entry> -<entry> - <id>tag:gs.example.org:4040,2017-04-25:subscription:1:person:6:2017-04-25T17:47:47+00:00</id> - <title>lambda (lambda)'s status on Tuesday, 25-Apr-2017 17:47:47 UTC</title> - <content type="html"><a href="http://gs.example.org:4040/index.php/lambda">lambda</a> started following <a href="http://pleroma.example.org:4000/users/lain5">l</a>.</content> - <link rel="alternate" type="text/html" href="http://gs.example.org/index.php/notice/37"/> - <activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb> - <published>2017-04-25T17:47:47+00:00</published> - <updated>2017-04-25T17:47:47+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <id>http://pleroma.example.org:4000/users/lain5</id> - <title>l</title> - <summary>lambadalambda</summary> - <link rel="alternate" type="text/html" href="http://pleroma.example.org:4000/users/lain5"/> - <link rel="avatar" type="image/png" media:width="48" media:height="48" href="http://gs.example.org/avatar/6-original-20170425174605.png"/> - <link rel="avatar" type="image/png" media:width="96" media:height="96" href="http://gs.example.org/avatar/6-96-20170425174605.png"/> - <link rel="avatar" type="image/png" media:width="48" media:height="48" href="http://gs.example.org/avatar/6-original-20170425174605.png"/> - <link rel="avatar" type="image/png" media:width="24" media:height="24" href="http://gs.example.org/avatar/6-24-20170425174747.png"/> - <poco:preferredUsername>lain5</poco:preferredUsername> - <poco:displayName>l</poco:displayName> - <poco:note>lambadalambda</poco:note> - </activity:object> - <link rel="ostatus:conversation" href="tag:gs.example.org:4040,2017-04-25:objectType=thread:nonce=119acad17515314c"/> - <ostatus:conversation>tag:gs.example.org:4040,2017-04-25:objectType=thread:nonce=119acad17515314c</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/37.atom"/> - <link rel="edit" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/37.atom"/> - <statusnet:notice_info local_id="37" source="activity"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:gs.example.org:4040,2017-04-25:noticeId=36:objectType=note</id> - <title>New note by lambda</title> - <content type="html">@<a href="http://pleroma.example.org:4000/users/lain5" class="h-card mention">lain5</a> Hey, how are you?</content> - <link rel="alternate" type="text/html" href="http://gs.example.org/index.php/notice/36"/> - <status_net notice_id="36"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-04-25T17:46:22+00:00</published> - <updated>2017-04-25T17:46:22+00:00</updated> - <link rel="ostatus:conversation" href="tag:gs.example.org:4040,2017-04-25:objectType=thread:nonce=9c5ec19a18191372"/> - <ostatus:conversation>tag:gs.example.org:4040,2017-04-25:objectType=thread:nonce=9c5ec19a18191372</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="http://pleroma.example.org:4000/users/lain5"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/36.atom"/> - <link rel="edit" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/36.atom"/> - <statusnet:notice_info local_id="36" source="web"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:gs.example.org:4040,2017-04-25:noticeId=35:objectType=note</id> - <title>New note by lambda</title> - <content type="html">@lain5@pleroma.example.org does this not work?</content> - <link rel="alternate" type="text/html" href="http://gs.example.org/index.php/notice/35"/> - <status_net notice_id="35"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-04-25T17:42:31+00:00</published> - <updated>2017-04-25T17:42:31+00:00</updated> - <link rel="ostatus:conversation" href="tag:gs.example.org:4040,2017-04-25:objectType=thread:nonce=fc841d7f52caa363"/> - <ostatus:conversation>tag:gs.example.org:4040,2017-04-25:objectType=thread:nonce=fc841d7f52caa363</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/35.atom"/> - <link rel="edit" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/35.atom"/> - <statusnet:notice_info local_id="35" source="web"></statusnet:notice_info> -</entry> -</feed> diff --git a/test/fixtures/tesla_mock/https___mamot.fr_users_Skruyb.atom b/test/fixtures/tesla_mock/https___mamot.fr_users_Skruyb.atom deleted file mode 100644 index b5f3d923b..000000000 --- a/test/fixtures/tesla_mock/https___mamot.fr_users_Skruyb.atom +++ /dev/null @@ -1,342 +0,0 @@ -<?xml version="1.0"?> -<feed xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:media="http://purl.org/syndication/atommedia" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:mastodon="http://mastodon.social/schema/1.0"> - <id>https://mamot.fr/users/Skruyb.atom</id> - <title>The 7th Son</title> - <subtitle>Fr and En.
-Posts will disappear on a regular basis.</subtitle> - <updated>2017-04-28T13:54:23Z</updated> - <logo>https://mamot.fr/system/accounts/avatars/000/026/213/original/d95dbcfc76f77f4c.jpg?1493230984</logo> - <author> - <id>https://mamot.fr/users/Skruyb</id> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://mamot.fr/users/Skruyb</uri> - <name>Skruyb</name> - <email>Skruyb@mamot.fr</email> - <summary type="html"><p>Fr and En.<br />Posts will disappear on a regular basis.</p></summary> - <link rel="alternate" type="text/html" href="https://mamot.fr/@Skruyb"/> - <link rel="avatar" type="image/jpeg" media:width="120" media:height="120" href="https://mamot.fr/system/accounts/avatars/000/026/213/original/d95dbcfc76f77f4c.jpg?1493230984"/> - <link rel="header" type="image/jpeg" media:width="700" media:height="335" href="https://mamot.fr/system/accounts/headers/000/026/213/original/c1aabdf5c97eb875.jpg?1492797601"/> - <poco:preferredUsername>Skruyb</poco:preferredUsername> - <poco:displayName>The 7th Son</poco:displayName> - <poco:note>Fr and En.
-Posts will disappear on a regular basis.</poco:note> - <mastodon:scope>public</mastodon:scope> - </author> - <link rel="alternate" type="text/html" href="https://mamot.fr/@Skruyb"/> - <link rel="self" type="application/atom+xml" href="https://mamot.fr/users/Skruyb.atom"/> - <link rel="next" type="application/atom+xml" href="https://mamot.fr/users/Skruyb.atom?max_id=175878"/> - <link rel="hub" href="https://mamot.fr/api/push"/> - <link rel="salmon" href="https://mamot.fr/api/salmon/26213"/> - <entry> - <id>tag:mamot.fr,2017-05-10:objectId=1299665:objectType=Status</id> - <published>2017-05-10T20:06:59Z</published> - <updated>2017-05-10T20:06:59Z</updated> - <title>New status by Skruyb</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="es"><p><span class="h-card"><a href="https://pouets.ovh/@noName" class="u-url mention">@<span>noName</span></a></span></p><p>Pour comparer faut avoir tester... Ô wait!!! 😁</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://pouets.ovh/users/noName"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mamot.fr/users/Skruyb/updates/176780"/> - <link rel="self" type="application/atom+xml" href="https://mamot.fr/users/Skruyb/updates/176780.atom"/> - <thr:in-reply-to ref="tag:pouets.ovh,2017-05-10:objectId=114198:objectType=Status" href="https://pouets.ovh/users/noName/updates/1174"/> - </entry> - <entry> - <id>tag:mamot.fr,2017-05-10:objectId=1299185:objectType=Status</id> - <published>2017-05-10T19:52:14Z</published> - <updated>2017-05-10T19:52:14Z</updated> - <title>New status by Skruyb</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="fr"><p><span class="h-card"><a href="https://witches.town/@Dhveszak" class="u-url mention">@<span>Dhveszak</span></a></span></p><p>Toi!! Tu vises le ministère de la propagande avoue!!!!!!!</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://witches.town/users/Dhveszak"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mamot.fr/users/Skruyb/updates/176702"/> - <link rel="self" type="application/atom+xml" href="https://mamot.fr/users/Skruyb/updates/176702.atom"/> - <thr:in-reply-to ref="tag:witches.town,2017-05-10:objectId=1439170:objectType=Status" href="https://witches.town/users/Dhveszak/updates/193318"/> - </entry> - <entry> - <id>tag:mamot.fr,2017-05-10:objectId=1299019:objectType=Status</id> - <published>2017-05-10T19:47:19Z</published> - <updated>2017-05-10T19:47:19Z</updated> - <title>New status by Skruyb</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="fr"><p>Facebook s&apos;attaque aux sites internet &quot;trompeurs&quot;</p><p><a href="http://u.afp.com/4W4z" rel="nofollow noopener" target="_blank"><span class="invisible">http://</span><span class="">u.afp.com/4W4z</span><span class="invisible"></span></a></p><p>J&apos;attends de voir que Facebook s&apos;attaque à lui même... rien qu&apos;à lire leurs conditions générales d&apos;utilisation, le respect de la vie privée...</p><p>Charité bien ordonnée... Parfois l&apos;égoïsme aurait du bon.</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mamot.fr/users/Skruyb/updates/176668"/> - <link rel="self" type="application/atom+xml" href="https://mamot.fr/users/Skruyb/updates/176668.atom"/> - </entry> - <entry> - <id>tag:mamot.fr,2017-05-10:objectId=1298889:objectType=Status</id> - <published>2017-05-10T19:43:18Z</published> - <updated>2017-05-10T19:43:18Z</updated> - <title>New status by Skruyb</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="fr"><p><span class="h-card"><a href="https://octodon.social/@Balise" class="u-url mention">@<span>Balise</span></a></span></p><p>Fait comme moi, annonce que tu fais dans le flou artistique et que seuls des esprits éclairés pourront en percevoir la beauté et apprécier. Globalement après ça, tout le monde trouve les photos cool :-p</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://octodon.social/users/Balise"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mamot.fr/users/Skruyb/updates/176641"/> - <link rel="self" type="application/atom+xml" href="https://mamot.fr/users/Skruyb/updates/176641.atom"/> - <thr:in-reply-to ref="tag:octodon.social,2017-05-10:objectId=1887380:objectType=Status" href="https://octodon.social/users/Balise/updates/115220"/> - </entry> - <entry> - <id>tag:mamot.fr,2017-05-10:objectId=1298728:objectType=Status</id> - <published>2017-05-10T19:38:39Z</published> - <updated>2017-05-10T19:38:39Z</updated> - <title>New status by Skruyb</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="ru"><p><span class="h-card"><a href="https://mastodon.social/@applecandy" class="u-url mention">@<span>applecandy</span></a></span></p><p>Lucky you!!!</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.social/users/applecandy"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mamot.fr/users/Skruyb/updates/176608"/> - <link rel="self" type="application/atom+xml" href="https://mamot.fr/users/Skruyb/updates/176608.atom"/> - <thr:in-reply-to ref="tag:mastodon.social,2017-05-10:objectId=5578123:objectType=Status" href="https://mastodon.social/users/applecandy/updates/2317372"/> - </entry> - <entry> - <id>tag:mamot.fr,2017-05-10:objectId=1298431:objectType=Status</id> - <published>2017-05-10T19:26:32Z</published> - <updated>2017-05-10T19:26:32Z</updated> - <title>New status by Skruyb</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="fr"><p>Est-ce que je suis le seul qui lorsqu&apos;il commence à compter les arbres sur le bord de la route n&apos;arrive pas à s&apos;arrêter de compter?</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mamot.fr/users/Skruyb/updates/176561"/> - <link rel="self" type="application/atom+xml" href="https://mamot.fr/users/Skruyb/updates/176561.atom"/> - </entry> - <entry> - <id>tag:mamot.fr,2017-05-10:objectId=1298224:objectType=Status</id> - <published>2017-05-10T19:18:17Z</published> - <updated>2017-05-10T19:18:17Z</updated> - <title>New status by Skruyb</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="fr"><p>Ca y est j&apos;ai une nouvelle passion. Mettre les bouchons qui trainent par terre dans le bons sens avec mon pied 🙌</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mamot.fr/users/Skruyb/updates/176536"/> - <link rel="self" type="application/atom+xml" href="https://mamot.fr/users/Skruyb/updates/176536.atom"/> - </entry> - <entry> - <id>tag:mamot.fr,2017-05-10:objectId=1297450:objectType=Status</id> - <published>2017-05-10T18:53:37Z</published> - <updated>2017-05-10T18:53:37Z</updated> - <title>New status by Skruyb</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="fr"><p>Ok. On est capable d&apos;envoyer des mecs dans l&apos;espace, avoir des voitures autonomes, des trucs intelligents de partout mais pas tous les bâtiments accessibles aux personnes à mobilité réduite, les émissions sur le services publics avec une personne faisant la traduction pour les sourds et malentendants de manière systématique...</p><p>J&apos;ai du louper un truc dans l&apos;ordre des priorités Oo</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mamot.fr/users/Skruyb/updates/176412"/> - <link rel="self" type="application/atom+xml" href="https://mamot.fr/users/Skruyb/updates/176412.atom"/> - </entry> - <entry> - <id>tag:mamot.fr,2017-05-10:objectId=1297292:objectType=Status</id> - <published>2017-05-10T18:48:17Z</published> - <updated>2017-05-10T18:48:17Z</updated> - <title>New status by Skruyb</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="fr"><p>J&apos;ai comme envie de faire un truc mais je ne sais pas quoi mais pourtant c&apos;est comme si je ressentais l&apos;idée dans ma tête mais c&apos;est pas clair...</p><p>Fuck!!! J&apos;vais aller draguer Josiane à la compta ça va me changer les idées!!!</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mamot.fr/users/Skruyb/updates/176387"/> - <link rel="self" type="application/atom+xml" href="https://mamot.fr/users/Skruyb/updates/176387.atom"/> - </entry> - <entry> - <id>tag:mamot.fr,2017-05-10:objectId=1296598:objectType=Status</id> - <published>2017-05-10T18:25:11Z</published> - <updated>2017-05-10T18:25:11Z</updated> - <title>New status by Skruyb</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="fr"><p><span class="h-card"><a href="https://mamot.fr/@Smeablog" class="u-url mention">@<span>Smeablog</span></a></span></p><p>Pas faux MDR!!!!</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mamot.fr/users/Smeablog"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mamot.fr/users/Skruyb/updates/176320"/> - <link rel="self" type="application/atom+xml" href="https://mamot.fr/users/Skruyb/updates/176320.atom"/> - <thr:in-reply-to ref="tag:mamot.fr,2017-05-10:objectId=1296591:objectType=Status" href="https://mamot.fr/@Smeablog/1296591"/> - </entry> - <entry> - <id>tag:mamot.fr,2017-05-10:objectId=1296571:objectType=Status</id> - <published>2017-05-10T18:24:13Z</published> - <updated>2017-05-10T18:24:13Z</updated> - <title>New status by Skruyb</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="fr"><p><span class="h-card"><a href="https://mamot.fr/@Smeablog" class="u-url mention">@<span>Smeablog</span></a></span></p><p>Ca ne change pas la finalité malheureusement, ça ne m&apos;ouvre pas ce à quoi je veux accéder 😭</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mamot.fr/users/Smeablog"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mamot.fr/users/Skruyb/updates/176315"/> - <link rel="self" type="application/atom+xml" href="https://mamot.fr/users/Skruyb/updates/176315.atom"/> - <thr:in-reply-to ref="tag:mamot.fr,2017-05-10:objectId=1296531:objectType=Status" href="https://mamot.fr/@Smeablog/1296531"/> - </entry> - <entry> - <id>tag:mamot.fr,2017-05-10:objectId=1296475:objectType=Status</id> - <published>2017-05-10T18:20:50Z</published> - <updated>2017-05-10T18:20:50Z</updated> - <title>New status by Skruyb</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="fr"><p>Arrrgghhhhhhh!!!!</p><p>Quand t&apos;es sur le point de cliquer sur un lien dans le fil public global et que BOOM ça se met à jour... J&apos;ose même pas imaginer combien j&apos;ai ouvert de pages web sans le vouloir!!!</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mamot.fr/users/Skruyb/updates/176298"/> - <link rel="self" type="application/atom+xml" href="https://mamot.fr/users/Skruyb/updates/176298.atom"/> - </entry> - <entry> - <id>tag:mamot.fr,2017-05-10:objectId=1296426:objectType=Status</id> - <published>2017-05-10T18:19:17Z</published> - <updated>2017-05-10T18:19:17Z</updated> - <title>Skruyb shared a status by Isaluini@mastodon.social</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb> - <activity:object> - <id>tag:mastodon.social,2017-05-10:objectId=5587049:objectType=Status</id> - <published>2017-05-10T18:18:59Z</published> - <updated>2017-05-10T18:19:00Z</updated> - <title>New status by Isaluini@mastodon.social</title> - <author> - <id>https://mastodon.social/users/Isaluini</id> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://mastodon.social/users/Isaluini</uri> - <name>Isaluini</name> - <email>Isaluini@mastodon.social</email> - <summary type="html"><p>Adicciones: Escribir, diseñar, cine, café, humor negro, música y dibujar. | Jedi. Bueno, no. Algún día (?) | Gratitude.</p></summary> - <link rel="alternate" type="text/html" href="https://mastodon.social/@Isaluini"/> - <link rel="avatar" type="image/jpeg" media:width="120" media:height="120" href="https://mamot.fr/system/accounts/avatars/000/027/466/original/6c4659e795647240.jpg?1493580262"/> - <link rel="header" type="image/jpeg" media:width="700" media:height="335" href="https://mamot.fr/system/accounts/headers/000/027/466/original/608989b32a3efe1b.jpg?1493580262"/> - <poco:preferredUsername>Isaluini</poco:preferredUsername> - <poco:displayName>Isa</poco:displayName> - <poco:note>Adicciones: Escribir, diseñar, cine, café, humor negro, música y dibujar. | Jedi. Bueno, no. Algún día (?) | Gratitude.</poco:note> - <mastodon:scope>public</mastodon:scope> - </author> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="ru"><p>♫ <br><a href="https://www.youtube.com/watch?v=pT68FS3YbQ4"><span class="invisible">https://www.</span><span class="ellipsis">youtube.com/watch?v=pT68FS3YbQ</span><span class="invisible">4</span></a></p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/users/Isaluini/updates/2318469"/> - </activity:object> - <content type="html" xml:lang="en"><p>♫ <br><a href="https://www.youtube.com/watch?v=pT68FS3YbQ4"><span class="invisible">https://www.</span><span class="ellipsis">youtube.com/watch?v=pT68FS3YbQ</span><span class="invisible">4</span></a></p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mamot.fr/users/Skruyb/updates/176292"/> - <link rel="self" type="application/atom+xml" href="https://mamot.fr/users/Skruyb/updates/176292.atom"/> - </entry> - <entry> - <id>tag:mamot.fr,2017-05-10:objectId=1295893:objectType=Status</id> - <published>2017-05-10T18:01:51Z</published> - <updated>2017-05-10T18:01:51Z</updated> - <title>New status by Skruyb</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="fr"><p><span class="h-card"><a href="https://mamot.fr/@Chat2Gouttieres" class="u-url mention">@<span>Chat2Gouttieres</span></a></span></p><p>Ah bah après faut savoir mettre à profit ce savoir ^^</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mamot.fr/users/Chat2Gouttieres"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mamot.fr/users/Skruyb/updates/176203"/> - <link rel="self" type="application/atom+xml" href="https://mamot.fr/users/Skruyb/updates/176203.atom"/> - <thr:in-reply-to ref="tag:mamot.fr,2017-05-10:objectId=1295869:objectType=Status" href="https://mamot.fr/@Chat2Gouttieres/1295869"/> - </entry> - <entry> - <id>tag:mamot.fr,2017-05-10:objectId=1295815:objectType=Status</id> - <published>2017-05-10T18:00:02Z</published> - <updated>2017-05-10T18:00:02Z</updated> - <title>New status by Skruyb</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="fr"><p><span class="h-card"><a href="https://mamot.fr/@Chat2Gouttieres" class="u-url mention">@<span>Chat2Gouttieres</span></a></span></p><p>Exactement. On a les jeux mais pas le pain encore.</p><p>Finalement on a rien inventé :-p</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mamot.fr/users/Chat2Gouttieres"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mamot.fr/users/Skruyb/updates/176182"/> - <link rel="self" type="application/atom+xml" href="https://mamot.fr/users/Skruyb/updates/176182.atom"/> - <thr:in-reply-to ref="tag:mamot.fr,2017-05-10:objectId=1295800:objectType=Status" href="https://mamot.fr/@Chat2Gouttieres/1295800"/> - </entry> - <entry> - <id>tag:mamot.fr,2017-05-10:objectId=1295778:objectType=Status</id> - <published>2017-05-10T17:58:52Z</published> - <updated>2017-05-10T17:58:52Z</updated> - <title>New status by Skruyb</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="fr"><p><span class="h-card"><a href="https://mamot.fr/@Chat2Gouttieres" class="u-url mention">@<span>Chat2Gouttieres</span></a></span></p><p>C&apos;est ça visiblement dans notre société dite moderne... &quot;Créer l&apos;illusion que&quot; Oo.</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mamot.fr/users/Chat2Gouttieres"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mamot.fr/users/Skruyb/updates/176174"/> - <link rel="self" type="application/atom+xml" href="https://mamot.fr/users/Skruyb/updates/176174.atom"/> - <thr:in-reply-to ref="tag:mamot.fr,2017-05-10:objectId=1295765:objectType=Status" href="https://mamot.fr/@Chat2Gouttieres/1295765"/> - </entry> - <entry> - <id>tag:mamot.fr,2017-05-10:objectId=1294943:objectType=Status</id> - <published>2017-05-10T17:31:44Z</published> - <updated>2017-05-10T17:31:44Z</updated> - <title>New status by Skruyb</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <summary xml:lang="it">Hey.</summary> - <content type="html" xml:lang="it"><p><span class="h-card"><a href="https://mastodon.social/@lambadalambda" class="u-url mention">@<span>lambadalambda</span></a></span></p><p>Hey!!!</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.social/users/lambadalambda"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mamot.fr/users/Skruyb/updates/176041"/> - <link rel="self" type="application/atom+xml" href="https://mamot.fr/users/Skruyb/updates/176041.atom"/> - <thr:in-reply-to ref="tag:mastodon.social,2017-05-10:objectId=5582979:objectType=Status" href="https://mastodon.social/users/lambadalambda/updates/2317991"/> - </entry> - <entry> - <id>tag:mamot.fr,2017-05-10:objectId=1294914:objectType=Status</id> - <published>2017-05-10T17:30:40Z</published> - <updated>2017-05-10T17:30:40Z</updated> - <title>New status by Skruyb</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="fr"><p><span class="h-card"><a href="https://mamot.fr/@EloClemTiti" class="u-url mention">@<span>EloClemTiti</span></a></span></p><p>J&apos;ai souvent cette impression en effet 😂</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mamot.fr/users/EloClemTiti"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mamot.fr/users/Skruyb/updates/176034"/> - <link rel="self" type="application/atom+xml" href="https://mamot.fr/users/Skruyb/updates/176034.atom"/> - <thr:in-reply-to ref="tag:mamot.fr,2017-05-10:objectId=1294608:objectType=Status" href="https://mamot.fr/@EloClemTiti/1294608"/> - </entry> - <entry> - <id>tag:mamot.fr,2017-05-10:objectId=1294148:objectType=Status</id> - <published>2017-05-10T17:02:01Z</published> - <updated>2017-05-10T17:02:01Z</updated> - <title>New status by Skruyb</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="fr"><p>Les gars, les boss veulent voir de l&apos;avancement!! Une idée?</p><p>On fait comme d&apos;habitude. On divise nos tâches en 25.000 tâches unitaires, on fout du vert au maximum et on crée l&apos;illusion que ça a bien avancé!</p><p>Deal!!</p><p>Bob, tu choisis quel vert on utilise<br />Alice, t&apos;es en charge de la typo<br />Moi, je m&apos;occupe qu&apos;on prend bien le dernier template ppt fournit par la comm interne.</p><p>Des winners qu&apos;on est!!!! Des WI-NNERS!!!</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mamot.fr/users/Skruyb/updates/175898"/> - <link rel="self" type="application/atom+xml" href="https://mamot.fr/users/Skruyb/updates/175898.atom"/> - </entry> - <entry> - <id>tag:mamot.fr,2017-05-10:objectId=1293995:objectType=Status</id> - <published>2017-05-10T16:57:53Z</published> - <updated>2017-05-10T16:57:53Z</updated> - <title>New status by Skruyb</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="ru"><p><span class="h-card"><a href="https://mastodon.social/@SauceHair" class="u-url mention">@<span>SauceHair</span></a></span></p><p>Cool!!</p><p>Bon courage.</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.social/users/SauceHair"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mamot.fr/users/Skruyb/updates/175878"/> - <link rel="self" type="application/atom+xml" href="https://mamot.fr/users/Skruyb/updates/175878.atom"/> - <thr:in-reply-to ref="tag:mastodon.social,2017-05-10:objectId=5579955:objectType=Status" href="https://mastodon.social/users/SauceHair/updates/2317615"/> - </entry> -</feed> diff --git a/test/fixtures/tesla_mock/https___mastodon.social_users_lambadalambda.atom b/test/fixtures/tesla_mock/https___mastodon.social_users_lambadalambda.atom deleted file mode 100644 index 4d732b109..000000000 --- a/test/fixtures/tesla_mock/https___mastodon.social_users_lambadalambda.atom +++ /dev/null @@ -1,464 +0,0 @@ -<?xml version="1.0"?> -<feed xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:media="http://purl.org/syndication/atommedia" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:mastodon="http://mastodon.social/schema/1.0"> - <id>https://mastodon.social/users/lambadalambda.atom</id> - <title>Critical Value</title> - <subtitle></subtitle> - <updated>2017-04-16T21:47:25Z</updated> - <logo>https://files.mastodon.social/accounts/avatars/000/000/264/original/1429214160519.gif</logo> - <author> - <id>https://mastodon.social/users/lambadalambda</id> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://mastodon.social/users/lambadalambda</uri> - <name>lambadalambda</name> - <email>lambadalambda@mastodon.social</email> - <link rel="alternate" type="text/html" href="https://mastodon.social/@lambadalambda"/> - <link rel="avatar" type="image/gif" media:width="120" media:height="120" href="https://files.mastodon.social/accounts/avatars/000/000/264/original/1429214160519.gif"/> - <link rel="header" type="" media:width="700" media:height="335" href="/headers/original/missing.png"/> - <poco:preferredUsername>lambadalambda</poco:preferredUsername> - <poco:displayName>Critical Value</poco:displayName> - <mastodon:scope>public</mastodon:scope> - </author> - <link rel="alternate" type="text/html" href="https://mastodon.social/@lambadalambda"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda.atom"/> - <link rel="next" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda.atom?max_id=1616358"/> - <link rel="hub" href="https://mastodon.social/api/push"/> - <link rel="salmon" href="https://mastodon.social/api/salmon/264"/> - <entry> - <id>tag:mastodon.social,2017-05-04:objectId=4991300:objectType=Status</id> - <published>2017-05-04T14:10:30Z</published> - <updated>2017-05-04T14:10:30Z</updated> - <title>Delete</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/delete</activity:verb> - <link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/2247090"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/2247090.atom"/> - </entry> - <entry> - <id>tag:mastodon.social,2017-05-04:objectId=4980289:objectType=Status</id> - <published>2017-05-04T07:43:23Z</published> - <updated>2017-05-04T07:43:23Z</updated> - <title>Delete</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/delete</activity:verb> - <link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/2244602"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/2244602.atom"/> - </entry> - <entry> - <id>tag:mastodon.social,2017-05-03:objectId=4952899:objectType=Status</id> - <published>2017-05-03T17:26:43Z</published> - <updated>2017-05-03T17:26:43Z</updated> - <title>New status by lambadalambda</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="en"><p><span class="h-card"><a href="https://pleroma.soykaf.com/users/lain" class="u-url mention">@<span>lain</span></a></span> OK!!</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://pleroma.soykaf.com/users/lain"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/2237124"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/2237124.atom"/> - <thr:in-reply-to ref="https://pleroma.soykaf.com/objects/5e755d92-f0ee-432f-8c17-590962aea59c" href=""/> - </entry> - <entry> - <id>tag:mastodon.social,2017-05-03:objectId=4952810:objectType=Status</id> - <published>2017-05-03T17:24:34Z</published> - <updated>2017-05-03T17:24:34Z</updated> - <title>New status by lambadalambda</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="el"><p><span class="h-card"><a href="https://pleroma.soykaf.com/users/lain" class="u-url mention">@<span>lain</span></a></span> yeah :)</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://pleroma.soykaf.com/users/lain"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/2237089"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/2237089.atom"/> - <thr:in-reply-to ref="https://pleroma.soykaf.com/objects/32ff0743-236a-41e5-81c5-a3211088e741" href=""/> - </entry> - <entry> - <id>tag:mastodon.social,2017-05-03:objectId=4950388:objectType=Status</id> - <published>2017-05-03T16:22:00Z</published> - <updated>2017-05-03T16:22:00Z</updated> - <title>lambadalambda shared a status by lambadalambda@social.heldscal.la</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb> - <activity:object> - <id>tag:social.heldscal.la,2017-05-03:noticeId=2030733:objectType=note</id> - <published>2017-05-03T12:29:20Z</published> - <updated>2017-05-03T12:29:31Z</updated> - <title>New status by lambadalambda@social.heldscal.la</title> - <author> - <id>https://social.heldscal.la/user/23211</id> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://social.heldscal.la/user/23211</uri> - <name>lambadalambda</name> - <email>lambadalambda@social.heldscal.la</email> - <summary type="html">Call me Deacon Blues.</summary> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/lambadalambda"/> - <link rel="avatar" type="image/jpeg" media:width="120" media:height="120" href="https://files.mastodon.social/accounts/avatars/000/000/236/original/23211-original-20170416114255.jpeg"/> - <link rel="header" type="" media:width="700" media:height="335" href="/headers/original/missing.png"/> - <poco:preferredUsername>lambadalambda</poco:preferredUsername> - <poco:displayName>Constance Variable</poco:displayName> - <poco:note>Call me Deacon Blues.</poco:note> - <mastodon:scope>public</mastodon:scope> - </author> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="en">Time for work. <a href="https://social.heldscal.la/file/953c117a1e7e4c763755d2ac29cf1aae08e025599f4a4cc11ddff4082c07f969.jpg">https://social.heldscal.la/attachment/120552</a></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="enclosure" type="image/jpeg" length="383072" href="https://files.mastodon.social/media_attachments/files/000/391/513/original/953c117a1e7e4c763755d2ac29cf1aae08e025599f4a4cc11ddff4082c07f969.jpg"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2030733"/> - </activity:object> - <content type="html" xml:lang="en">Time for work. <a href="https://social.heldscal.la/file/953c117a1e7e4c763755d2ac29cf1aae08e025599f4a4cc11ddff4082c07f969.jpg">https://social.heldscal.la/attachment/120552</a></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/2236405"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/2236405.atom"/> - </entry> - <entry> - <id>tag:mastodon.social,2017-05-03:objectId=4934452:objectType=Status</id> - <published>2017-05-03T08:21:09Z</published> - <updated>2017-05-03T08:21:09Z</updated> - <title>lambadalambda shared a status by lain@pleroma.soykaf.com</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb> - <activity:object> - <id>https://pleroma.soykaf.com/objects/4c1bda26-902e-4525-9fcd-b9fd44925193</id> - <published>2017-05-03T08:04:44Z</published> - <updated>2017-05-03T08:05:52Z</updated> - <title>New status by lain@pleroma.soykaf.com</title> - <author> - <id>https://pleroma.soykaf.com/users/lain</id> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://pleroma.soykaf.com/users/lain</uri> - <name>lain</name> - <email>lain@pleroma.soykaf.com</email> - <summary type="html">Test account</summary> - <link rel="alternate" type="text/html" href="https://pleroma.soykaf.com/users/lain"/> - <link rel="avatar" type="image/jpeg" media:width="120" media:height="120" href="https://files.mastodon.social/accounts/avatars/000/125/902/original/6B3AFC74ACA841B24CFB94DB9044C84EDE6AFF31C71718B023D413DAED09A68E.jpeg"/> - <link rel="header" type="" media:width="700" media:height="335" href="/headers/original/missing.png"/> - <poco:preferredUsername>lain</poco:preferredUsername> - <poco:displayName>Lain Iwakura</poco:displayName> - <poco:note>Test account</poco:note> - <mastodon:scope>public</mastodon:scope> - </author> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="en">Added returning the entries as xml... let's see if the mastodon hammering stops now.</content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href=""/> - </activity:object> - <content type="html" xml:lang="en">Added returning the entries as xml... let's see if the mastodon hammering stops now.</content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/2232660"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/2232660.atom"/> - </entry> - <entry> - <id>tag:mastodon.social,2017-05-02:objectId=4905499:objectType=Status</id> - <published>2017-05-02T19:34:21Z</published> - <updated>2017-05-02T19:34:21Z</updated> - <title>New status by lambadalambda</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="ru"><p><span class="h-card"><a href="https://pleroma.soykaf.com/users/lain" class="u-url mention">@<span>lain</span></a></span> yay!</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://pleroma.soykaf.com/users/lain"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/2226006"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/2226006.atom"/> - <thr:in-reply-to ref="https://pleroma.soykaf.com/objects/b79fa9cd-1d27-448a-844f-79f306bc75c9" href=""/> - </entry> - <entry> - <id>tag:mastodon.social,2017-05-02:objectId=4905442:objectType=Status</id> - <published>2017-05-02T19:33:33Z</published> - <updated>2017-05-02T19:33:33Z</updated> - <title>New status by lambadalambda</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="fa"><p><span class="h-card"><a href="https://pleroma.soykaf.com/users/lain" class="u-url mention">@<span>lain</span></a></span> so?</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://pleroma.soykaf.com/users/lain"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/2225992"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/2225992.atom"/> - <thr:in-reply-to ref="https://pleroma.soykaf.com/objects/233a878a-974e-4e75-b1c8-aa7657f561fc" href=""/> - </entry> - <entry> - <id>tag:mastodon.social,2017-05-02:objectId=4901603:objectType=Status</id> - <published>2017-05-02T18:33:06Z</published> - <updated>2017-05-02T18:33:06Z</updated> - <title>New status by lambadalambda</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="el"><p><span class="h-card"><a href="https://pleroma.soykaf.com/users/lain" class="u-url mention">@<span>lain</span></a></span> hey</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://pleroma.soykaf.com/users/lain"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/2224923"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/2224923.atom"/> - <thr:in-reply-to ref="https://pleroma.soykaf.com/objects/c237d966-ac75-4fe3-a87a-d89d71a3a7a4" href=""/> - </entry> - <entry> - <id>tag:mastodon.social,2017-05-01:objectId=4836720:objectType=Status</id> - <published>2017-05-01T18:52:16Z</published> - <updated>2017-05-01T18:52:16Z</updated> - <title>lambadalambda shared a status by lain@pleroma.soykaf.com</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb> - <activity:object> - <id>https://pleroma.soykaf.com/objects/7b41bb51-9aba-436a-82d9-dd3f5aca98c9</id> - <published>2017-05-01T18:50:54Z</published> - <updated>2017-05-01T18:50:57Z</updated> - <title>New status by lain@pleroma.soykaf.com</title> - <author> - <id>https://pleroma.soykaf.com/users/lain</id> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://pleroma.soykaf.com/users/lain</uri> - <name>lain</name> - <email>lain@pleroma.soykaf.com</email> - <summary type="html">Test account</summary> - <link rel="alternate" type="text/html" href="https://pleroma.soykaf.com/users/lain"/> - <link rel="avatar" type="image/jpeg" media:width="120" media:height="120" href="https://files.mastodon.social/accounts/avatars/000/125/902/original/6B3AFC74ACA841B24CFB94DB9044C84EDE6AFF31C71718B023D413DAED09A68E.jpeg"/> - <link rel="header" type="" media:width="700" media:height="335" href="/headers/original/missing.png"/> - <poco:preferredUsername>lain</poco:preferredUsername> - <poco:displayName>Lain Iwakura</poco:displayName> - <poco:note>Test account</poco:note> - <mastodon:scope>public</mastodon:scope> - </author> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="en"><a href="https://mastodon.social/users/lambadalambda">@lambadalambda@mastodon.social</a> you're an all-star.</content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.social/users/lambadalambda"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href=""/> - <thr:in-reply-to ref="tag:mastodon.social,2017-05-01:objectId=4836142:objectType=Status" href="https://mastodon.social/@lambadalambda/4836142"/> - </activity:object> - <content type="html" xml:lang="en"><a href="https://mastodon.social/users/lambadalambda">@lambadalambda@mastodon.social</a> you're an all-star.</content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/2211632"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/2211632.atom"/> - </entry> - <entry> - <id>tag:mastodon.social,2017-05-01:objectId=4836142:objectType=Status</id> - <published>2017-05-01T18:38:47Z</published> - <updated>2017-05-01T18:38:47Z</updated> - <title>New status by lambadalambda</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="ru"><p><span class="h-card"><a href="https://pleroma.soykaf.com/users/lain" class="u-url mention">@<span>lain</span></a></span> Hey now!</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://pleroma.soykaf.com/users/lain"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/2211518"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/2211518.atom"/> - <thr:in-reply-to ref="https://pleroma.soykaf.com/objects/ffae4bea-00a3-4cef-8076-4ee4d448cb46" href=""/> - </entry> - <entry> - <id>tag:mastodon.social,2017-05-01:objectId=4836055:objectType=Status</id> - <published>2017-05-01T18:37:04Z</published> - <updated>2017-05-01T18:37:04Z</updated> - <title>New status by lambadalambda</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="el"><p><span class="h-card"><a href="https://pleroma.soykaf.com/users/lain" class="u-url mention">@<span>lain</span></a></span> hello</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://pleroma.soykaf.com/users/lain"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/2211496"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/2211496.atom"/> - <thr:in-reply-to ref="https://pleroma.soykaf.com/objects/ffae4bea-00a3-4cef-8076-4ee4d448cb46" href=""/> - </entry> - <entry> - <id>tag:mastodon.social,2017-05-01:objectId=4834850:objectType=Status</id> - <published>2017-05-01T18:10:43Z</published> - <updated>2017-05-01T18:10:43Z</updated> - <title>New status by lambadalambda</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="el"><p><span class="h-card"><a href="https://pleroma.soykaf.com/users/lain" class="u-url mention">@<span>lain</span></a></span> Hey!</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://pleroma.soykaf.com/users/lain"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/2211256"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/2211256.atom"/> - </entry> - <entry> - <id>tag:mastodon.social,2017-04-29:objectId=4694455:objectType=Status</id> - <published>2017-04-29T18:39:12Z</published> - <updated>2017-04-29T18:39:12Z</updated> - <title>New status by lambadalambda</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="ru"><p>@lain@pleroma.soykaf.com What&apos;s up?</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/2189604"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/2189604.atom"/> - </entry> - <entry> - <id>tag:mastodon.social,2017-04-29:objectId=4694384:objectType=Status</id> - <published>2017-04-29T18:37:32Z</published> - <updated>2017-04-29T18:37:32Z</updated> - <title>New status by lambadalambda</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="fr"><p><span class="h-card"><a href="https://social.heldscal.la/lain" class="u-url mention">@<span>lain</span></a></span> Hey.</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://social.heldscal.la/user/37181"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/2189588"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/2189588.atom"/> - </entry> - <entry> - <id>tag:mastodon.social,2017-04-07:objectId=1874242:objectType=Status</id> - <published>2017-04-07T11:02:56Z</published> - <updated>2017-04-07T11:02:56Z</updated> - <title>lambadalambda shared a status by 0xroy@social.wxcafe.net</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb> - <activity:object> - <id>tag:social.wxcafe.net,2017-04-07:objectId=72554:objectType=Status</id> - <published>2017-04-07T11:01:59Z</published> - <updated>2017-04-07T11:02:00Z</updated> - <title>New status by 0xroy@social.wxcafe.net</title> - <author> - <id>https://social.wxcafe.net/users/0xroy</id> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://social.wxcafe.net/users/0xroy</uri> - <name>0xroy</name> - <email>0xroy@social.wxcafe.net</email> - <summary type="html">ta caution weeb | discussions privées : <a href="https://%F0%9F%92%8C.0xroy.me"><span class="invisible">https://</span><span class="">💌.0xroy.me</span><span class="invisible"></span></a></summary> - <link rel="alternate" type="text/html" href="https://social.wxcafe.net/@0xroy"/> - <link rel="avatar" type="image/jpeg" media:width="120" media:height="120" href="https://files.mastodon.social/accounts/avatars/000/036/953/original/20068e41d0310172.jpg"/> - <link rel="header" type="image/jpeg" media:width="700" media:height="335" href="https://files.mastodon.social/accounts/headers/000/036/953/original/2229d0e3f129fe8c.jpg"/> - <poco:preferredUsername>0xroy</poco:preferredUsername> - <poco:displayName>「R O Y 🍵 B O S」</poco:displayName> - <poco:note>ta caution weeb | discussions privées : https://💌.0xroy.me</poco:note> - <mastodon:scope>public</mastodon:scope> - </author> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="en"><p>someone pls eli5 matrix (protocol) and riot</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://social.wxcafe.net/users/0xroy/updates/4510"/> - </activity:object> - <content type="html" xml:lang="en"><p>someone pls eli5 matrix (protocol) and riot</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/1689208"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/1689208.atom"/> - </entry> - <entry> - <id>tag:mastodon.social,2017-04-06:objectId=1768247:objectType=Status</id> - <published>2017-04-06T11:10:19Z</published> - <updated>2017-04-06T11:10:19Z</updated> - <title>lambadalambda shared a status by areyoutoo@mastodon.xyz</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb> - <activity:object> - <id>tag:mastodon.xyz,2017-04-05:objectId=133327:objectType=Status</id> - <published>2017-04-05T17:36:41Z</published> - <updated>2017-04-05T18:12:14Z</updated> - <title>New status by areyoutoo@mastodon.xyz</title> - <author> - <id>https://mastodon.xyz/users/areyoutoo</id> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://mastodon.xyz/users/areyoutoo</uri> - <name>areyoutoo</name> - <email>areyoutoo@mastodon.xyz</email> - <summary type="html">devops | retired gamedev | always boost puppy pics</summary> - <link rel="alternate" type="text/html" href="https://mastodon.xyz/@areyoutoo"/> - <link rel="avatar" type="image/png" media:width="120" media:height="120" href="https://files.mastodon.social/accounts/avatars/000/047/888/original/5ce2e132d4c18d65.png"/> - <link rel="header" type="image/png" media:width="700" media:height="335" href="https://files.mastodon.social/accounts/headers/000/047/888/original/missing.png"/> - <poco:preferredUsername>areyoutoo</poco:preferredUsername> - <poco:displayName>Raw Butter</poco:displayName> - <poco:note>devops | retired gamedev | always boost puppy pics</poco:note> - <mastodon:scope>public</mastodon:scope> - </author> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="en"><p>Some UX thoughts for <a href="https://mastodon.xyz/tags/mastodev">#<span>mastodev</span></a>:</p><p>- Would be nice if I could work on multiple draft toots? Clicking to reply to someone seems to erase any draft I had been working on.</p><p>- Kinda risky to click on the Federated Timeline if it loads new toots and scrolls 10ms before I click on something.</p><p>I probably don't know enough web frontend to help, but it might be fun to try.</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <category term="mastodev"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.xyz/users/areyoutoo/updates/36028"/> - </activity:object> - <content type="html" xml:lang="en"><p>Some UX thoughts for <a href="https://mastodon.xyz/tags/mastodev">#<span>mastodev</span></a>:</p><p>- Would be nice if I could work on multiple draft toots? Clicking to reply to someone seems to erase any draft I had been working on.</p><p>- Kinda risky to click on the Federated Timeline if it loads new toots and scrolls 10ms before I click on something.</p><p>I probably don't know enough web frontend to help, but it might be fun to try.</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/1658950"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/1658950.atom"/> - </entry> - <entry> - <id>tag:mastodon.social,2017-04-06:objectId=1764509:objectType=Status</id> - <published>2017-04-06T10:15:38Z</published> - <updated>2017-04-06T10:15:38Z</updated> - <title>New status by lambadalambda</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <summary xml:lang="en">This is a test for cw federation</summary> - <content type="html" xml:lang="en"><p>This is a test for cw federation body text.</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/1657819"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/1657819.atom"/> - </entry> - <entry> - <id>tag:mastodon.social,2017-04-05:objectId=1645208:objectType=Status</id> - <published>2017-04-05T07:14:53Z</published> - <updated>2017-04-05T07:14:53Z</updated> - <title>lambadalambda shared a status by lambadalambda@social.heldscal.la</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb> - <activity:object> - <id>tag:social.heldscal.la,2017-04-05:noticeId=1502088:objectType=note</id> - <published>2017-04-05T06:12:09Z</published> - <updated>2017-04-05T07:12:47Z</updated> - <title>New status by lambadalambda@social.heldscal.la</title> - <author> - <id>https://social.heldscal.la/user/23211</id> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://social.heldscal.la/user/23211</uri> - <name>lambadalambda</name> - <email>lambadalambda@social.heldscal.la</email> - <summary type="html">Call me Deacon Blues.</summary> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/lambadalambda"/> - <link rel="avatar" type="image/jpeg" media:width="120" media:height="120" href="https://files.mastodon.social/accounts/avatars/000/000/236/original/23211-original-20170416114255.jpeg"/> - <link rel="header" type="" media:width="700" media:height="335" href="/headers/original/missing.png"/> - <poco:preferredUsername>lambadalambda</poco:preferredUsername> - <poco:displayName>Constance Variable</poco:displayName> - <poco:note>Call me Deacon Blues.</poco:note> - <mastodon:scope>public</mastodon:scope> - </author> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="en">Federation 101: <a href="https://www.youtube.com/watch?v=t1lYU5CA40o">https://www.youtube.com/watch?v=t1lYU5CA40o</a></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/1502088"/> - </activity:object> - <content type="html" xml:lang="en">Federation 101: <a href="https://www.youtube.com/watch?v=t1lYU5CA40o">https://www.youtube.com/watch?v=t1lYU5CA40o</a></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/1618003"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/1618003.atom"/> - </entry> - <entry> - <id>tag:mastodon.social,2017-04-05:objectId=1641750:objectType=Status</id> - <published>2017-04-05T05:44:48Z</published> - <updated>2017-04-05T05:44:48Z</updated> - <title>New status by lambadalambda</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="en"><p><span class="h-card"><a href="https://social.heldscal.la/lambadalambda" class="u-url mention">@<span>lambadalambda</span></a></span> just a test.</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://social.heldscal.la/user/23211"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/1616358"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/1616358.atom"/> - </entry> -</feed> diff --git a/test/fixtures/tesla_mock/https___osada.macgirvin.com_channel_mike.json b/test/fixtures/tesla_mock/https___osada.macgirvin.com_channel_mike.json index c42f3a53c..ca76d6e17 100644 --- a/test/fixtures/tesla_mock/https___osada.macgirvin.com_channel_mike.json +++ b/test/fixtures/tesla_mock/https___osada.macgirvin.com_channel_mike.json @@ -8,6 +8,7 @@ "preferredUsername": "mike", "name": "Mike Macgirvin (Osada)", "updated": "2018-08-29T03:09:11Z", + "discoverable": "true", "icon": { "type": "Image", "mediaType": "image/jpeg", @@ -51,4 +52,4 @@ "created": "2018-10-17T07:16:28Z", "signatureValue": "WbfFVIPImkd3yNu6brz0CvZaeV242rwAbH0vy8DM4vfnXCxLr5Uv/Wj9gwP+tbooTxGaahAKBeqlGkQp8RLEo37LATrKMRLA/0V6DeeV+C5ORWR9B4WxyWiD3s/9Wf+KesFMtktNLAcMZ5PfnOS/xNYerhnpkp/gWPxtkglmLIWJv+w18A5zZ01JCxsO4QljHbhYaEUPHUfQ97abrkLECeam+FThVwdO6BFCtbjoNXHfzjpSZL/oKyBpi5/fpnqMqOLOQPs5WgBBZJvjEYYkQcoPTyxYI5NGpNbzIjGHPQNuACnOelH16A7L+q4swLWDIaEFeXQ2/5bmqVKZDZZ6usNP4QyTVszwd8jqo27qcDTNibXDUTsTdKpNQvM/3UncBuzuzmUV3FczhtGshIU1/pRVZiQycpVqPlGLvXhP/yZCe+1siyqDd+3uMaS2vkHTObSl5r+VYof+c+TcjrZXHSWnQTg8/X3zkoBWosrQ93VZcwjzMxQoARYv6rphbOoTz7RPmGAXYUt3/PDWkqDlmQDwCpLNNkJo1EidyefZBdD9HXQpCBO0ZU0NHb0JmPvg/+zU0krxlv70bm3RHA/maBETVjroIWzt7EwQEg5pL2hVnvSBG+1wF3BtRVe77etkPOHxLnYYIcAMLlVKCcgDd89DPIziQyruvkx1busHI08=" } -} +}
\ No newline at end of file diff --git a/test/fixtures/tesla_mock/https___pawoo.net_users_pekorino.atom b/test/fixtures/tesla_mock/https___pawoo.net_users_pekorino.atom deleted file mode 100644 index 17d1956e8..000000000 --- a/test/fixtures/tesla_mock/https___pawoo.net_users_pekorino.atom +++ /dev/null @@ -1,231 +0,0 @@ -<?xml version="1.0"?> -<feed xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:media="http://purl.org/syndication/atommedia" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:mastodon="http://mastodon.social/schema/1.0"> - <id>https://pawoo.net/users/pekorino.atom</id> - <title>モノエ</title> - <subtitle>シアトル・米国
-
-GNUsocial 英語版
-http://shitposter.club/mono
-
-</subtitle> - <updated>2017-05-07T09:28:20Z</updated> - <logo>https://img.pawoo.net/accounts/avatars/000/128/378/original/e1fce04a36a1ad90.jpg</logo> - <author> - <id>https://pawoo.net/users/pekorino</id> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://pawoo.net/users/pekorino</uri> - <name>pekorino</name> - <email>pekorino@pawoo.net</email> - <summary type="html"><p>シアトル・米国</p><p>GNUsocial 英語版<br /><a href="http://shitposter.club/mono" rel="nofollow noopener" target="_blank"><span class="invisible">http://</span><span class="">shitposter.club/mono</span><span class="invisible"></span></a> </p></summary> - <link rel="alternate" type="text/html" href="https://pawoo.net/@pekorino"/> - <link rel="avatar" type="image/jpeg" media:width="120" media:height="120" href="https://img.pawoo.net/accounts/avatars/000/128/378/original/e1fce04a36a1ad90.jpg"/> - <link rel="header" type="image/png" media:width="700" media:height="335" href="https://img.pawoo.net/accounts/headers/000/128/378/original/bae3502120206e68.png"/> - <poco:preferredUsername>pekorino</poco:preferredUsername> - <poco:displayName>モノエ</poco:displayName> - <poco:note>シアトル・米国
-
-GNUsocial 英語版
-http://shitposter.club/mono
-
-</poco:note> - <mastodon:scope>public</mastodon:scope> - </author> - <link rel="alternate" type="text/html" href="https://pawoo.net/@pekorino"/> - <link rel="self" type="application/atom+xml" href="https://pawoo.net/users/pekorino.atom"/> - <link rel="hub" href="https://pawoo.net/api/push"/> - <link rel="salmon" href="https://pawoo.net/api/salmon/128378"/> - <entry> - <id>tag:pawoo.net,2017-05-07:objectId=9319211:objectType=Status</id> - <published>2017-05-07T09:56:35Z</published> - <updated>2017-05-07T09:56:35Z</updated> - <title>New status by pekorino</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="en"><p><span class="h-card"><a href="https://shitposter.club/moonman" class="u-url mention">@<span>moonman</span></a></span> <span class="h-card"><a href="https://shitposter.club/rw" class="u-url mention">@<span>rw</span></a></span> <span class="h-card"><a href="https://social.heldscal.la/lambadalambda" class="u-url mention">@<span>lambadalambda</span></a></span> <span class="h-card"><a href="https://shitposter.club/mono" class="u-url mention">@<span>mono</span></a></span> </p><p>i have to wait for someone to respond to this before i can follow because i dont think this software has a direct follow by url option</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://shitposter.club/user/9056"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://social.heldscal.la/user/23211"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://shitposter.club/user/666"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://shitposter.club/user/1"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://pawoo.net/users/pekorino/updates/2496950"/> - <link rel="self" type="application/atom+xml" href="https://pawoo.net/users/pekorino/updates/2496950.atom"/> - <thr:in-reply-to ref="tag:pawoo.net,2017-05-07:objectId=9318595:objectType=Status" href="https://pawoo.net/@pekorino/9318595"/> - </entry> - <entry> - <id>tag:pawoo.net,2017-05-07:objectId=9318595:objectType=Status</id> - <published>2017-05-07T09:54:39Z</published> - <updated>2017-05-07T09:54:39Z</updated> - <title>New status by pekorino</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="en"><p><span class="h-card"><a href="https://shitposter.club/mono" class="u-url mention">@<span>mono</span></a></span> <span class="h-card"><a href="https://social.heldscal.la/lambadalambda" class="u-url mention">@<span>lambadalambda</span></a></span> <span class="h-card"><a href="https://shitposter.club/rw" class="u-url mention">@<span>rw</span></a></span> <span class="h-card"><a href="https://shitposter.club/moonman" class="u-url mention">@<span>moonman</span></a></span> <br />please respond</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://shitposter.club/user/1"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://shitposter.club/user/666"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://social.heldscal.la/user/23211"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://shitposter.club/user/9056"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://pawoo.net/users/pekorino/updates/2496838"/> - <link rel="self" type="application/atom+xml" href="https://pawoo.net/users/pekorino/updates/2496838.atom"/> - <thr:in-reply-to ref="tag:shitposter.club,2017-05-07:noticeId=2856143:objectType=note" href="https://shitposter.club/notice/2856143"/> - </entry> - <entry> - <id>tag:pawoo.net,2017-05-07:objectId=9313978:objectType=Status</id> - <published>2017-05-07T09:39:17Z</published> - <updated>2017-05-07T09:39:17Z</updated> - <title>New status by pekorino</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="en"><p><span class="h-card"><a href="https://shitposter.club/moonman" class="u-url mention">@<span>moonman</span></a></span> <br />mastodon is so slow. browser crashed twice trying to set avatar</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://shitposter.club/user/1"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://pawoo.net/users/pekorino/updates/2496065"/> - <link rel="self" type="application/atom+xml" href="https://pawoo.net/users/pekorino/updates/2496065.atom"/> - </entry> - <entry> - <id>tag:pawoo.net,2017-05-07:objectId=9312691:objectType=Status</id> - <published>2017-05-07T09:34:38Z</published> - <updated>2017-05-07T09:34:38Z</updated> - <title>New status by pekorino</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="en"><p><span class="h-card"><a href="https://shitposter.club/hardbass2k8" class="u-url mention">@<span>hardbass2k8</span></a></span> <a href="https://pawoo.net/media/mZJjLpbPU72GFEz2Svk" rel="nofollow noopener" target="_blank"><span class="invisible">https://</span><span class="ellipsis">pawoo.net/media/mZJjLpbPU72GFE</span><span class="invisible">z2Svk</span></a></p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://shitposter.club/user/9591"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="enclosure" type="image/jpeg" length="42074" href="https://img.pawoo.net/media_attachments/files/000/681/737/original/483a0d76fce39156.jpg"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://pawoo.net/users/pekorino/updates/2495835"/> - <link rel="self" type="application/atom+xml" href="https://pawoo.net/users/pekorino/updates/2495835.atom"/> - <thr:in-reply-to ref="tag:shitposter.club,2017-05-07:noticeId=2855897:objectType=note" href="https://shitposter.club/notice/2855897"/> - </entry> - <entry> - <id>tag:pawoo.net,2017-05-07:objectId=9312379:objectType=Status</id> - <published>2017-05-07T09:33:29Z</published> - <updated>2017-05-07T09:33:29Z</updated> - <title>New status by pekorino</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="en"><p><span class="h-card"><a href="https://shitposter.club/hardbass2k8" class="u-url mention">@<span>hardbass2k8</span></a></span> <a href="https://pawoo.net/media/nt5JHBEHyTN2bqzdcGU" rel="nofollow noopener" target="_blank"><span class="invisible">https://</span><span class="ellipsis">pawoo.net/media/nt5JHBEHyTN2bq</span><span class="invisible">zdcGU</span></a></p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://shitposter.club/user/9591"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="enclosure" type="image/png" length="8605" href="https://img.pawoo.net/media_attachments/files/000/681/714/original/1e3f216d4f78c69d.png"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://pawoo.net/users/pekorino/updates/2495772"/> - <link rel="self" type="application/atom+xml" href="https://pawoo.net/users/pekorino/updates/2495772.atom"/> - <thr:in-reply-to ref="tag:shitposter.club,2017-05-07:noticeId=2855886:objectType=comment" href="https://shitposter.club/notice/2855886"/> - </entry> - <entry> - <id>tag:pawoo.net,2017-05-07:objectId=9311765:objectType=Status</id> - <published>2017-05-07T09:31:26Z</published> - <updated>2017-05-07T09:31:26Z</updated> - <title>New status by pekorino</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="en"><p><a href="https://pawoo.net/media/C4RV6ubsEtvS04DX6qs" rel="nofollow noopener" target="_blank"><span class="invisible">https://</span><span class="ellipsis">pawoo.net/media/C4RV6ubsEtvS04</span><span class="invisible">DX6qs</span></a></p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="enclosure" type="image/jpeg" length="71196" href="https://img.pawoo.net/media_attachments/files/000/681/667/original/dc310e8fd312e7ff.jpg"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://pawoo.net/users/pekorino/updates/2495666"/> - <link rel="self" type="application/atom+xml" href="https://pawoo.net/users/pekorino/updates/2495666.atom"/> - </entry> - <entry> - <id>tag:pawoo.net,2017-05-07:objectId=9311610:objectType=Status</id> - <published>2017-05-07T09:30:59Z</published> - <updated>2017-05-07T09:30:59Z</updated> - <title>New status by pekorino</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="en"><p><a href="https://pawoo.net/media/MBmkeEdrjs8pAtCHN6s" rel="nofollow noopener" target="_blank"><span class="invisible">https://</span><span class="ellipsis">pawoo.net/media/MBmkeEdrjs8pAt</span><span class="invisible">CHN6s</span></a></p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="enclosure" type="image/jpeg" length="158377" href="https://img.pawoo.net/media_attachments/files/000/681/656/original/7e2d78ecfd243e67.jpg"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://pawoo.net/users/pekorino/updates/2495632"/> - <link rel="self" type="application/atom+xml" href="https://pawoo.net/users/pekorino/updates/2495632.atom"/> - </entry> - <entry> - <id>tag:pawoo.net,2017-05-07:objectId=9307782:objectType=Status</id> - <published>2017-05-07T09:16:47Z</published> - <updated>2017-05-07T09:16:47Z</updated> - <title>New status by pekorino</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="en"><p><span class="h-card"><a href="https://shitposter.club/mono" class="u-url mention">@<span>mono</span></a></span></p><p>test</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://shitposter.club/user/9056"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://pawoo.net/users/pekorino/updates/2494966"/> - <link rel="self" type="application/atom+xml" href="https://pawoo.net/users/pekorino/updates/2494966.atom"/> - </entry> - <entry> - <id>tag:pawoo.net,2017-05-07:objectId=9307444:objectType=Status</id> - <published>2017-05-07T09:15:42Z</published> - <updated>2017-05-07T09:15:42Z</updated> - <title>New status by pekorino</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="en"><p><span class="h-card"><a href="https://shitposter.club/hardbass2k8" class="u-url mention">@<span>hardbass2k8</span></a></span> テスト</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://shitposter.club/user/9591"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://pawoo.net/users/pekorino/updates/2494900"/> - <link rel="self" type="application/atom+xml" href="https://pawoo.net/users/pekorino/updates/2494900.atom"/> - <thr:in-reply-to ref="tag:shitposter.club,2017-05-07:noticeId=2855867:objectType=note" href="https://shitposter.club/notice/2855867"/> - </entry> - <entry> - <id>tag:pawoo.net,2017-05-07:objectId=9307239:objectType=Status</id> - <published>2017-05-07T09:14:58Z</published> - <updated>2017-05-07T09:14:58Z</updated> - <title>New status by pekorino</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="en"><p>ててててててテスト</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://pawoo.net/users/pekorino/updates/2494866"/> - <link rel="self" type="application/atom+xml" href="https://pawoo.net/users/pekorino/updates/2494866.atom"/> - </entry> - <entry> - <id>tag:pawoo.net,2017-04-20:objectId=2212164:objectType=Status</id> - <published>2017-04-20T06:19:18Z</published> - <updated>2017-04-20T06:19:18Z</updated> - <title>New status by pekorino</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="en"><p><span class="h-card"><a href="https://shitposter.club/mono" class="u-url mention">@<span>mono</span></a></span> <a href="https://pawoo.net/media/iMbjMBVPfZJX3lUC2Sc" rel="nofollow noopener" target="_blank"><span class="invisible">https://</span><span class="ellipsis">pawoo.net/media/iMbjMBVPfZJX3l</span><span class="invisible">UC2Sc</span></a></p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://shitposter.club/user/9056"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="enclosure" type="image/png" length="754410" href="https://img.pawoo.net/media_attachments/files/000/199/926/original/f11a4c9c91403766.png"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://pawoo.net/users/pekorino/updates/874763"/> - <link rel="self" type="application/atom+xml" href="https://pawoo.net/users/pekorino/updates/874763.atom"/> - <thr:in-reply-to ref="tag:shitposter.club,2017-04-20:noticeId=2570261:objectType=note" href="https://shitposter.club/notice/2570261"/> - </entry> - <entry> - <id>tag:pawoo.net,2017-04-20:objectId=2206216:objectType=Status</id> - <published>2017-04-20T05:57:59Z</published> - <updated>2017-04-20T05:57:59Z</updated> - <title>New status by pekorino</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="en"><p>テスト</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://pawoo.net/users/pekorino/updates/872900"/> - <link rel="self" type="application/atom+xml" href="https://pawoo.net/users/pekorino/updates/872900.atom"/> - </entry> - <entry> - <id>tag:pawoo.net,2017-04-20:objectId=2204702:objectType=Status</id> - <published>2017-04-20T05:52:09Z</published> - <updated>2017-04-20T05:52:09Z</updated> - <title>New status by pekorino</title> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <content type="html" xml:lang="en"><p>HELLOWORLD</p></content> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <mastodon:scope>public</mastodon:scope> - <link rel="alternate" type="text/html" href="https://pawoo.net/users/pekorino/updates/872464"/> - <link rel="self" type="application/atom+xml" href="https://pawoo.net/users/pekorino/updates/872464.atom"/> - </entry> -</feed> diff --git a/test/fixtures/tesla_mock/https___pleroma.soykaf.com_users_lain_feed.atom.xml b/test/fixtures/tesla_mock/https___pleroma.soykaf.com_users_lain_feed.atom.xml deleted file mode 100644 index a2a2629a6..000000000 --- a/test/fixtures/tesla_mock/https___pleroma.soykaf.com_users_lain_feed.atom.xml +++ /dev/null @@ -1 +0,0 @@ -<?xml version="1.0"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:ostatus="http://ostatus.org/schema/1.0"><id>https://pleroma.soykaf.com/users/lain/feed.atom</id><title>lain's timeline</title><updated>2017-05-05T08:38:03.385598</updated><link rel="hub" href="https://pleroma.soykaf.com/push/hub/lain"/><link rel="salmon" href="https://pleroma.soykaf.com/users/lain/salmon"/><link rel="self" href="https://pleroma.soykaf.com/users/lain/feed.atom" type="application/atom+xml"/><author><id>https://pleroma.soykaf.com/users/lain</id><activity:object>http://activitystrea.ms/schema/1.0/person</activity:object><uri>https://pleroma.soykaf.com/users/lain</uri><poco:preferredUsername>lain</poco:preferredUsername><poco:displayName>Lain Iwakura</poco:displayName><poco:note>Test account</poco:note><name>lain</name><link rel="avatar" href="https://pleroma.soykaf.com/media/dbd1aa2f-21a3-4333-955f-67c0ac988cc2/6B3AFC74ACA841B24CFB94DB9044C84EDE6AFF31C71718B023D413DAED09A68E.jpeg"/></author><entry><activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb><id>https://pleroma.soykaf.com/activities/579e4224-b2ab-4ffa-8bbe-f7197a0a38d1</id><title>lain repeated a notice</title><content type="html">RT In just seven days, I can make you a man!<br> -- The Rocky Horror Picture Show</content><published>2017-05-05T08:38:03.385590</published><updated>2017-05-05T08:38:03.385598</updated><ostatus:conversation>https://pleroma.soykaf.com/contexts/e8673466-9642-4c9e-8781-f0f69d6b15ae</ostatus:conversation><link href="https://pleroma.soykaf.com/contexts/e8673466-9642-4c9e-8781-f0f69d6b15ae" rel="ostatus:conversation"/><link rel="self" type="application/atom+xml" href="https://pleroma.soykaf.com/activities/579e4224-b2ab-4ffa-8bbe-f7197a0a38d1"/><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb><id>https://pleroma.soykaf.com/objects/53dd40f4-3069-45a1-863b-94a9b317093d</id><title>New note by fortune</title><content type="html">In just seven days, I can make you a man!<br> -- The Rocky Horror Picture Show</content><published>2017-05-05T02:10:02.930802</published><updated>2017-05-05T08:38:03.423539</updated><ostatus:conversation>https://pleroma.soykaf.com/contexts/e8673466-9642-4c9e-8781-f0f69d6b15ae</ostatus:conversation><link href="https://pleroma.soykaf.com/contexts/e8673466-9642-4c9e-8781-f0f69d6b15ae" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://pleroma.soykaf.com/objects/53dd40f4-3069-45a1-863b-94a9b317093d" rel="self"/><author><id>https://pleroma.soykaf.com/users/fortune</id><activity:object>http://activitystrea.ms/schema/1.0/person</activity:object><uri>https://pleroma.soykaf.com/users/fortune</uri><poco:preferredUsername>fortune</poco:preferredUsername><poco:displayName>fortune</poco:displayName><poco:note>The trusty unix fortune file</poco:note><name>fortune</name><link rel="avatar" href="https://pleroma.soykaf.com/media/07ed0371-2817-4d80-97e1-255ca632fac6/66BA0B957C5E18404D405029B6C2B01FF1A306FB6EEF3E1D1F4C30DEBB1156D7.jpeg"/></author><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/></activity:object><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://pleroma.soykaf.com/users/fortune"/></entry><entry><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb><id>https://pleroma.soykaf.com/objects/2bc86888-a256-4771-bb53-903f375804f9</id><title>New note by lain</title><content type="html">RTs federating into pleroma now.</content><published>2017-05-04T18:18:50.276470</published><updated>2017-05-04T18:18:50.276476</updated><ostatus:conversation>https://pleroma.soykaf.com/contexts/b7ae9350-f317-48aa-8058-2668091bb280</ostatus:conversation><link href="https://pleroma.soykaf.com/contexts/b7ae9350-f317-48aa-8058-2668091bb280" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://pleroma.soykaf.com/objects/2bc86888-a256-4771-bb53-903f375804f9" rel="self"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/></entry><entry><activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb><id>https://pleroma.soykaf.com/activities/902b1f50-f295-4189-8c15-9c880919e121</id><title>New favorite by lain</title><content type="html">lain favorited something</content><published>2017-05-04T08:03:01.308890</published><updated>2017-05-04T08:03:01.308927</updated><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><id>tag:gs.smuglo.li,2017-05-03:noticeId=2164642:objectType=comment</id></activity:object><ostatus:conversation>https://pleroma.soykaf.com/contexts/9419f742-aaba-4eb5-89a2-8b599e8bf43c</ostatus:conversation><link href="https://pleroma.soykaf.com/contexts/9419f742-aaba-4eb5-89a2-8b599e8bf43c" rel="ostatus:conversation"/><link rel="self" type="application/atom+xml" href="https://pleroma.soykaf.com/activities/902b1f50-f295-4189-8c15-9c880919e121"/><thr:in-reply-to ref="tag:gs.smuglo.li,2017-05-03:noticeId=2164642:objectType=comment"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://gs.smuglo.li/user/2"/></entry><entry><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb><id>https://pleroma.soykaf.com/objects/4e396e66-b063-454c-92c6-583506a9a2de</id><title>New note by lain</title><content type="html">Classic.<br><a href='https://pleroma.soykaf.com/media/adc36781-9765-4d9a-b57c-99b7a99108b2/mikodaemonstop.jpg'>https://pleroma.soykaf.com/media/adc36781-9765-4d9a-b57c-99b7a99108b2/mikodaemonstop.jpg</a></content><published>2017-05-04T07:59:45.180619</published><updated>2017-05-04T07:59:45.180628</updated><ostatus:conversation>https://pleroma.soykaf.com/contexts/6afd9659-41e6-406d-ae97-43b880722861</ostatus:conversation><link href="https://pleroma.soykaf.com/contexts/6afd9659-41e6-406d-ae97-43b880722861" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://pleroma.soykaf.com/objects/4e396e66-b063-454c-92c6-583506a9a2de" rel="self"/><link rel="enclosure" href="https://pleroma.soykaf.com/media/adc36781-9765-4d9a-b57c-99b7a99108b2/mikodaemonstop.jpg" type="image/jpeg"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/></entry><entry><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb><id>https://pleroma.soykaf.com/objects/85d183e9-c935-4655-a1e6-8d69a4108235</id><title>New note by lain</title><content type="html">ん?<br><a href='https://pleroma.soykaf.com/media/ab144c6d-a38c-4d35-a60b-9a998becc094/n.gif'>https://pleroma.soykaf.com/media/ab144c6d-a38c-4d35-a60b-9a998becc094/n.gif</a></content><published>2017-05-04T07:58:08.810716</published><updated>2017-05-04T07:58:08.810726</updated><ostatus:conversation>https://pleroma.soykaf.com/contexts/2e1aa616-86ce-4b50-9c81-63045a972156</ostatus:conversation><link href="https://pleroma.soykaf.com/contexts/2e1aa616-86ce-4b50-9c81-63045a972156" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://pleroma.soykaf.com/objects/85d183e9-c935-4655-a1e6-8d69a4108235" rel="self"/><link rel="enclosure" href="https://pleroma.soykaf.com/media/ab144c6d-a38c-4d35-a60b-9a998becc094/n.gif" type="image/gif"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/></entry><entry><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb><id>https://pleroma.soykaf.com/objects/7c5c45bb-e4d9-4f72-b4c6-0314afbd3553</id><title>New note by lain</title><content type="html">yeah.</content><published>2017-05-04T07:55:17.335290</published><updated>2017-05-04T07:55:17.335299</updated><ostatus:conversation>https://pleroma.soykaf.com/contexts/702c06cf-56ff-4a2f-bf5a-150bc00bb168</ostatus:conversation><link href="https://pleroma.soykaf.com/contexts/702c06cf-56ff-4a2f-bf5a-150bc00bb168" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://pleroma.soykaf.com/objects/7c5c45bb-e4d9-4f72-b4c6-0314afbd3553" rel="self"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/></entry><entry><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb><id>https://pleroma.soykaf.com/objects/f33f5f54-1c1d-4462-b9ed-229bb635dfd8</id><title>New note by lain</title><content type="html">yeah.</content><published>2017-05-04T07:49:24.931484</published><updated>2017-05-04T07:49:24.931492</updated><ostatus:conversation>https://pleroma.soykaf.com/contexts/c4932e7a-00cb-431a-b4ec-7404cb9daf65</ostatus:conversation><link href="https://pleroma.soykaf.com/contexts/c4932e7a-00cb-431a-b4ec-7404cb9daf65" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://pleroma.soykaf.com/objects/f33f5f54-1c1d-4462-b9ed-229bb635dfd8" rel="self"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/></entry><entry><activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb><id>https://pleroma.soykaf.com/activities/0709bc79-7ac5-4983-b6d0-2205bf5ceba3</id><title>New favorite by lain</title><content type="html">lain favorited something</content><published>2017-05-03T20:08:11.294579</published><updated>2017-05-03T20:08:11.294587</updated><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><id>tag:pawoo.net,2017-05-03:objectId=7967690:objectType=Status</id></activity:object><ostatus:conversation>https://pleroma.soykaf.com/contexts/07a4b34d-6255-4bb2-8c73-c295a09ac952</ostatus:conversation><link href="https://pleroma.soykaf.com/contexts/07a4b34d-6255-4bb2-8c73-c295a09ac952" rel="ostatus:conversation"/><link rel="self" type="application/atom+xml" href="https://pleroma.soykaf.com/activities/0709bc79-7ac5-4983-b6d0-2205bf5ceba3"/><thr:in-reply-to ref="tag:pawoo.net,2017-05-03:objectId=7967690:objectType=Status"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://pawoo.net/users/God_Emperor_of_Dune"/></entry><entry><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb><id>https://pleroma.soykaf.com/objects/72c0288e-62d8-43d9-b3d8-1a9d78be8375</id><title>New note by lain</title><content type="html"><a href='https://pawoo.net/users/God_Emperor_of_Dune'>@God_Emperor_of_Dune@pawoo.net</a> no man, just some fun domination play among buddies, nothing homo about it.</content><published>2017-05-03T20:01:00.998314</published><updated>2017-05-03T20:01:00.998322</updated><ostatus:conversation>https://pleroma.soykaf.com/contexts/07a4b34d-6255-4bb2-8c73-c295a09ac952</ostatus:conversation><link href="https://pleroma.soykaf.com/contexts/07a4b34d-6255-4bb2-8c73-c295a09ac952" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://pleroma.soykaf.com/objects/72c0288e-62d8-43d9-b3d8-1a9d78be8375" rel="self"/><thr:in-reply-to ref="tag:pawoo.net,2017-05-03:objectId=7966029:objectType=Status"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://pawoo.net/users/God_Emperor_of_Dune"/></entry><entry><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb><id>https://pleroma.soykaf.com/objects/d846409e-cf2a-4b68-a149-d5de34a91b0d</id><title>New note by lain</title><content type="html"><a href='https://social.heldscal.la/user/24974'>@dtluna@social.heldscal.la</a> btfo.<br><a href='https://pleroma.soykaf.com/media/fbe42e87-5574-4544-89ba-29ddf46227fa/pnc__picked_media_1889ce61-4961-4fea-8a14-04fe6783ebf6.jpg'>https://pleroma.soykaf.com/media/fbe42e87-5574-4544-89ba-29ddf46227fa/pnc__picked_media_1889ce61-4961-4fea-8a14-04fe6783ebf6.jpg</a></content><published>2017-05-03T20:00:15.860995</published><updated>2017-05-03T20:00:15.861002</updated><ostatus:conversation>https://pleroma.soykaf.com/contexts/0e88f35e-1a38-4181-bef9-5cbb0d943c63</ostatus:conversation><link href="https://pleroma.soykaf.com/contexts/0e88f35e-1a38-4181-bef9-5cbb0d943c63" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://pleroma.soykaf.com/objects/d846409e-cf2a-4b68-a149-d5de34a91b0d" rel="self"/><link rel="enclosure" href="https://pleroma.soykaf.com/media/fbe42e87-5574-4544-89ba-29ddf46227fa/pnc__picked_media_1889ce61-4961-4fea-8a14-04fe6783ebf6.jpg" type="image/jpeg"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://social.heldscal.la/user/24974"/></entry><entry><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb><id>https://pleroma.soykaf.com/objects/9075265f-f3b2-40e8-809f-10714f05a1fd</id><title>New note by lain</title><content type="html">#nohomo <br><a href='https://pleroma.soykaf.com/media/5cc5ad91-d637-4c45-a691-5ea778dc1bb3/pnc__picked_media_f62dc9ae-ea23-4fe6-bf85-cb75a129ab34.jpg'>https://pleroma.soykaf.com/media/5cc5ad91-d637-4c45-a691-5ea778dc1bb3/pnc__picked_media_f62dc9ae-ea23-4fe6-bf85-cb75a129ab34.jpg</a></content><published>2017-05-03T19:50:38.589106</published><updated>2017-05-03T19:50:38.589113</updated><ostatus:conversation>https://pleroma.soykaf.com/contexts/07a4b34d-6255-4bb2-8c73-c295a09ac952</ostatus:conversation><link href="https://pleroma.soykaf.com/contexts/07a4b34d-6255-4bb2-8c73-c295a09ac952" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://pleroma.soykaf.com/objects/9075265f-f3b2-40e8-809f-10714f05a1fd" rel="self"/><link rel="enclosure" href="https://pleroma.soykaf.com/media/5cc5ad91-d637-4c45-a691-5ea778dc1bb3/pnc__picked_media_f62dc9ae-ea23-4fe6-bf85-cb75a129ab34.jpg" type="image/jpeg"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/></entry><entry><activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb><id>https://pleroma.soykaf.com/activities/7924e992-0a95-40d9-8d17-7278c6c634c9</id><title>New favorite by lain</title><content type="html">lain favorited something</content><published>2017-05-03T18:32:59.273375</published><updated>2017-05-03T18:32:59.273382</updated><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><id>tag:gs.smuglo.li,2017-05-03:noticeId=2164774:objectType=comment</id></activity:object><ostatus:conversation>https://pleroma.soykaf.com/contexts/9419f742-aaba-4eb5-89a2-8b599e8bf43c</ostatus:conversation><link href="https://pleroma.soykaf.com/contexts/9419f742-aaba-4eb5-89a2-8b599e8bf43c" rel="ostatus:conversation"/><link rel="self" type="application/atom+xml" href="https://pleroma.soykaf.com/activities/7924e992-0a95-40d9-8d17-7278c6c634c9"/><thr:in-reply-to ref="tag:gs.smuglo.li,2017-05-03:noticeId=2164774:objectType=comment"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://gs.smuglo.li/user/2"/></entry><entry><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb><id>https://pleroma.soykaf.com/objects/569571ba-f54c-41b0-bde4-0fede54599f0</id><title>New note by lain</title><content type="html"><a href='https://gs.smuglo.li/user/2'>@nepfag@gs.smuglo.li</a>@gs.smuglo.li I'll do proper subfolders soon, for now it's one per attachment + thumbs etc.</content><published>2017-05-03T18:27:01.449949</published><updated>2017-05-03T18:27:01.449956</updated><ostatus:conversation>https://pleroma.soykaf.com/contexts/9419f742-aaba-4eb5-89a2-8b599e8bf43c</ostatus:conversation><link href="https://pleroma.soykaf.com/contexts/9419f742-aaba-4eb5-89a2-8b599e8bf43c" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://pleroma.soykaf.com/objects/569571ba-f54c-41b0-bde4-0fede54599f0" rel="self"/><thr:in-reply-to ref="tag:gs.smuglo.li,2017-05-03:noticeId=2164642:objectType=comment"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://gs.smuglo.li/user/2"/></entry><entry><activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb><id>https://pleroma.soykaf.com/activities/b6cc5d7c-0785-4785-a689-f1b05dc9b24d</id><title>lain repeated a notice</title><content type="html">RT <p><span class="h-card"><a href="https://pleroma.soykaf.com/users/lain" class="u-url mention">@<span>lain</span></a></span> Hey now!</p></content><published>2017-05-03T18:13:48.891061</published><updated>2017-05-03T18:13:48.891069</updated><ostatus:conversation>https://pleroma.soykaf.com/contexts/ec6fdd27-0ec1-4672-8408-5a8e5a9c094b</ostatus:conversation><link href="https://pleroma.soykaf.com/contexts/ec6fdd27-0ec1-4672-8408-5a8e5a9c094b" rel="ostatus:conversation"/><link rel="self" type="application/atom+xml" href="https://pleroma.soykaf.com/activities/b6cc5d7c-0785-4785-a689-f1b05dc9b24d"/><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb><id>tag:mastodon.social,2017-05-01:objectId=4836142:objectType=Status</id><title>New note by lambadalambda@mastodon.social</title><content type="html"><p><span class="h-card"><a href="https://pleroma.soykaf.com/users/lain" class="u-url mention">@<span>lain</span></a></span> Hey now!</p></content><published>2017-05-01T18:38:49.365391</published><updated>2017-05-03T18:13:48.934745</updated><ostatus:conversation>https://pleroma.soykaf.com/contexts/ec6fdd27-0ec1-4672-8408-5a8e5a9c094b</ostatus:conversation><link href="https://pleroma.soykaf.com/contexts/ec6fdd27-0ec1-4672-8408-5a8e5a9c094b" rel="ostatus:conversation"/><link type="application/atom+xml" href="tag:mastodon.social,2017-05-01:objectId=4836142:objectType=Status" rel="self"/><thr:in-reply-to ref="https://pleroma.soykaf.com/objects/ffae4bea-00a3-4cef-8076-4ee4d448cb46"/><author><id>https://mastodon.social/users/lambadalambda</id><activity:object>http://activitystrea.ms/schema/1.0/person</activity:object><uri>https://mastodon.social/users/lambadalambda</uri><poco:preferredUsername>lambadalambda@mastodon.social</poco:preferredUsername><poco:displayName>Critical Value</poco:displayName><poco:note>nil</poco:note><name>lambadalambda@mastodon.social</name><link rel="avatar" href="https://files.mastodon.social/accounts/avatars/000/000/264/original/1429214160519.gif"/></author><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://pleroma.soykaf.com/users/lain"/></activity:object><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.social/users/lambadalambda"/></entry><entry><activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb><id>https://pleroma.soykaf.com/activities/3c09eb31-4ba8-4ff5-b4fa-8f6f74d58bf0</id><title>lain repeated a notice</title><content type="html">RT Haha, salmons from mastodon didn't work because it's not implementing conversation id...</content><published>2017-05-03T18:13:15.148041</published><updated>2017-05-03T18:13:15.148049</updated><ostatus:conversation>tag:social.heldscal.la,2017-05-01:objectType=thread:nonce=86cda6c734401d80</ostatus:conversation><link href="tag:social.heldscal.la,2017-05-01:objectType=thread:nonce=86cda6c734401d80" rel="ostatus:conversation"/><link rel="self" type="application/atom+xml" href="https://pleroma.soykaf.com/activities/3c09eb31-4ba8-4ff5-b4fa-8f6f74d58bf0"/><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb><id>tag:social.heldscal.la,2017-05-01:noticeId=2000425:objectType=note</id><title>New note by lambadalambda@social.heldscal.la</title><content type="html">Haha, salmons from mastodon didn't work because it's not implementing conversation id...</content><published>2017-05-01T18:39:36.216377</published><updated>2017-05-03T18:13:15.171143</updated><ostatus:conversation>tag:social.heldscal.la,2017-05-01:objectType=thread:nonce=86cda6c734401d80</ostatus:conversation><link href="tag:social.heldscal.la,2017-05-01:objectType=thread:nonce=86cda6c734401d80" rel="ostatus:conversation"/><link type="application/atom+xml" href="tag:social.heldscal.la,2017-05-01:noticeId=2000425:objectType=note" rel="self"/><author><id>https://social.heldscal.la/user/23211</id><activity:object>http://activitystrea.ms/schema/1.0/person</activity:object><uri>https://social.heldscal.la/user/23211</uri><poco:preferredUsername>lambadalambda@social.heldscal.la</poco:preferredUsername><poco:displayName>Constance Variable</poco:displayName><poco:note>nil</poco:note><name>lambadalambda@social.heldscal.la</name><link rel="avatar" href="https://social.heldscal.la/avatar/23211-original-20170416114255.jpeg"/></author><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/></activity:object><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://social.heldscal.la/user/23211"/></entry><entry><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb><id>https://pleroma.soykaf.com/objects/b8fc83d5-d7c0-4b5f-8976-0317b51935ea</id><title>New note by lain</title><content type="html">.<br><a href='https://pleroma.soykaf.com/media/563008a7-9a60-47ac-a263-22835729adf6/1492530528735.png'>https://pleroma.soykaf.com/media/563008a7-9a60-47ac-a263-22835729adf6/1492530528735.png</a></content><published>2017-05-03T18:12:50.745241</published><updated>2017-05-03T18:12:50.745249</updated><ostatus:conversation>https://pleroma.soykaf.com/contexts/9419f742-aaba-4eb5-89a2-8b599e8bf43c</ostatus:conversation><link href="https://pleroma.soykaf.com/contexts/9419f742-aaba-4eb5-89a2-8b599e8bf43c" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://pleroma.soykaf.com/objects/b8fc83d5-d7c0-4b5f-8976-0317b51935ea" rel="self"/><link rel="enclosure" href="https://pleroma.soykaf.com/media/563008a7-9a60-47ac-a263-22835729adf6/1492530528735.png" type="image/png"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/></entry><entry><activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb><id>https://pleroma.soykaf.com/activities/ac93ecef-cde0-48e8-ae4b-19e3b94dbe30</id><title>lain repeated a notice</title><content type="html">RT Awright, which one of you hid my PENIS ENVY?</content><published>2017-05-03T18:08:49.231001</published><updated>2017-05-03T18:08:49.235354</updated><ostatus:conversation>https://pleroma.soykaf.com/contexts/a9132cf8-6afa-4dd8-8b29-7b6fcab623b8</ostatus:conversation><link href="https://pleroma.soykaf.com/contexts/a9132cf8-6afa-4dd8-8b29-7b6fcab623b8" rel="ostatus:conversation"/><link rel="self" type="application/atom+xml" href="https://pleroma.soykaf.com/activities/ac93ecef-cde0-48e8-ae4b-19e3b94dbe30"/><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb><id>https://pleroma.soykaf.com/objects/04e15c66-4936-4930-a134-32841f088bcf</id><title>New note by fortune</title><content type="html">Awright, which one of you hid my PENIS ENVY?</content><published>2017-05-01T19:40:03.169996</published><updated>2017-05-03T18:08:49.285347</updated><ostatus:conversation>https://pleroma.soykaf.com/contexts/a9132cf8-6afa-4dd8-8b29-7b6fcab623b8</ostatus:conversation><link href="https://pleroma.soykaf.com/contexts/a9132cf8-6afa-4dd8-8b29-7b6fcab623b8" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://pleroma.soykaf.com/objects/04e15c66-4936-4930-a134-32841f088bcf" rel="self"/><author><id>https://pleroma.soykaf.com/users/fortune</id><activity:object>http://activitystrea.ms/schema/1.0/person</activity:object><uri>https://pleroma.soykaf.com/users/fortune</uri><poco:preferredUsername>fortune</poco:preferredUsername><poco:displayName>fortune</poco:displayName><poco:note>The trusty unix fortune file</poco:note><name>fortune</name><link rel="avatar" href="https://pleroma.soykaf.com/media/07ed0371-2817-4d80-97e1-255ca632fac6/66BA0B957C5E18404D405029B6C2B01FF1A306FB6EEF3E1D1F4C30DEBB1156D7.jpeg"/></author><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/></activity:object><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://pleroma.soykaf.com/users/fortune"/></entry><entry><activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb><id>https://pleroma.soykaf.com/activities/54b10fa9-d602-4a0f-b659-e6d3f7bc8c4c</id><title>lain repeated a notice</title><content type="html">RT He is a man capable of turning any colour into grey.<br> -- John LeCarre</content><published>2017-05-03T17:44:47.578984</published><updated>2017-05-03T17:44:47.578996</updated><ostatus:conversation>https://pleroma.soykaf.com/contexts/8aebc8e5-5352-4047-8b74-4098a5830cca</ostatus:conversation><link href="https://pleroma.soykaf.com/contexts/8aebc8e5-5352-4047-8b74-4098a5830cca" rel="ostatus:conversation"/><link rel="self" type="application/atom+xml" href="https://pleroma.soykaf.com/activities/54b10fa9-d602-4a0f-b659-e6d3f7bc8c4c"/><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb><id>https://pleroma.soykaf.com/objects/70ded299-184d-49cd-af17-23c0950536aa</id><title>New note by fortune</title><content type="html">He is a man capable of turning any colour into grey.<br> -- John LeCarre</content><published>2017-05-02T08:40:03.419465</published><updated>2017-05-03T17:44:47.646192</updated><ostatus:conversation>https://pleroma.soykaf.com/contexts/8aebc8e5-5352-4047-8b74-4098a5830cca</ostatus:conversation><link href="https://pleroma.soykaf.com/contexts/8aebc8e5-5352-4047-8b74-4098a5830cca" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://pleroma.soykaf.com/objects/70ded299-184d-49cd-af17-23c0950536aa" rel="self"/><author><id>https://pleroma.soykaf.com/users/fortune</id><activity:object>http://activitystrea.ms/schema/1.0/person</activity:object><uri>https://pleroma.soykaf.com/users/fortune</uri><poco:preferredUsername>fortune</poco:preferredUsername><poco:displayName>fortune</poco:displayName><poco:note>The trusty unix fortune file</poco:note><name>fortune</name><link rel="avatar" href="https://pleroma.soykaf.com/media/07ed0371-2817-4d80-97e1-255ca632fac6/66BA0B957C5E18404D405029B6C2B01FF1A306FB6EEF3E1D1F4C30DEBB1156D7.jpeg"/></author><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/></activity:object><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://pleroma.soykaf.com/users/fortune"/></entry><entry><activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb><id>https://pleroma.soykaf.com/activities/eff9fe49-8fc9-48e6-a1a0-921aa25c8118</id><title>lain repeated a notice</title><content type="html">RT The real trouble with women is that they have *all* the pussy.</content><published>2017-05-03T17:30:22.596037</published><updated>2017-05-03T17:30:22.596048</updated><ostatus:conversation>https://pleroma.soykaf.com/contexts/8c88c9df-4e40-4f54-b15f-c21848d1a8e2</ostatus:conversation><link href="https://pleroma.soykaf.com/contexts/8c88c9df-4e40-4f54-b15f-c21848d1a8e2" rel="ostatus:conversation"/><link rel="self" type="application/atom+xml" href="https://pleroma.soykaf.com/activities/eff9fe49-8fc9-48e6-a1a0-921aa25c8118"/><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb><id>https://pleroma.soykaf.com/objects/0b9b008d-49eb-48a9-a18d-172ce7d01ea2</id><title>New note by fortune</title><content type="html">The real trouble with women is that they have *all* the pussy.</content><published>2017-05-02T12:10:03.603086</published><updated>2017-05-03T17:30:22.683141</updated><ostatus:conversation>https://pleroma.soykaf.com/contexts/8c88c9df-4e40-4f54-b15f-c21848d1a8e2</ostatus:conversation><link href="https://pleroma.soykaf.com/contexts/8c88c9df-4e40-4f54-b15f-c21848d1a8e2" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://pleroma.soykaf.com/objects/0b9b008d-49eb-48a9-a18d-172ce7d01ea2" rel="self"/><author><id>https://pleroma.soykaf.com/users/fortune</id><activity:object>http://activitystrea.ms/schema/1.0/person</activity:object><uri>https://pleroma.soykaf.com/users/fortune</uri><poco:preferredUsername>fortune</poco:preferredUsername><poco:displayName>fortune</poco:displayName><poco:note>The trusty unix fortune file</poco:note><name>fortune</name><link rel="avatar" href="https://pleroma.soykaf.com/media/07ed0371-2817-4d80-97e1-255ca632fac6/66BA0B957C5E18404D405029B6C2B01FF1A306FB6EEF3E1D1F4C30DEBB1156D7.jpeg"/></author><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/></activity:object><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://pleroma.soykaf.com/users/fortune"/></entry><entry><activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb><id>https://pleroma.soykaf.com/activities/5d90bb26-ce23-4a5b-8dbd-651011780007</id><title>New favorite by lain</title><content type="html">lain favorited something</content><published>2017-05-03T17:28:20.967926</published><updated>2017-05-03T17:28:20.967935</updated><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><id>tag:mastodon.social,2017-05-03:objectId=4952899:objectType=Status</id></activity:object><ostatus:conversation>https://pleroma.soykaf.com/contexts/42701ab4-964a-441a-a372-f51bd183e441</ostatus:conversation><link href="https://pleroma.soykaf.com/contexts/42701ab4-964a-441a-a372-f51bd183e441" rel="ostatus:conversation"/><link rel="self" type="application/atom+xml" href="https://pleroma.soykaf.com/activities/5d90bb26-ce23-4a5b-8dbd-651011780007"/><thr:in-reply-to ref="tag:mastodon.social,2017-05-03:objectId=4952899:objectType=Status"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.social/users/lambadalambda"/></entry></feed>
\ No newline at end of file diff --git a/test/fixtures/tesla_mock/https___shitposter.club_api_statuses_show_2827873.atom.xml b/test/fixtures/tesla_mock/https___shitposter.club_api_statuses_show_2827873.atom.xml deleted file mode 100644 index 26fdebb49..000000000 --- a/test/fixtures/tesla_mock/https___shitposter.club_api_statuses_show_2827873.atom.xml +++ /dev/null @@ -1,54 +0,0 @@ -<entry xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:georss="http://www.georss.org/georss" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:media="http://purl.org/syndication/atommedia" xmlns:statusnet="http://status.net/schema/api/1/"> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment</id> - <title>New comment by moonman</title> - <content type="html">@<a href="https://shitposter.club/user/9655" class="h-card mention" title="Solidarity for Pigs">neimzr4luzerz</a> @<a href="https://gs.smuglo.li/user/2326" class="h-card mention" title="Dolus_McHonest">dolus</a> childhood poring over Strong's concordance and a koine Greek dictionary, fast forward to 2017 and some fuckstick who translates japanese jackoff material tells me you just need to make it sound right in English</content> - <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2827873"/> - <status_net notice_id="2827873"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-05-05T08:51:48+00:00</published> - <updated>2017-05-05T08:51:48+00:00</updated> - <author> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://shitposter.club/user/1</uri> - <name>moonman</name> - <summary>EMAIL:shitposterclub@gmail.com XMPP: moon@talk.shitposter.club Matrix Ed25519 fingerprint: 2HuDUTEz3iFN5N3xl6PYp9xZW/EWhgbbt78SrFy4w8o</summary> - <link rel="alternate" type="text/html" href="https://shitposter.club/moonman"/> - <link rel="avatar" type="image/jpeg" media:width="1040" media:height="1040" href="https://shitposter.club/avatar/1-original-20170503024316.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://shitposter.club/avatar/1-96-20170503024316.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="48" media:height="48" href="https://shitposter.club/avatar/1-48-20170503024316.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="24" media:height="24" href="https://shitposter.club/avatar/1-24-20170503024318.jpeg"/> - <poco:preferredUsername>moonman</poco:preferredUsername> - <poco:displayName>Generic Enemy</poco:displayName> - <poco:note>EMAIL:shitposterclub@gmail.com XMPP: moon@talk.shitposter.club Matrix Ed25519 fingerprint: 2HuDUTEz3iFN5N3xl6PYp9xZW/EWhgbbt78SrFy4w8o</poco:note> - <poco:address> - <poco:formatted>The Moon</poco:formatted> - </poco:address> - <poco:urls> - <poco:type>homepage</poco:type> - <poco:value>https://shitposter.club/moonman</poco:value> - <poco:primary>true</poco:primary> - </poco:urls> - <followers url="https://shitposter.club/moonman/subscribers"></followers> - <statusnet:profile_info local_id="1"></statusnet:profile_info> - </author> - <thr:in-reply-to ref="tag:shitposter.club,2017-05-05:noticeId=2827849:objectType=comment" href="https://shitposter.club/notice/2827849"></thr:in-reply-to> - <link rel="related" href="https://shitposter.club/notice/2827849"/> - <link rel="ostatus:conversation" href="https://shitposter.club/conversation/1390270"/> - <ostatus:conversation href="https://shitposter.club/conversation/1390270" local_id="1390270" ref="tag:shitposter.club,2017-05-05:objectType=thread:nonce=3c16e9c2681f6d26">tag:shitposter.club,2017-05-05:objectType=thread:nonce=3c16e9c2681f6d26</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://gs.smuglo.li/user/2326"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://shitposter.club/user/9655"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <source> - <id>https://shitposter.club/api/statuses/user_timeline/1.atom</id> - <title>Generic Enemy</title> - <link rel="alternate" type="text/html" href="https://shitposter.club/moonman"/> - <link rel="self" type="application/atom+xml" href="https://shitposter.club/api/statuses/user_timeline/1.atom"/> - <link rel="license" href="https://shitposter.club/doc/tos"/> - <icon>https://shitposter.club/avatar/1-96-20170503024316.jpeg</icon> - <updated>2017-05-05T11:43:58+00:00</updated> - </source> - <link rel="self" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2827873.atom"/> - <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2827873.atom"/> - <statusnet:notice_info local_id="2827873" source="Qvitter"></statusnet:notice_info> -</entry> diff --git a/test/fixtures/tesla_mock/https___shitposter.club_api_statuses_user_timeline_1.atom.xml b/test/fixtures/tesla_mock/https___shitposter.club_api_statuses_user_timeline_1.atom.xml deleted file mode 100644 index 31df7c2a6..000000000 --- a/test/fixtures/tesla_mock/https___shitposter.club_api_statuses_user_timeline_1.atom.xml +++ /dev/null @@ -1,454 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:georss="http://www.georss.org/georss" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:media="http://purl.org/syndication/atommedia" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:statusnet="http://status.net/schema/api/1/"> - <generator uri="https://gnu.io/social" version="1.2.0-beta4">GNU social</generator> - <id>https://shitposter.club/api/statuses/user_timeline/1.atom</id> - <title>moonman timeline</title> - <subtitle>Updates from moonman on Shitposter Club!</subtitle> - <logo>https://shitposter.club/avatar/1-96-20170503024316.jpeg</logo> - <updated>2017-05-05T13:24:09+00:00</updated> -<author> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://shitposter.club/user/1</uri> - <name>moonman</name> - <summary>EMAIL:shitposterclub@gmail.com XMPP: moon@talk.shitposter.club Matrix Ed25519 fingerprint: 2HuDUTEz3iFN5N3xl6PYp9xZW/EWhgbbt78SrFy4w8o</summary> - <link rel="alternate" type="text/html" href="https://shitposter.club/moonman"/> - <link rel="avatar" type="image/jpeg" media:width="1040" media:height="1040" href="https://shitposter.club/avatar/1-original-20170503024316.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://shitposter.club/avatar/1-96-20170503024316.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="48" media:height="48" href="https://shitposter.club/avatar/1-48-20170503024316.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="24" media:height="24" href="https://shitposter.club/avatar/1-24-20170503024318.jpeg"/> - <poco:preferredUsername>moonman</poco:preferredUsername> - <poco:displayName>Generic Enemy</poco:displayName> - <poco:note>EMAIL:shitposterclub@gmail.com XMPP: moon@talk.shitposter.club Matrix Ed25519 fingerprint: 2HuDUTEz3iFN5N3xl6PYp9xZW/EWhgbbt78SrFy4w8o</poco:note> - <poco:address> - <poco:formatted>The Moon</poco:formatted> - </poco:address> - <poco:urls> - <poco:type>homepage</poco:type> - <poco:value>https://shitposter.club/moonman</poco:value> - <poco:primary>true</poco:primary> - </poco:urls> - <followers url="https://shitposter.club/moonman/subscribers"></followers> - <statusnet:profile_info local_id="1"></statusnet:profile_info> -</author> - <link href="https://shitposter.club/moonman" rel="alternate" type="text/html"/> - <link href="https://shitposter.club/main/sup" rel="http://api.friendfeed.com/2008/03#sup" type="application/json"/> - <link href="https://shitposter.club/api/statuses/user_timeline/1.atom?max_id=2828044" rel="next" type="application/atom+xml"/> - <link href="https://shitposter.club/main/push/hub" rel="hub"/> - <link href="https://shitposter.club/main/salmon/user/1" rel="salmon"/> - <link href="https://shitposter.club/main/salmon/user/1" rel="http://salmon-protocol.org/ns/salmon-replies"/> - <link href="https://shitposter.club/main/salmon/user/1" rel="http://salmon-protocol.org/ns/salmon-mention"/> - <link href="https://shitposter.club/api/statuses/user_timeline/1.atom" rel="self" type="application/atom+xml"/> -<entry> - <id>tag:shitposter.club,2017-05-05:subscription:1:person:23190:2017-05-05T11:43:58+00:00</id> - <title>Generic Enemy (moonman)'s status on Friday, 05-May-2017 11:43:58 UTC</title> - <content type="html"><a href="https://shitposter.club/moonman">Generic Enemy</a> started following <a href="https://noagendasocial.com/@Ma5on">Mason</a>.</content> - <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2829381"/> - <activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb> - <published>2017-05-05T11:43:58+00:00</published> - <updated>2017-05-05T11:43:58+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <id>https://noagendasocial.com/users/Ma5on</id> - <title>Mason</title> - <link rel="alternate" type="text/html" href="https://noagendasocial.com/@Ma5on"/> - <link rel="avatar" type="image/jpeg" media:width="120" media:height="120" href="https://shitposter.club/avatar/23190-original-20170505114356.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://shitposter.club/avatar/23190-96-20170505114358.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="48" media:height="48" href="https://shitposter.club/avatar/23190-48-20170505114358.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="24" media:height="24" href="https://shitposter.club/avatar/23190-24-20170505114358.jpeg"/> - <poco:preferredUsername>ma5on</poco:preferredUsername> - <poco:displayName>Mason</poco:displayName> - </activity:object> - <link rel="ostatus:conversation" href="https://shitposter.club/conversation/1391451"/> - <ostatus:conversation href="https://shitposter.club/conversation/1391451" local_id="1391451" ref="tag:shitposter.club,2017-05-05:objectType=thread:nonce=abffa9c14a054d3b">tag:shitposter.club,2017-05-05:objectType=thread:nonce=abffa9c14a054d3b</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2829381.atom"/> - <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2829381.atom"/> - <statusnet:notice_info local_id="2829381" source="activity"></statusnet:notice_info> -</entry> -<entry> - <id>tag:shitposter.club,2017-05-05:subscription:1:person:14357:2017-05-05T10:29:03+00:00</id> - <title>Generic Enemy (moonman)'s status on Friday, 05-May-2017 10:29:03 UTC</title> - <content type="html"><a href="https://shitposter.club/moonman">Generic Enemy</a> started following <a href="https://mastodon.cloud/@ohyran">Jens Reuterberg</a>.</content> - <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2828682"/> - <activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb> - <published>2017-05-05T10:29:03+00:00</published> - <updated>2017-05-05T10:29:03+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <id>https://mastodon.cloud/users/ohyran</id> - <title>Jens Reuterberg</title> - <summary>RPG-nerd, illustrator, Open Source enthusiast, KDE dude, designer and gay lefty. Might be a cliché - but we will soon find out!</summary> - <link rel="alternate" type="text/html" href="https://mastodon.cloud/@ohyran"/> - <link rel="avatar" type="image/jpeg" media:width="120" media:height="120" href="https://shitposter.club/avatar/14357-original-20170505110123.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://shitposter.club/avatar/14357-96-20170505110757.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="48" media:height="48" href="https://shitposter.club/avatar/14357-48-20170505110757.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="24" media:height="24" href="https://shitposter.club/avatar/14357-24-20170505110757.jpeg"/> - <poco:preferredUsername>ohyran</poco:preferredUsername> - <poco:displayName>Jens Reuterberg</poco:displayName> - <poco:note>RPG-nerd, illustrator, Open Source enthusiast, KDE dude, designer and gay lefty. Might be a cliché - but we will soon find out!</poco:note> - </activity:object> - <link rel="ostatus:conversation" href="https://shitposter.club/conversation/1390971"/> - <ostatus:conversation href="https://shitposter.club/conversation/1390971" local_id="1390971" ref="tag:shitposter.club,2017-05-05:objectType=thread:nonce=937151d4825a85bf">tag:shitposter.club,2017-05-05:objectType=thread:nonce=937151d4825a85bf</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828682.atom"/> - <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828682.atom"/> - <statusnet:notice_info local_id="2828682" source="activity"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:shitposter.club,2017-05-05:noticeId=2828637:objectType=note</id> - <title>New note by moonman</title> - <content type="html">basicall i would just rather have ppl say &quot;i like x and y&quot; than &quot;i'm a nerd&quot; the term can be retired.</content> - <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2828637"/> - <status_net notice_id="2828637"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-05-05T10:24:54+00:00</published> - <updated>2017-05-05T10:24:54+00:00</updated> - <link rel="ostatus:conversation" href="https://shitposter.club/conversation/1390949"/> - <ostatus:conversation href="https://shitposter.club/conversation/1390949" local_id="1390949" ref="tag:shitposter.club,2017-05-05:objectType=thread:nonce=65992b0b9b5e6931">tag:shitposter.club,2017-05-05:objectType=thread:nonce=65992b0b9b5e6931</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828637.atom"/> - <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828637.atom"/> - <statusnet:notice_info local_id="2828637" source="Qvitter"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>tag:shitposter.club,2017-05-05:noticeId=2828579:objectType=comment</id> - <title>New comment by moonman</title> - <content type="html">@<a href="https://gs.smuglo.li/user/35497" class="h-card mention" title="Bokuro Bokusawa">boco</a> to be honest i've turned right around and been cruel to other people, i said i'd never do it but it happens again eventually.</content> - <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2828579"/> - <status_net notice_id="2828579"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-05-05T10:20:33+00:00</published> - <updated>2017-05-05T10:20:33+00:00</updated> - <thr:in-reply-to ref="tag:gs.smuglo.li,2017-05-05:noticeId=2189031:objectType=comment" href="https://gs.smuglo.li/notice/2189031"></thr:in-reply-to> - <link rel="related" href="https://gs.smuglo.li/notice/2189031"/> - <link rel="ostatus:conversation" href="https://shitposter.club/conversation/1390862"/> - <ostatus:conversation href="https://shitposter.club/conversation/1390862" local_id="1390862" ref="tag:shitposter.club,2017-05-05:objectType=thread:nonce=c997fc73d7f8a8f0">tag:shitposter.club,2017-05-05:objectType=thread:nonce=c997fc73d7f8a8f0</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://gs.smuglo.li/user/35497"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828579.atom"/> - <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828579.atom"/> - <statusnet:notice_info local_id="2828579" source="Qvitter"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>tag:shitposter.club,2017-05-05:noticeId=2828554:objectType=comment</id> - <title>New comment by moonman</title> - <content type="html">@<a href="https://mastodon.cloud/users/ohyran" class="h-card mention" title="Jens Reuterberg">ohyran</a> i won't ever get over bullying but i agree otherwise. i don't go to comic shops too often these days but i got dragged to one last year and the sheer diversity of people enjoying comics now compared to years ago was striking and it pleased me. and i noticed a couple years ago because of youtube i find things i truly enjoy watching, like in-depth videos about electronic parts, didn't exist 20 years ago. it's pretty great.</content> - <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2828554"/> - <status_net notice_id="2828554"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-05-05T10:18:10+00:00</published> - <updated>2017-05-05T10:18:10+00:00</updated> - <thr:in-reply-to ref="tag:mastodon.cloud,2017-05-05:objectId=6334570:objectType=Status" href="https://mastodon.cloud/users/ohyran/updates/595969"></thr:in-reply-to> - <link rel="related" href="https://mastodon.cloud/users/ohyran/updates/595969"/> - <link rel="ostatus:conversation" href="https://shitposter.club/conversation/1390752"/> - <ostatus:conversation href="https://shitposter.club/conversation/1390752" local_id="1390752" ref="tag:shitposter.club,2017-05-05:objectType=thread:nonce=efae3a23b6e05767">tag:shitposter.club,2017-05-05:objectType=thread:nonce=efae3a23b6e05767</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.cloud/users/ohyran"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828554.atom"/> - <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828554.atom"/> - <statusnet:notice_info local_id="2828554" source="Qvitter"></statusnet:notice_info> -</entry> -<entry> - <id>tag:shitposter.club,2017-05-05:fave:1:comment:2828502:2017-05-05T10:12:52+00:00</id> - <title>Favorite</title> - <content type="html">moonman favorited something by ohyran: <p><span class="h-card"><a href="https://shitposter.club/moonman" class="u-url mention">@<span>moonman</span></a></span> fair enough - that distinction makes it clearer...</p><p>On the other hand - those of us who did "pay the price" of being nerdy little kids in the 80's and 90's should strive to get past it anyway (mental health wise not "just get over it") and see the "nerd culture" thing as a blessing of sorts. We are in the optimal spot to do it. (not saying that that is something easy btw just that NOW is the best of time to start talking about it)</p></content> - <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2828506"/> - <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb> - <published>2017-05-05T10:12:52+00:00</published> - <updated>2017-05-05T10:12:52+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>tag:mastodon.cloud,2017-05-05:objectId=6334570:objectType=Status</id> - <title>New comment by ohyran</title> - <content type="html"><p><span class="h-card"><a href="https://shitposter.club/moonman" class="u-url mention">@<span>moonman</span></a></span> fair enough - that distinction makes it clearer...</p><p>On the other hand - those of us who did "pay the price" of being nerdy little kids in the 80's and 90's should strive to get past it anyway (mental health wise not "just get over it") and see the "nerd culture" thing as a blessing of sorts. We are in the optimal spot to do it. (not saying that that is something easy btw just that NOW is the best of time to start talking about it)</p></content> - <link rel="alternate" type="text/html" href="https://mastodon.cloud/users/ohyran/updates/595969"/> - <status_net notice_id="2828502"></status_net> - </activity:object> - <thr:in-reply-to ref="tag:mastodon.cloud,2017-05-05:objectId=6334570:objectType=Status" href="https://mastodon.cloud/users/ohyran/updates/595969"></thr:in-reply-to> - <link rel="related" href="https://mastodon.cloud/users/ohyran/updates/595969"/> - <link rel="ostatus:conversation" href="https://shitposter.club/conversation/1390752"/> - <ostatus:conversation href="https://shitposter.club/conversation/1390752" local_id="1390752" ref="tag:shitposter.club,2017-05-05:objectType=thread:nonce=efae3a23b6e05767">tag:shitposter.club,2017-05-05:objectType=thread:nonce=efae3a23b6e05767</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828506.atom"/> - <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828506.atom"/> - <statusnet:notice_info local_id="2828506" source="unknown"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:shitposter.club,2017-05-05:noticeId=2828496:objectType=note</id> - <title>New note by moonman</title> - <content type="html">things are better now, a lot less kids in america get beaten up and called a fag. still too many.</content> - <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2828496"/> - <status_net notice_id="2828496"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-05-05T10:11:31+00:00</published> - <updated>2017-05-05T10:11:31+00:00</updated> - <link rel="ostatus:conversation" href="https://shitposter.club/conversation/1390862"/> - <ostatus:conversation href="https://shitposter.club/conversation/1390862" local_id="1390862" ref="tag:shitposter.club,2017-05-05:objectType=thread:nonce=c997fc73d7f8a8f0">tag:shitposter.club,2017-05-05:objectType=thread:nonce=c997fc73d7f8a8f0</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828496.atom"/> - <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828496.atom"/> - <statusnet:notice_info local_id="2828496" source="Qvitter"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>tag:shitposter.club,2017-05-05:noticeId=2828457:objectType=comment</id> - <title>New comment by moonman</title> - <content type="html">@<a href="https://shitposter.club/user/21787" class="h-card mention" title="Yukari">cutscenes</a> @<a href="https://gs.smuglo.li/user/28250" class="h-card mention" title="Bricky">thatbrickster</a> @<a href="https://gs.smuglo.li/user/35497" class="h-card mention" title="Bokuro Bokusawa">boco</a> i never understood this because nerds had pocket protectors, which was a draftsman engineer thing and therefore smart, while geeks were people in carnivals who bit heads off small animals.</content> - <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2828457"/> - <status_net notice_id="2828457"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-05-05T10:07:57+00:00</published> - <updated>2017-05-05T10:07:57+00:00</updated> - <thr:in-reply-to ref="tag:shitposter.club,2017-05-05:noticeId=2828427:objectType=comment" href="https://shitposter.club/notice/2828427"></thr:in-reply-to> - <link rel="related" href="https://shitposter.club/notice/2828427"/> - <link rel="ostatus:conversation" href="https://shitposter.club/conversation/1390752"/> - <ostatus:conversation href="https://shitposter.club/conversation/1390752" local_id="1390752" ref="tag:shitposter.club,2017-05-05:objectType=thread:nonce=efae3a23b6e05767">tag:shitposter.club,2017-05-05:objectType=thread:nonce=efae3a23b6e05767</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://gs.smuglo.li/user/28250"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://gs.smuglo.li/user/35497"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://shitposter.club/user/21787"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828457.atom"/> - <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828457.atom"/> - <statusnet:notice_info local_id="2828457" source="Qvitter"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>tag:shitposter.club,2017-05-05:noticeId=2828435:objectType=comment</id> - <title>New comment by moonman</title> - <content type="html">@<a href="https://mastodon.cloud/users/ohyran" class="h-card mention" title="Jens Reuterberg">ohyran</a> since i didn't specify i'm talking about people subjected to physical and psychological abuse and not people that are just mad that more people like comic books now.</content> - <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2828435"/> - <status_net notice_id="2828435"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-05-05T10:05:07+00:00</published> - <updated>2017-05-05T10:05:07+00:00</updated> - <thr:in-reply-to ref="tag:mastodon.cloud,2017-05-05:objectId=6331705:objectType=Status" href="https://mastodon.cloud/users/ohyran/updates/595757"></thr:in-reply-to> - <link rel="related" href="https://mastodon.cloud/users/ohyran/updates/595757"/> - <link rel="ostatus:conversation" href="https://shitposter.club/conversation/1390752"/> - <ostatus:conversation href="https://shitposter.club/conversation/1390752" local_id="1390752" ref="tag:shitposter.club,2017-05-05:objectType=thread:nonce=efae3a23b6e05767">tag:shitposter.club,2017-05-05:objectType=thread:nonce=efae3a23b6e05767</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.cloud/users/ohyran"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828435.atom"/> - <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828435.atom"/> - <statusnet:notice_info local_id="2828435" source="Qvitter"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:shitposter.club,2017-05-05:noticeId=2828326:objectType=note</id> - <title>New note by moonman</title> - <content type="html">if you were a &quot;nerd&quot; before, like, 2001 you have permanent excuse to hate this kind of shit. <a href="https://shitposter.club/file/b79fa5644be0d6f22679136e67b7bf45c9c4a74a55c32dd2d0cf15de4ddd5be5.gif" title="https://shitposter.club/file/b79fa5644be0d6f22679136e67b7bf45c9c4a74a55c32dd2d0cf15de4ddd5be5.gif" class="attachment" id="attachment-662105" rel="nofollow external">https://shitposter.club/attachment/662105</a></content> - <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2828326"/> - <status_net notice_id="2828326"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-05-05T09:47:42+00:00</published> - <updated>2017-05-05T09:47:42+00:00</updated> - <link rel="ostatus:conversation" href="https://shitposter.club/conversation/1390752"/> - <ostatus:conversation href="https://shitposter.club/conversation/1390752" local_id="1390752" ref="tag:shitposter.club,2017-05-05:objectType=thread:nonce=efae3a23b6e05767">tag:shitposter.club,2017-05-05:objectType=thread:nonce=efae3a23b6e05767</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="enclosure" href="https://shitposter.club/file/b79fa5644be0d6f22679136e67b7bf45c9c4a74a55c32dd2d0cf15de4ddd5be5.gif" type="image/gif" length="1023884"/> - <link rel="self" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828326.atom"/> - <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828326.atom"/> - <statusnet:notice_info local_id="2828326" source="Qvitter"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:shitposter.club,2017-05-05:noticeId=2828250:objectType=note</id> - <title>New note by moonman</title> - <content type="html"><a href="https://shitposter.club/file/1283e2d4dd8f96b8eeb5d9a16b318e210868aa11386cf0d593891e4c75c9126e.gif" title="https://shitposter.club/file/1283e2d4dd8f96b8eeb5d9a16b318e210868aa11386cf0d593891e4c75c9126e.gif" class="attachment" id="attachment-662098" rel="nofollow external">https://shitposter.club/attachment/662098</a></content> - <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2828250"/> - <status_net notice_id="2828250"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-05-05T09:39:06+00:00</published> - <updated>2017-05-05T09:39:06+00:00</updated> - <link rel="ostatus:conversation" href="https://shitposter.club/conversation/1390709"/> - <ostatus:conversation href="https://shitposter.club/conversation/1390709" local_id="1390709" ref="tag:shitposter.club,2017-05-05:objectType=thread:nonce=ea8ffae90546f0ab">tag:shitposter.club,2017-05-05:objectType=thread:nonce=ea8ffae90546f0ab</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="enclosure" href="https://shitposter.club/file/1283e2d4dd8f96b8eeb5d9a16b318e210868aa11386cf0d593891e4c75c9126e.gif" type="image/gif" length="1020391"/> - <link rel="self" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828250.atom"/> - <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828250.atom"/> - <statusnet:notice_info local_id="2828250" source="Qvitter"></statusnet:notice_info> -</entry> -<entry> - <id>tag:shitposter.club,2017-05-05:fave:1:comment:2828161:2017-05-05T09:28:19+00:00</id> - <title>Favorite</title> - <content type="html">moonman favorited something by kro: @<a href="https://shitposter.club/user/1" class="h-card u-url p-nickname mention" title="Generic Enemy">moonman</a> Till Brooklyn?</content> - <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2828162"/> - <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb> - <published>2017-05-05T09:28:19+00:00</published> - <updated>2017-05-05T09:28:19+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>tag:gs.smuglo.li,2017-05-05:noticeId=2188587:objectType=comment</id> - <title>New comment by kro</title> - <content type="html">@<a href="https://shitposter.club/user/1" class="h-card u-url p-nickname mention" title="Generic Enemy">moonman</a> Till Brooklyn?</content> - <link rel="alternate" type="text/html" href="https://gs.smuglo.li/notice/2188587"/> - <status_net notice_id="2828161"></status_net> - </activity:object> - <thr:in-reply-to ref="tag:gs.smuglo.li,2017-05-05:noticeId=2188587:objectType=comment" href="https://gs.smuglo.li/notice/2188587"></thr:in-reply-to> - <link rel="related" href="https://gs.smuglo.li/notice/2188587"/> - <link rel="ostatus:conversation" href="https://shitposter.club/conversation/1390624"/> - <ostatus:conversation href="https://shitposter.club/conversation/1390624" local_id="1390624" ref="tag:shitposter.club,2017-05-05:objectType=thread:nonce=d7aa6b5b057ca555">tag:shitposter.club,2017-05-05:objectType=thread:nonce=d7aa6b5b057ca555</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828162.atom"/> - <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828162.atom"/> - <statusnet:notice_info local_id="2828162" source="unknown"></statusnet:notice_info> -</entry> -<entry> - <id>tag:shitposter.club,2017-05-05:fave:1:comment:2828125:2017-05-05T09:24:56+00:00</id> - <title>Favorite</title> - <content type="html">moonman favorited something by hardbass2k8: this has obviously interesting implications in various places, for example:<br /> the nationalism of the nazis might not have been real, who would have thought?<br /> socialism is usually promoted to implementation by real douchebags!<br /> your local social justice people might want diversity but they don't want you, m/19, white, why?<br /> amateur soccer club, they want to be the best in the amateur league but actually they just get drunk after training and are 50% overweight.<br /> This is because humans are not capable of telepathy, so if you join a group it doesn't magically align every little bit of your being with the declared group goals.<br /> <br /> Even though you see unmanned group beliefs flying around from time to time, generally groups are created from a bunch of people. they are not a container for people, they are the people inside them.<br /> <br /> so if you see a group that appears to be cool don't think of it as cool because its goals are cool but because its members are cool. if they aren't, tough cookies. don't be the retard and end up on the camp watchtower.</content> - <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2828136"/> - <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb> - <published>2017-05-05T09:24:56+00:00</published> - <updated>2017-05-05T09:24:56+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>tag:shitposter.club,2017-05-05:noticeId=2828125:objectType=comment</id> - <title>New comment by hardbass2k8</title> - <content type="html">this has obviously interesting implications in various places, for example:<br /> the nationalism of the nazis might not have been real, who would have thought?<br /> socialism is usually promoted to implementation by real douchebags!<br /> your local social justice people might want diversity but they don't want you, m/19, white, why?<br /> amateur soccer club, they want to be the best in the amateur league but actually they just get drunk after training and are 50% overweight.<br /> This is because humans are not capable of telepathy, so if you join a group it doesn't magically align every little bit of your being with the declared group goals.<br /> <br /> Even though you see unmanned group beliefs flying around from time to time, generally groups are created from a bunch of people. they are not a container for people, they are the people inside them.<br /> <br /> so if you see a group that appears to be cool don't think of it as cool because its goals are cool but because its members are cool. if they aren't, tough cookies. don't be the retard and end up on the camp watchtower.</content> - <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2828125"/> - <status_net notice_id="2828125"></status_net> - </activity:object> - <thr:in-reply-to ref="tag:shitposter.club,2017-05-05:noticeId=2828125:objectType=comment" href="https://shitposter.club/notice/2828125"></thr:in-reply-to> - <link rel="related" href="https://shitposter.club/notice/2828125"/> - <link rel="ostatus:conversation" href="https://shitposter.club/conversation/1390589"/> - <ostatus:conversation href="https://shitposter.club/conversation/1390589" local_id="1390589" ref="tag:shitposter.club,2017-05-05:objectType=thread:nonce=51b227fe92f6babf">tag:shitposter.club,2017-05-05:objectType=thread:nonce=51b227fe92f6babf</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828136.atom"/> - <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828136.atom"/> - <statusnet:notice_info local_id="2828136" source="unknown"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:shitposter.club,2017-05-05:noticeId=2828128:objectType=note</id> - <title>New note by moonman</title> - <content type="html">In a valid remake of They live, signs would say REBEL, and DON'T GET MARRIED AND HAVE KIDS</content> - <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2828128"/> - <status_net notice_id="2828128"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-05-05T09:24:23+00:00</published> - <updated>2017-05-05T09:24:23+00:00</updated> - <link rel="ostatus:conversation" href="https://shitposter.club/conversation/1390642"/> - <ostatus:conversation href="https://shitposter.club/conversation/1390642" local_id="1390642" ref="tag:shitposter.club,2017-05-05:objectType=thread:nonce=b74397fa766b82c9">tag:shitposter.club,2017-05-05:objectType=thread:nonce=b74397fa766b82c9</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828128.atom"/> - <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828128.atom"/> - <statusnet:notice_info local_id="2828128" source="Qvitter"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:shitposter.club,2017-05-05:noticeId=2828104:objectType=note</id> - <title>New note by moonman</title> - <content type="html"><a href="https://shitposter.club/file/4d34178bde99599f31a28928e1666fbd58448d8a22e94ed82222496e4a45cb07.gif" title="https://shitposter.club/file/4d34178bde99599f31a28928e1666fbd58448d8a22e94ed82222496e4a45cb07.gif" class="attachment" id="attachment-662049" rel="nofollow external">https://shitposter.club/attachment/662049</a></content> - <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2828104"/> - <status_net notice_id="2828104"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-05-05T09:21:01+00:00</published> - <updated>2017-05-05T09:21:01+00:00</updated> - <link rel="ostatus:conversation" href="https://shitposter.club/conversation/1390624"/> - <ostatus:conversation href="https://shitposter.club/conversation/1390624" local_id="1390624" ref="tag:shitposter.club,2017-05-05:objectType=thread:nonce=d7aa6b5b057ca555">tag:shitposter.club,2017-05-05:objectType=thread:nonce=d7aa6b5b057ca555</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="enclosure" href="https://shitposter.club/file/4d34178bde99599f31a28928e1666fbd58448d8a22e94ed82222496e4a45cb07.gif" type="image/gif" length="278366"/> - <link rel="self" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828104.atom"/> - <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828104.atom"/> - <statusnet:notice_info local_id="2828104" source="Qvitter"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:shitposter.club,2017-05-05:noticeId=2828102:objectType=note</id> - <title>New note by moonman</title> - <content type="html">when ppl find out i haven't always been serious <a href="https://shitposter.club/file/5859fa95875342cc65dba0d852f726db158ce28198c326d5f13d9de7c0d2c449.gif" title="https://shitposter.club/file/5859fa95875342cc65dba0d852f726db158ce28198c326d5f13d9de7c0d2c449.gif" class="attachment" id="attachment-662053" rel="nofollow external">https://shitposter.club/attachment/662053</a></content> - <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2828102"/> - <status_net notice_id="2828102"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-05-05T09:20:45+00:00</published> - <updated>2017-05-05T09:20:45+00:00</updated> - <link rel="ostatus:conversation" href="https://shitposter.club/conversation/1390622"/> - <ostatus:conversation href="https://shitposter.club/conversation/1390622" local_id="1390622" ref="tag:shitposter.club,2017-05-05:objectType=thread:nonce=0a025ac5a570b4ec">tag:shitposter.club,2017-05-05:objectType=thread:nonce=0a025ac5a570b4ec</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="enclosure" href="https://shitposter.club/file/5859fa95875342cc65dba0d852f726db158ce28198c326d5f13d9de7c0d2c449.gif" type="image/gif" length="119239"/> - <link rel="self" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828102.atom"/> - <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828102.atom"/> - <statusnet:notice_info local_id="2828102" source="Qvitter"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>tag:shitposter.club,2017-05-05:noticeId=2828086:objectType=comment</id> - <title>New comment by moonman</title> - <content type="html">@<a href="https://shitposter.club/user/9655" class="h-card mention" title="Solidarity for Pigs">neimzr4luzerz</a> @<a href="https://gs.smuglo.li/user/2326" class="h-card mention" title="Dolus_McHonest">dolus</a> @<a href="https://gs.smuglo.li/user/35497" class="h-card mention" title="Bokuro Bokusawa">boco</a> you are being too serious lol</content> - <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2828086"/> - <status_net notice_id="2828086"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-05-05T09:17:19+00:00</published> - <updated>2017-05-05T09:17:19+00:00</updated> - <thr:in-reply-to ref="tag:shitposter.club,2017-05-05:noticeId=2828082:objectType=comment" href="https://shitposter.club/notice/2828082"></thr:in-reply-to> - <link rel="related" href="https://shitposter.club/notice/2828082"/> - <link rel="ostatus:conversation" href="https://shitposter.club/conversation/1390270"/> - <ostatus:conversation href="https://shitposter.club/conversation/1390270" local_id="1390270" ref="tag:shitposter.club,2017-05-05:objectType=thread:nonce=3c16e9c2681f6d26">tag:shitposter.club,2017-05-05:objectType=thread:nonce=3c16e9c2681f6d26</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://gs.smuglo.li/user/2326"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://shitposter.club/user/9655"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://gs.smuglo.li/user/35497"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828086.atom"/> - <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828086.atom"/> - <statusnet:notice_info local_id="2828086" source="Qvitter"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:shitposter.club,2017-05-05:noticeId=2828085:objectType=note</id> - <title>New note by moonman</title> - <content type="html">shitposter dot club <a href="https://shitposter.club/file/9b084c7210b16abbf4d28594b924a07ef4a2a06f89d901a4c42fb1e243291263.gif" title="https://shitposter.club/file/9b084c7210b16abbf4d28594b924a07ef4a2a06f89d901a4c42fb1e243291263.gif" class="attachment" id="attachment-662047" rel="nofollow external">https://shitposter.club/attachment/662047</a></content> - <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2828085"/> - <status_net notice_id="2828085"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-05-05T09:16:50+00:00</published> - <updated>2017-05-05T09:16:50+00:00</updated> - <link rel="ostatus:conversation" href="https://shitposter.club/conversation/1390613"/> - <ostatus:conversation href="https://shitposter.club/conversation/1390613" local_id="1390613" ref="tag:shitposter.club,2017-05-05:objectType=thread:nonce=d1ae088a1b91e5e5">tag:shitposter.club,2017-05-05:objectType=thread:nonce=d1ae088a1b91e5e5</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="enclosure" href="https://shitposter.club/file/9b084c7210b16abbf4d28594b924a07ef4a2a06f89d901a4c42fb1e243291263.gif" type="image/gif" length="681847"/> - <link rel="self" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828085.atom"/> - <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828085.atom"/> - <statusnet:notice_info local_id="2828085" source="Qvitter"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:shitposter.club,2017-05-05:noticeId=2828061:objectType=note</id> - <title>New note by moonman</title> - <content type="html">even when i lie i tell the truth, is that so hard to understand?</content> - <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2828061"/> - <status_net notice_id="2828061"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-05-05T09:15:07+00:00</published> - <updated>2017-05-05T09:15:07+00:00</updated> - <link rel="ostatus:conversation" href="https://shitposter.club/conversation/1390593"/> - <ostatus:conversation href="https://shitposter.club/conversation/1390593" local_id="1390593" ref="tag:shitposter.club,2017-05-05:objectType=thread:nonce=a516e4b8506b8ef5">tag:shitposter.club,2017-05-05:objectType=thread:nonce=a516e4b8506b8ef5</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828061.atom"/> - <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828061.atom"/> - <statusnet:notice_info local_id="2828061" source="Qvitter"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>tag:shitposter.club,2017-05-05:noticeId=2828052:objectType=comment</id> - <title>New comment by moonman</title> - <content type="html">@<a href="https://shitposter.club/user/9591" class="h-card mention" title="warum hei&#xDF;en deutschl&#xE4;nder deutschl&#xE4;nder">hardbass2k8</a> history, anthropology.</content> - <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2828052"/> - <status_net notice_id="2828052"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-05-05T09:14:22+00:00</published> - <updated>2017-05-05T09:14:22+00:00</updated> - <thr:in-reply-to ref="tag:shitposter.club,2017-05-05:noticeId=2828048:objectType=comment" href="https://shitposter.club/notice/2828048"></thr:in-reply-to> - <link rel="related" href="https://shitposter.club/notice/2828048"/> - <link rel="ostatus:conversation" href="https://shitposter.club/conversation/1390564"/> - <ostatus:conversation href="https://shitposter.club/conversation/1390564" local_id="1390564" ref="tag:shitposter.club,2017-05-05:objectType=thread:nonce=fe4d7f35b13403ba">tag:shitposter.club,2017-05-05:objectType=thread:nonce=fe4d7f35b13403ba</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://shitposter.club/user/9591"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828052.atom"/> - <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828052.atom"/> - <statusnet:notice_info local_id="2828052" source="Qvitter"></statusnet:notice_info> -</entry> -</feed> diff --git a/test/fixtures/tesla_mock/https___shitposter.club_notice_2827873.json b/test/fixtures/tesla_mock/https___shitposter.club_notice_2827873.json deleted file mode 100644 index 4b7b4df44..000000000 --- a/test/fixtures/tesla_mock/https___shitposter.club_notice_2827873.json +++ /dev/null @@ -1 +0,0 @@ -{"@context":["https://www.w3.org/ns/activitystreams","https://shitposter.club/schemas/litepub-0.1.jsonld",{"@language":"und"}],"actor":"https://shitposter.club/users/moonman","attachment":[],"attributedTo":"https://shitposter.club/users/moonman","cc":["https://shitposter.club/users/moonman/followers"],"content":"@<a href=\"https://shitposter.club/users/9655\" class=\"h-card mention\" title=\"Solidarity for Pigs\">neimzr4luzerz</a> @<a href=\"https://gs.smuglo.li/user/2326\" class=\"h-card mention\" title=\"Dolus_McHonest\">dolus</a> childhood poring over Strong's concordance and a koine Greek dictionary, fast forward to 2017 and some fuckstick who translates japanese jackoff material tells me you just need to make it sound right in English","context":"tag:shitposter.club,2017-05-05:objectType=thread:nonce=3c16e9c2681f6d26","conversation":"tag:shitposter.club,2017-05-05:objectType=thread:nonce=3c16e9c2681f6d26","id":"tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment","inReplyTo":"tag:shitposter.club,2017-05-05:noticeId=2827849:objectType=comment","inReplyToStatusId":2827849,"published":"2017-05-05T08:51:48Z","sensitive":false,"summary":null,"tag":[],"to":["https://www.w3.org/ns/activitystreams#Public"],"type":"Note"}
\ No newline at end of file diff --git a/test/fixtures/tesla_mock/https___social.heldscal.la_api_statuses_user_timeline_23211.atom.xml b/test/fixtures/tesla_mock/https___social.heldscal.la_api_statuses_user_timeline_23211.atom.xml deleted file mode 100644 index 6cba5c28f..000000000 --- a/test/fixtures/tesla_mock/https___social.heldscal.la_api_statuses_user_timeline_23211.atom.xml +++ /dev/null @@ -1,591 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:georss="http://www.georss.org/georss" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:media="http://purl.org/syndication/atommedia" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:statusnet="http://status.net/schema/api/1/"> - <generator uri="https://gnu.io/social" version="1.0.2-dev">GNU social</generator> - <id>https://social.heldscal.la/api/statuses/user_timeline/23211.atom</id> - <title>lambadalambda timeline</title> - <subtitle>Updates from lambadalambda on social.heldscal.la!</subtitle> - <logo>https://social.heldscal.la/avatar/23211-96-20170416114255.jpeg</logo> - <updated>2017-05-05T12:01:21+00:00</updated> -<author> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://social.heldscal.la/user/23211</uri> - <name>lambadalambda</name> - <summary>Call me Deacon Blues.</summary> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/lambadalambda"/> - <link rel="avatar" type="image/jpeg" media:width="236" media:height="236" href="https://social.heldscal.la/avatar/23211-original-20170416114255.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/23211-96-20170416114255.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="48" media:height="48" href="https://social.heldscal.la/avatar/23211-48-20170416114255.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="24" media:height="24" href="https://social.heldscal.la/avatar/23211-24-20170416114257.jpeg"/> - <poco:preferredUsername>lambadalambda</poco:preferredUsername> - <poco:displayName>Constance Variable</poco:displayName> - <poco:note>Call me Deacon Blues.</poco:note> - <poco:address> - <poco:formatted>Berlin</poco:formatted> - </poco:address> - <poco:urls> - <poco:type>homepage</poco:type> - <poco:value>https://heldscal.la</poco:value> - <poco:primary>true</poco:primary> - </poco:urls> - <followers url="https://social.heldscal.la/lambadalambda/subscribers"></followers> - <statusnet:profile_info local_id="23211"></statusnet:profile_info> -</author> - <link href="https://social.heldscal.la/lambadalambda" rel="alternate" type="text/html"/> - <link href="https://social.heldscal.la/main/sup" rel="http://api.friendfeed.com/2008/03#sup" type="application/json"/> - <link href="https://social.heldscal.la/api/statuses/user_timeline/23211.atom?max_id=2060731" rel="next" type="application/atom+xml"/> - <link href="https://social.heldscal.la/main/push/hub" rel="hub"/> - <link href="https://social.heldscal.la/main/salmon/user/23211" rel="salmon"/> - <link href="https://social.heldscal.la/main/salmon/user/23211" rel="http://salmon-protocol.org/ns/salmon-replies"/> - <link href="https://social.heldscal.la/main/salmon/user/23211" rel="http://salmon-protocol.org/ns/salmon-mention"/> - <link href="https://social.heldscal.la/api/statuses/user_timeline/23211.atom" rel="self" type="application/atom+xml"/> -<entry> - <id>tag:social.heldscal.la,2017-05-05:fave:23211:comment:2063249:2017-05-05T11:40:21+00:00</id> - <title>Favorite</title> - <content type="html">lambadalambda favorited something by tatiana: <p><span class="h-card"><a href="https://social.heldscal.la/lambadalambda" class="u-url mention">@<span>lambadalambda</span></a></span> they will start complaining about this, but won't come up with any solutions)</p></content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2063306"/> - <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb> - <published>2017-05-05T11:40:21+00:00</published> - <updated>2017-05-05T11:40:21+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>tag:social.weho.st,2017-05-05:objectId=172033:objectType=Status</id> - <title>New comment by tatiana</title> - <content type="html"><p><span class="h-card"><a href="https://social.heldscal.la/lambadalambda" class="u-url mention">@<span>lambadalambda</span></a></span> they will start complaining about this, but won't come up with any solutions)</p></content> - <link rel="alternate" type="text/html" href="https://social.weho.st/users/Tatiana/updates/2841"/> - <status_net notice_id="2063249"></status_net> - </activity:object> - <thr:in-reply-to ref="tag:social.weho.st,2017-05-05:objectId=172033:objectType=Status" href="https://social.weho.st/users/Tatiana/updates/2841"></thr:in-reply-to> - <link rel="related" href="https://social.weho.st/users/Tatiana/updates/2841"/> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1062581"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/1062581" local_id="1062581" ref="tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=e95b99adc050e198">tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=e95b99adc050e198</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2063306.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2063306.atom"/> - <statusnet:notice_info local_id="2063306" source="unknown"></statusnet:notice_info> -</entry> -<entry> - <id>tag:social.heldscal.la,2017-05-05:fave:23211:comment:2063041:2017-05-05T11:27:28+00:00</id> - <title>Favorite</title> - <content type="html">lambadalambda favorited something by kat: @<a href="https://social.heldscal.la/lambadalambda" class="h-card mention" title="Constance Variable">lambadalambda</a> if the admin reading mine would delete a few it would be really useful in prioritising. </content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2063148"/> - <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb> - <published>2017-05-05T11:27:28+00:00</published> - <updated>2017-05-05T11:27:28+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>tag:quitter.se,2017-05-05:noticeId=11807959:objectType=comment</id> - <title>New comment by kat</title> - <content type="html">@<a href="https://social.heldscal.la/lambadalambda" class="h-card mention" title="Constance Variable">lambadalambda</a> if the admin reading mine would delete a few it would be really useful in prioritising. </content> - <link rel="alternate" type="text/html" href="http://quitter.se/notice/11807959"/> - <status_net notice_id="2063041"></status_net> - </activity:object> - <thr:in-reply-to ref="tag:quitter.se,2017-05-05:noticeId=11807959:objectType=comment" href="http://quitter.se/notice/11807959"></thr:in-reply-to> - <link rel="related" href="http://quitter.se/notice/11807959"/> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1062581"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/1062581" local_id="1062581" ref="tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=e95b99adc050e198">tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=e95b99adc050e198</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2063148.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2063148.atom"/> - <statusnet:notice_info local_id="2063148" source="unknown"></statusnet:notice_info> -</entry> -<entry> - <id>tag:social.heldscal.la,2017-05-05:noticeId=2062924:objectType=note</id> - <title>lambadalambda repeated a notice by nielsk</title> - <content type="html">RT @nielsk @<a href="https://social.heldscal.la/user/23211" class="h-card u-url p-nickname mention" title="Constance Variable">lambadalambda</a> but there are soooo many, where should I start to read?</content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2062924"/> - <activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb> - <published>2017-05-05T11:09:37+00:00</published> - <updated>2017-05-05T11:09:37+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type> - <id>tag:mastodon.social,2017-05-05:objectId=5024471:objectType=Status</id> - <title></title> - <content type="html"><p><span class="h-card"><a href="https://social.heldscal.la/lambadalambda" class="u-url mention">@<span>lambadalambda</span></a></span> but there are soooo many, where should I start to read?</p></content> - <link rel="alternate" type="text/html" href="https://mastodon.social/users/nielsk/updates/2256348"/> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-05-05T11:05:18+00:00</published> - <updated>2017-05-05T11:05:18+00:00</updated> - <author> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://mastodon.social/users/nielsk</uri> - <name>nielsk</name> - <summary>Sysadmin by day and ehm… sysadmin by night. Besides that old video games, Japan, economics and some other stuff</summary> - <link rel="alternate" type="text/html" href="https://mastodon.social/@nielsk"/> - <link rel="avatar" type="image/jpeg" media:width="120" media:height="120" href="https://social.heldscal.la/avatar/29849-original-20170428120037.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/29849-96-20170428120041.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="48" media:height="48" href="https://social.heldscal.la/avatar/29849-48-20170428120041.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="24" media:height="24" href="https://social.heldscal.la/avatar/29849-24-20170429103753.jpeg"/> - <poco:preferredUsername>nielsk</poco:preferredUsername> - <poco:displayName>nielsk</poco:displayName> - <poco:note>Sysadmin by day and ehm… sysadmin by night. Besides that old video games, Japan, economics and some other stuff</poco:note> - <statusnet:profile_info local_id="29849"></statusnet:profile_info> - </author> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>tag:mastodon.social,2017-05-05:objectId=5024471:objectType=Status</id> - <title>New comment by nielsk</title> - <content type="html"><p><span class="h-card"><a href="https://social.heldscal.la/lambadalambda" class="u-url mention">@<span>lambadalambda</span></a></span> but there are soooo many, where should I start to read?</p></content> - <link rel="alternate" type="text/html" href="https://mastodon.social/users/nielsk/updates/2256348"/> - <status_net notice_id="2062875"></status_net> - </activity:object> - <thr:in-reply-to ref="tag:social.heldscal.la,2017-05-05:noticeId=2062583:objectType=note" href="https://social.heldscal.la/notice/2062583"></thr:in-reply-to> - <link rel="related" href="https://social.heldscal.la/notice/2062583"/> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1062581"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/1062581" local_id="1062581" ref="tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=e95b99adc050e198">tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=e95b99adc050e198</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://social.heldscal.la/user/23211"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <source> - <id>https://mastodon.social/users/nielsk.atom</id> - <title>nielsk</title> - <link rel="alternate" type="text/html" href="https://mastodon.social/@nielsk"/> - <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/nielsk.atom"/> - <icon>https://social.heldscal.la/avatar/29849-96-20170428120041.jpeg</icon> - <updated>2017-05-05T11:06:32+00:00</updated> - </source> - </activity:object> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1062581"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/1062581" local_id="1062581" ref="tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=e95b99adc050e198">tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=e95b99adc050e198</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2062924.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2062924.atom"/> - <statusnet:notice_info local_id="2062924" source="api" repeat_of="2062875"></statusnet:notice_info> -</entry> -<entry> - <id>tag:social.heldscal.la,2017-05-05:fave:23211:comment:2062875:2017-05-05T11:09:27+00:00</id> - <title>Favorite</title> - <content type="html">lambadalambda favorited something by nielsk: <p><span class="h-card"><a href="https://social.heldscal.la/lambadalambda" class="u-url mention">@<span>lambadalambda</span></a></span> but there are soooo many, where should I start to read?</p></content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2062923"/> - <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb> - <published>2017-05-05T11:09:27+00:00</published> - <updated>2017-05-05T11:09:27+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>tag:mastodon.social,2017-05-05:objectId=5024471:objectType=Status</id> - <title>New comment by nielsk</title> - <content type="html"><p><span class="h-card"><a href="https://social.heldscal.la/lambadalambda" class="u-url mention">@<span>lambadalambda</span></a></span> but there are soooo many, where should I start to read?</p></content> - <link rel="alternate" type="text/html" href="https://mastodon.social/users/nielsk/updates/2256348"/> - <status_net notice_id="2062875"></status_net> - </activity:object> - <thr:in-reply-to ref="tag:mastodon.social,2017-05-05:objectId=5024471:objectType=Status" href="https://mastodon.social/users/nielsk/updates/2256348"></thr:in-reply-to> - <link rel="related" href="https://mastodon.social/users/nielsk/updates/2256348"/> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1062581"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/1062581" local_id="1062581" ref="tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=e95b99adc050e198">tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=e95b99adc050e198</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2062923.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2062923.atom"/> - <statusnet:notice_info local_id="2062923" source="unknown"></statusnet:notice_info> -</entry> -<entry> - <id>tag:social.heldscal.la,2017-05-05:fave:23211:comment:2062863:2017-05-05T11:09:11+00:00</id> - <title>Favorite</title> - <content type="html">lambadalambda favorited something by kasil: <p><span class="h-card"><a href="https://social.heldscal.la/lambadalambda" class="u-url mention">@<span>lambadalambda</span></a></span> surely, google is not that evil !</p></content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2062921"/> - <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb> - <published>2017-05-05T11:09:11+00:00</published> - <updated>2017-05-05T11:09:11+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>tag:loutre.info,2017-05-05:objectId=23331:objectType=Status</id> - <title>New comment by kasil</title> - <content type="html"><p><span class="h-card"><a href="https://social.heldscal.la/lambadalambda" class="u-url mention">@<span>lambadalambda</span></a></span> surely, google is not that evil !</p></content> - <link rel="alternate" type="text/html" href="https://loutre.info/users/Kasil/updates/159"/> - <status_net notice_id="2062863"></status_net> - </activity:object> - <thr:in-reply-to ref="tag:loutre.info,2017-05-05:objectId=23331:objectType=Status" href="https://loutre.info/users/Kasil/updates/159"></thr:in-reply-to> - <link rel="related" href="https://loutre.info/users/Kasil/updates/159"/> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1062581"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/1062581" local_id="1062581" ref="tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=e95b99adc050e198">tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=e95b99adc050e198</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2062921.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2062921.atom"/> - <statusnet:notice_info local_id="2062921" source="unknown"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>tag:social.heldscal.la,2017-05-05:noticeId=2062767:objectType=comment</id> - <title>New comment by lambadalambda</title> - <content type="html">@<a href="https://sealion.club/user/4" class="h-card u-url p-nickname mention" title="dewoo &#x274E;">dwmatiz</a> dunno, probably.</content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2062767"/> - <status_net notice_id="2062767"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-05-05T10:55:17+00:00</published> - <updated>2017-05-05T10:55:17+00:00</updated> - <thr:in-reply-to ref="tag:sealion.club,2017-05-05:noticeId=3183881:objectType=comment" href="https://sealion.club/notice/3183881"></thr:in-reply-to> - <link rel="related" href="https://sealion.club/notice/3183881"/> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1062581"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/1062581" local_id="1062581" ref="tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=e95b99adc050e198">tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=e95b99adc050e198</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://sealion.club/user/4"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2062767.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2062767.atom"/> - <statusnet:notice_info local_id="2062767" source="Pleroma FE"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>tag:social.heldscal.la,2017-05-05:noticeId=2062705:objectType=comment</id> - <title>New comment by lambadalambda</title> - <content type="html">@<a href="https://gs.smuglo.li/user/28250" class="h-card u-url p-nickname mention" title="Bricky">thatbrickster</a> I do it, too.</content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2062705"/> - <status_net notice_id="2062705"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-05-05T10:48:12+00:00</published> - <updated>2017-05-05T10:48:12+00:00</updated> - <thr:in-reply-to ref="tag:gs.smuglo.li,2017-05-05:noticeId=2189353:objectType=comment" href="https://gs.smuglo.li/notice/2189353"></thr:in-reply-to> - <link rel="related" href="https://gs.smuglo.li/notice/2189353"/> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1062581"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/1062581" local_id="1062581" ref="tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=e95b99adc050e198">tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=e95b99adc050e198</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://gs.smuglo.li/user/28250"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2062705.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2062705.atom"/> - <statusnet:notice_info local_id="2062705" source="Pleroma FE"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>tag:social.heldscal.la,2017-05-05:noticeId=2062620:objectType=comment</id> - <title>New comment by lambadalambda</title> - <content type="html">@<a href="https://social.tchncs.de/users/israuor" class="h-card u-url p-nickname mention" title="Israuor &#x2642;">israuor</a> @<a href="https://mastodon.gougere.fr/users/bortzmeyer" class="h-card u-url p-nickname mention" title="S. Bortzmeyer &#x2705;">bortzmeyer</a> so, 99%. 100% for 'normal' people.</content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2062620"/> - <status_net notice_id="2062620"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-05-05T10:38:52+00:00</published> - <updated>2017-05-05T10:38:52+00:00</updated> - <thr:in-reply-to ref="tag:social.tchncs.de,2017-05-05:objectId=1667119:objectType=Status" href="https://social.tchncs.de/users/israuor/updates/74901"></thr:in-reply-to> - <link rel="related" href="https://social.tchncs.de/users/israuor/updates/74901"/> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1062581"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/1062581" local_id="1062581" ref="tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=e95b99adc050e198">tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=e95b99adc050e198</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://social.tchncs.de/users/israuor"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.gougere.fr/users/bortzmeyer"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2062620.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2062620.atom"/> - <statusnet:notice_info local_id="2062620" source="Pleroma FE"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:social.heldscal.la,2017-05-05:noticeId=2062583:objectType=note</id> - <title>New note by lambadalambda</title> - <content type="html">I wonder what'll happen when people realize the admin at their mail hoster can read all their e-mails.</content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2062583"/> - <status_net notice_id="2062583"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-05-05T10:35:45+00:00</published> - <updated>2017-05-05T10:35:45+00:00</updated> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1062581"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/1062581" local_id="1062581" ref="tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=e95b99adc050e198">tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=e95b99adc050e198</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2062583.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2062583.atom"/> - <statusnet:notice_info local_id="2062583" source="Pleroma FE"></statusnet:notice_info> -</entry> -<entry> - <id>tag:social.heldscal.la,2017-05-05:subscription:23211:person:35708:2017-05-05T09:34:46+00:00</id> - <title>Constance Variable (lambadalambda@social.heldscal.la)'s status on Friday, 05-May-2017 09:34:46 UTC</title> - <content type="html"><a href="https://social.heldscal.la/lambadalambda">Constance Variable</a> started following <a href="https://mastodon.social/@milouse">milouse</a>.</content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2062053"/> - <activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb> - <published>2017-05-05T09:34:46+00:00</published> - <updated>2017-05-05T09:34:46+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <id>https://mastodon.social/users/milouse</id> - <title>milouse</title> - <summary>#Scout leader #sgdf, interested in #openweb, #semanticweb, #privacy, #foss and #socialeconomy. 0xA714ECAC8C9CEE3D</summary> - <link rel="alternate" type="text/html" href="https://mastodon.social/@milouse"/> - <link rel="avatar" type="image/png" media:width="120" media:height="120" href="https://social.heldscal.la/avatar/35708-original-20170505105902.png"/> - <link rel="avatar" type="image/png" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/35708-96-20170505105911.png"/> - <link rel="avatar" type="image/png" media:width="48" media:height="48" href="https://social.heldscal.la/avatar/35708-48-20170505105911.png"/> - <link rel="avatar" type="image/png" media:width="24" media:height="24" href="https://social.heldscal.la/avatar/35708-24-20170505105938.png"/> - <poco:preferredUsername>milouse</poco:preferredUsername> - <poco:displayName>milouse</poco:displayName> - <poco:note>#Scout leader #sgdf, interested in #openweb, #semanticweb, #privacy, #foss and #socialeconomy. 0xA714ECAC8C9CEE3D</poco:note> - </activity:object> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1062248"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/1062248" local_id="1062248" ref="tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=26ca19a355bb6135">tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=26ca19a355bb6135</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2062053.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2062053.atom"/> - <statusnet:notice_info local_id="2062053" source="activity"></statusnet:notice_info> -</entry> -<entry> - <id>tag:social.heldscal.la,2017-05-05:noticeId=2061871:objectType=note</id> - <title>lambadalambda repeated a notice by safebot</title> - <content type="html">RT @<a href="https://gs.smuglo.li/user/25857" class="h-card u-url p-nickname mention" title="safebot">safebot</a> #<span class="tag"><a href="https://social.heldscal.la/tag/cheers" rel="tag">cheers</a></span> <a href="https://gs.smuglo.li/attachment/456444" title="https://gs.smuglo.li/attachment/456444" rel="nofollow external noreferrer" class="attachment" id="attachment-432334">https://gs.smuglo.li/attachment/456444</a></content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2061871"/> - <activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb> - <published>2017-05-05T09:16:17+00:00</published> - <updated>2017-05-05T09:16:17+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type> - <id>tag:gs.smuglo.li,2017-05-05:noticeId=2188073:objectType=note</id> - <title></title> - <content type="html">#<span class="tag"><a href="https://gs.smuglo.li/tag/cheers" rel="tag">cheers</a></span> <a href="https://gs.smuglo.li/file/5099e73c83da778cd032a721e96880f99a868b712be2975d08238547a5ba06c7.jpg" title="https://gs.smuglo.li/file/5099e73c83da778cd032a721e96880f99a868b712be2975d08238547a5ba06c7.jpg" rel="nofollow noreferrer" class="attachment">https://gs.smuglo.li/attachment/456444</a></content> - <link rel="alternate" type="text/html" href="https://gs.smuglo.li/notice/2188073"/> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-05-05T08:36:53+00:00</published> - <updated>2017-05-05T08:36:53+00:00</updated> - <author> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://gs.smuglo.li/user/25857</uri> - <name>safebot</name> - <link rel="alternate" type="text/html" href="https://gs.smuglo.li/safebot"/> - <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/25719-original-20161215233234.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/25719-original-20161215233234.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="48" media:height="48" href="https://social.heldscal.la/avatar/25719-48-20161215233239.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="24" media:height="24" href="https://social.heldscal.la/avatar/25719-24-20161215235533.jpeg"/> - <poco:preferredUsername>safebot</poco:preferredUsername> - <poco:displayName>safebot</poco:displayName> - <statusnet:profile_info local_id="25719"></statusnet:profile_info> - </author> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:gs.smuglo.li,2017-05-05:noticeId=2188073:objectType=note</id> - <title>New note by safebot</title> - <content type="html">#<span class="tag"><a href="https://gs.smuglo.li/tag/cheers" rel="tag">cheers</a></span> <a href="https://gs.smuglo.li/file/5099e73c83da778cd032a721e96880f99a868b712be2975d08238547a5ba06c7.jpg" title="https://gs.smuglo.li/file/5099e73c83da778cd032a721e96880f99a868b712be2975d08238547a5ba06c7.jpg" rel="nofollow noreferrer" class="attachment">https://gs.smuglo.li/attachment/456444</a></content> - <link rel="alternate" type="text/html" href="https://gs.smuglo.li/notice/2188073"/> - <status_net notice_id="2061504"></status_net> - </activity:object> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1061934"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/1061934" local_id="1061934" ref="https://gs.smuglo.li/conversation/1009429">https://gs.smuglo.li/conversation/1009429</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <category term="cheers"></category> - <source> - <id>https://gs.smuglo.li/api/statuses/user_timeline/25857.atom</id> - <title>safebot</title> - <link rel="alternate" type="text/html" href="https://gs.smuglo.li/safebot"/> - <link rel="self" type="application/atom+xml" href="https://gs.smuglo.li/api/statuses/user_timeline/25857.atom"/> - <icon>https://social.heldscal.la/avatar/25719-original-20161215233234.jpeg</icon> - <updated>2017-05-05T12:00:57+00:00</updated> - </source> - </activity:object> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1061934"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/1061934" local_id="1061934" ref="https://gs.smuglo.li/conversation/1009429">https://gs.smuglo.li/conversation/1009429</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2061871.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2061871.atom"/> - <statusnet:notice_info local_id="2061871" source="api" repeat_of="2061504"></statusnet:notice_info> -</entry> -<entry> - <id>tag:social.heldscal.la,2017-05-05:fave:23211:comment:2061643:2017-05-05T09:12:50+00:00</id> - <title>Favorite</title> - <content type="html">lambadalambda favorited something by moonman: @<a href="https://shitposter.club/user/9655" class="h-card mention" title="Solidarity for Pigs">neimzr4luzerz</a> @<a href="https://gs.smuglo.li/user/2326" class="h-card mention" title="Dolus_McHonest">dolus</a> childhood poring over Strong's concordance and a koine Greek dictionary, fast forward to 2017 and some fuckstick who translates japanese jackoff material tells me you just need to make it sound right in English</content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2061828"/> - <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb> - <published>2017-05-05T09:12:50+00:00</published> - <updated>2017-05-05T09:12:50+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment</id> - <title>New comment by moonman</title> - <content type="html">@<a href="https://shitposter.club/user/9655" class="h-card mention" title="Solidarity for Pigs">neimzr4luzerz</a> @<a href="https://gs.smuglo.li/user/2326" class="h-card mention" title="Dolus_McHonest">dolus</a> childhood poring over Strong's concordance and a koine Greek dictionary, fast forward to 2017 and some fuckstick who translates japanese jackoff material tells me you just need to make it sound right in English</content> - <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2827873"/> - <status_net notice_id="2061643"></status_net> - </activity:object> - <thr:in-reply-to ref="tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment" href="https://shitposter.club/notice/2827873"></thr:in-reply-to> - <link rel="related" href="https://shitposter.club/notice/2827873"/> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1061781"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/1061781" local_id="1061781" ref="tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=55ead90125cd4bd4">tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=55ead90125cd4bd4</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2061828.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2061828.atom"/> - <statusnet:notice_info local_id="2061828" source="unknown"></statusnet:notice_info> -</entry> -<entry> - <id>tag:social.heldscal.la,2017-05-05:fave:23211:comment:2061696:2017-05-05T09:06:10+00:00</id> - <title>Favorite</title> - <content type="html">lambadalambda favorited something by moonman: @<a href="https://shitposter.club/user/9655" class="h-card mention" title="Solidarity for Pigs">neimzr4luzerz</a> <br /> <span class="greentext">&gt; (((common era)))</span></content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2061781"/> - <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb> - <published>2017-05-05T09:06:10+00:00</published> - <updated>2017-05-05T09:06:10+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>tag:shitposter.club,2017-05-05:noticeId=2827918:objectType=comment</id> - <title>New comment by moonman</title> - <content type="html">@<a href="https://shitposter.club/user/9655" class="h-card mention" title="Solidarity for Pigs">neimzr4luzerz</a> <br /> <span class="greentext">&gt; (((common era)))</span></content> - <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2827918"/> - <status_net notice_id="2061696"></status_net> - </activity:object> - <thr:in-reply-to ref="tag:shitposter.club,2017-05-05:noticeId=2827918:objectType=comment" href="https://shitposter.club/notice/2827918"></thr:in-reply-to> - <link rel="related" href="https://shitposter.club/notice/2827918"/> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1061781"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/1061781" local_id="1061781" ref="tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=55ead90125cd4bd4">tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=55ead90125cd4bd4</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2061781.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2061781.atom"/> - <statusnet:notice_info local_id="2061781" source="unknown"></statusnet:notice_info> -</entry> -<entry> - <id>tag:social.heldscal.la,2017-05-05:fave:23211:note:2061673:2017-05-05T08:58:28+00:00</id> - <title>Favorite</title> - <content type="html">lambadalambda favorited something by moonman: discussion is one thing but any argument I've heard over and over again for the last three decades is going to go unanswered.</content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2061702"/> - <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb> - <published>2017-05-05T08:58:28+00:00</published> - <updated>2017-05-05T08:58:28+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:shitposter.club,2017-05-05:noticeId=2827895:objectType=note</id> - <title>New note by moonman</title> - <content type="html">discussion is one thing but any argument I've heard over and over again for the last three decades is going to go unanswered.</content> - <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2827895"/> - <status_net notice_id="2061673"></status_net> - </activity:object> - <thr:in-reply-to ref="tag:shitposter.club,2017-05-05:noticeId=2827895:objectType=note" href="https://shitposter.club/notice/2827895"></thr:in-reply-to> - <link rel="related" href="https://shitposter.club/notice/2827895"/> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1062026"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/1062026" local_id="1062026" ref="https://shitposter.club/conversation/1390494">https://shitposter.club/conversation/1390494</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2061702.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2061702.atom"/> - <statusnet:notice_info local_id="2061702" source="unknown"></statusnet:notice_info> -</entry> -<entry> - <id>tag:social.heldscal.la,2017-05-05:fave:23211:comment:2061280:2017-05-05T08:47:38+00:00</id> - <title>Favorite</title> - <content type="html">lambadalambda favorited something by moonman: @<a href="https://shitposter.club/user/9655" class="h-card mention" title="Solidarity for Pigs">neimzr4luzerz</a> sex is for procreation and as an expression of intimacy between commited couples, it is a sacramental act</content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2061614"/> - <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb> - <published>2017-05-05T08:47:38+00:00</published> - <updated>2017-05-05T08:47:38+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>tag:shitposter.club,2017-05-05:noticeId=2827561:objectType=comment</id> - <title>New comment by moonman</title> - <content type="html">@<a href="https://shitposter.club/user/9655" class="h-card mention" title="Solidarity for Pigs">neimzr4luzerz</a> sex is for procreation and as an expression of intimacy between commited couples, it is a sacramental act</content> - <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2827561"/> - <status_net notice_id="2061280"></status_net> - </activity:object> - <thr:in-reply-to ref="tag:shitposter.club,2017-05-05:noticeId=2827561:objectType=comment" href="https://shitposter.club/notice/2827561"></thr:in-reply-to> - <link rel="related" href="https://shitposter.club/notice/2827561"/> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1061781"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/1061781" local_id="1061781" ref="tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=55ead90125cd4bd4">tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=55ead90125cd4bd4</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2061614.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2061614.atom"/> - <statusnet:notice_info local_id="2061614" source="unknown"></statusnet:notice_info> -</entry> -<entry> - <id>tag:social.heldscal.la,2017-05-05:fave:23211:note:2061535:2017-05-05T08:40:55+00:00</id> - <title>Favorite</title> - <content type="html">lambadalambda favorited something by fortune: What did Mickey Mouse get for Christmas?<br /> <br /> A Dan Quayle watch.<br /> <br /> -- heard from a Mike Dukakis field worker</content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2061544"/> - <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb> - <published>2017-05-05T08:40:55+00:00</published> - <updated>2017-05-05T08:40:55+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:social.heldscal.la,2017-05-05:noticeId=2061535:objectType=note</id> - <title>New note by fortune</title> - <content type="html">What did Mickey Mouse get for Christmas?<br /> <br /> A Dan Quayle watch.<br /> <br /> -- heard from a Mike Dukakis field worker</content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2061535"/> - <status_net notice_id="2061535"></status_net> - </activity:object> - <thr:in-reply-to ref="tag:social.heldscal.la,2017-05-05:noticeId=2061535:objectType=note" href="https://social.heldscal.la/notice/2061535"></thr:in-reply-to> - <link rel="related" href="https://social.heldscal.la/notice/2061535"/> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1061954"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/1061954" local_id="1061954" ref="tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=5185e5c145ee4762">tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=5185e5c145ee4762</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2061544.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2061544.atom"/> - <statusnet:notice_info local_id="2061544" source="unknown"></statusnet:notice_info> -</entry> -<entry> - <id>tag:social.heldscal.la,2017-05-05:fave:23211:comment:2061421:2017-05-05T08:36:27+00:00</id> - <title>Favorite</title> - <content type="html">lambadalambda favorited something by moonman: @<a href="https://maly.io/users/sonya" class="h-card mention" title="Sonya Mann ✅">sonya</a> banned from 4chan. you better watch ou. i'm trouble, y'hear?</content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2061495"/> - <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb> - <published>2017-05-05T08:36:27+00:00</published> - <updated>2017-05-05T08:36:27+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>tag:shitposter.club,2017-05-05:noticeId=2827689:objectType=comment</id> - <title>New comment by moonman</title> - <content type="html">@<a href="https://maly.io/users/sonya" class="h-card mention" title="Sonya Mann ✅">sonya</a> banned from 4chan. you better watch ou. i'm trouble, y'hear?</content> - <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2827689"/> - <status_net notice_id="2061421"></status_net> - </activity:object> - <thr:in-reply-to ref="tag:shitposter.club,2017-05-05:noticeId=2827689:objectType=comment" href="https://shitposter.club/notice/2827689"></thr:in-reply-to> - <link rel="related" href="https://shitposter.club/notice/2827689"/> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1060861"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/1060861" local_id="1060861" ref="https://shitposter.club/conversation/1389345">https://shitposter.club/conversation/1389345</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2061495.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2061495.atom"/> - <statusnet:notice_info local_id="2061495" source="unknown"></statusnet:notice_info> -</entry> -<entry> - <id>tag:social.heldscal.la,2017-05-05:fave:23211:comment:2061351:2017-05-05T08:28:03+00:00</id> - <title>Favorite</title> - <content type="html">lambadalambda favorited something by moonman: @<a href="https://social.heldscal.la/user/29138" class="h-card mention" title="Claes Wallin (韋嘉誠)">clacke</a> is that the sequel to Time Crisis</content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2061410"/> - <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb> - <published>2017-05-05T08:28:03+00:00</published> - <updated>2017-05-05T08:28:03+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>tag:shitposter.club,2017-05-05:noticeId=2827630:objectType=comment</id> - <title>New comment by moonman</title> - <content type="html">@<a href="https://social.heldscal.la/user/29138" class="h-card mention" title="Claes Wallin (韋嘉誠)">clacke</a> is that the sequel to Time Crisis</content> - <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2827630"/> - <status_net notice_id="2061351"></status_net> - </activity:object> - <thr:in-reply-to ref="tag:shitposter.club,2017-05-05:noticeId=2827630:objectType=comment" href="https://shitposter.club/notice/2827630"></thr:in-reply-to> - <link rel="related" href="https://shitposter.club/notice/2827630"/> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1056672"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/1056672" local_id="1056672" ref="https://shitposter.club/conversation/1385528">https://shitposter.club/conversation/1385528</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2061410.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2061410.atom"/> - <statusnet:notice_info local_id="2061410" source="unknown"></statusnet:notice_info> -</entry> -<entry> - <id>tag:social.heldscal.la,2017-05-05:fave:23211:comment:2061339:2017-05-05T08:21:05+00:00</id> - <title>Favorite</title> - <content type="html">lambadalambda favorited something by hardbass2k8: @<a href="https://social.heldscal.la/user/23211" class="h-card mention" title="Constance Variable">lambadalambda</a> pretty sure it's money laundering</content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2061357"/> - <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb> - <published>2017-05-05T08:21:05+00:00</published> - <updated>2017-05-05T08:21:05+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>tag:shitposter.club,2017-05-05:noticeId=2827617:objectType=comment</id> - <title>New comment by hardbass2k8</title> - <content type="html">@<a href="https://social.heldscal.la/user/23211" class="h-card mention" title="Constance Variable">lambadalambda</a> pretty sure it's money laundering</content> - <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2827617"/> - <status_net notice_id="2061339"></status_net> - </activity:object> - <thr:in-reply-to ref="tag:shitposter.club,2017-05-05:noticeId=2827617:objectType=comment" href="https://shitposter.club/notice/2827617"></thr:in-reply-to> - <link rel="related" href="https://shitposter.club/notice/2827617"/> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1059050"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/1059050" local_id="1059050" ref="https://shitposter.club/conversation/1387523">https://shitposter.club/conversation/1387523</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2061357.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2061357.atom"/> - <statusnet:notice_info local_id="2061357" source="unknown"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:social.heldscal.la,2017-05-05:noticeId=2061303:objectType=note</id> - <title>New note by lambadalambda</title> - <content type="html">It's got tattoos, it's got a pierced hood<br /> It's got generation X<br /> It's got lesbians, and vitriol<br /> And sadomasochistic latex sex<br /> It's got Mighty Morphin' power brokers<br /> And Tanya Harding nude<br /> Macrobiotic lacto-vegan non-confrontational free range food<br /> It's got the handshake, peace talk, non-aggression pact<br /> A multicultural integration of segregated historical facts<br /> <br /> #<span class="tag"><a href="https://social.heldscal.la/tag/nsfw" rel="tag">nsfw</a></span> <a href="https://social.heldscal.la/file/61c13b99c92f40ec4865e7a3830da340b187e3de70d94b8da38fd2138bbede3a.jpg" title="https://social.heldscal.la/file/61c13b99c92f40ec4865e7a3830da340b187e3de70d94b8da38fd2138bbede3a.jpg" rel="nofollow external noreferrer" class="attachment" id="attachment-432199">https://social.heldscal.la/attachment/432199</a> <a href="https://social.heldscal.la/file/a88bba1a324da68ee2cfdbcd1c4cde60bd9553298244d6f81731270b71aa80df.jpg" title="https://social.heldscal.la/file/a88bba1a324da68ee2cfdbcd1c4cde60bd9553298244d6f81731270b71aa80df.jpg" rel="nofollow external noreferrer" class="attachment" id="attachment-432200">https://social.heldscal.la/attachment/432200</a> <a href="https://social.heldscal.la/file/887329a303250e73dc2eea06b1f0512fcac4b9d1b534068f03c45f00d5b21c39.jpg" title="https://social.heldscal.la/file/887329a303250e73dc2eea06b1f0512fcac4b9d1b534068f03c45f00d5b21c39.jpg" rel="nofollow external noreferrer" class="attachment" id="attachment-432201">https://social.heldscal.la/attachment/432201</a> <a href="https://social.heldscal.la/file/6d7a1ec15c1368c4c68810434d24da528606fcbccdd1da97b25affafeeb6ffda.jpg" title="https://social.heldscal.la/file/6d7a1ec15c1368c4c68810434d24da528606fcbccdd1da97b25affafeeb6ffda.jpg" rel="nofollow external noreferrer" class="attachment" id="attachment-432202">https://social.heldscal.la/attachment/432202</a> <a href="https://social.heldscal.la/file/2f55f2bb028eb9be744cc82b35a6b86b496d8c3924c700aff55a872ff11df54c.jpg" title="https://social.heldscal.la/file/2f55f2bb028eb9be744cc82b35a6b86b496d8c3924c700aff55a872ff11df54c.jpg" rel="nofollow external noreferrer" class="attachment" id="attachment-432203">https://social.heldscal.la/attachment/432203</a></content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2061303"/> - <status_net notice_id="2061303"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-05-05T08:17:08+00:00</published> - <updated>2017-05-05T08:17:08+00:00</updated> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1061817"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/1061817" local_id="1061817" ref="tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=bb6f4343036970e8">tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=bb6f4343036970e8</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <category term="nsfw"></category> - <link rel="enclosure" href="https://social.heldscal.la/file/61c13b99c92f40ec4865e7a3830da340b187e3de70d94b8da38fd2138bbede3a.jpg" type="image/jpeg" length="239712"/> - <link rel="enclosure" href="https://social.heldscal.la/file/a88bba1a324da68ee2cfdbcd1c4cde60bd9553298244d6f81731270b71aa80df.jpg" type="image/jpeg" length="185200"/> - <link rel="enclosure" href="https://social.heldscal.la/file/887329a303250e73dc2eea06b1f0512fcac4b9d1b534068f03c45f00d5b21c39.jpg" type="image/jpeg" length="292061"/> - <link rel="enclosure" href="https://social.heldscal.la/file/6d7a1ec15c1368c4c68810434d24da528606fcbccdd1da97b25affafeeb6ffda.jpg" type="image/jpeg" length="147280"/> - <link rel="enclosure" href="https://social.heldscal.la/file/2f55f2bb028eb9be744cc82b35a6b86b496d8c3924c700aff55a872ff11df54c.jpg" type="image/jpeg" length="164659"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2061303.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2061303.atom"/> - <statusnet:notice_info local_id="2061303" source="Pleroma FE"></statusnet:notice_info> -</entry> -</feed> diff --git a/test/fixtures/tesla_mock/https___social.heldscal.la_api_statuses_user_timeline_29191.atom.xml b/test/fixtures/tesla_mock/https___social.heldscal.la_api_statuses_user_timeline_29191.atom.xml deleted file mode 100644 index f70fbc695..000000000 --- a/test/fixtures/tesla_mock/https___social.heldscal.la_api_statuses_user_timeline_29191.atom.xml +++ /dev/null @@ -1,719 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:georss="http://www.georss.org/georss" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:media="http://purl.org/syndication/atommedia" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:statusnet="http://status.net/schema/api/1/"> - <generator uri="https://gnu.io/social" version="1.0.2-dev">GNU social</generator> - <id>https://social.heldscal.la/api/statuses/user_timeline/29191.atom</id> - <title>shp timeline</title> - <subtitle>Updates from shp on social.heldscal.la!</subtitle> - <logo>https://social.heldscal.la/avatar/29191-96-20170421154949.jpeg</logo> - <updated>2017-05-05T11:57:06+00:00</updated> -<author> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://social.heldscal.la/user/29191</uri> - <name>shp</name> - <summary>cofe</summary> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/shp"/> - <link rel="avatar" type="image/jpeg" media:width="735" media:height="735" href="https://social.heldscal.la/avatar/29191-original-20170421154949.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/29191-96-20170421154949.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="48" media:height="48" href="https://social.heldscal.la/avatar/29191-48-20170421154949.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="24" media:height="24" href="https://social.heldscal.la/avatar/29191-24-20170421161149.jpeg"/> - <poco:preferredUsername>shp</poco:preferredUsername> - <poco:displayName>shp</poco:displayName> - <poco:note>cofe</poco:note> - <poco:address> - <poco:formatted>cofe</poco:formatted> - </poco:address> - <followers url="https://social.heldscal.la/shp/subscribers"></followers> - <statusnet:profile_info local_id="29191"></statusnet:profile_info> -</author> - <link href="https://social.heldscal.la/shp" rel="alternate" type="text/html"/> - <link href="https://social.heldscal.la/main/sup" rel="http://api.friendfeed.com/2008/03#sup" type="application/json"/> - <link href="https://social.heldscal.la/api/statuses/user_timeline/29191.atom?max_id=1907936" rel="next" type="application/atom+xml"/> - <link href="https://social.heldscal.la/main/push/hub" rel="hub"/> - <link href="https://social.heldscal.la/main/salmon/user/29191" rel="salmon"/> - <link href="https://social.heldscal.la/main/salmon/user/29191" rel="http://salmon-protocol.org/ns/salmon-replies"/> - <link href="https://social.heldscal.la/main/salmon/user/29191" rel="http://salmon-protocol.org/ns/salmon-mention"/> - <link href="https://social.heldscal.la/api/statuses/user_timeline/29191.atom" rel="self" type="application/atom+xml"/> -<entry> - <id>tag:social.heldscal.la,2017-04-29:noticeId=1967657:objectType=note</id> - <title>shp repeated a notice by lain</title> - <content type="html">RT @<a href="https://social.heldscal.la/user/37181" class="h-card u-url p-nickname mention" title="Lain Iwakura">lain</a> @<a href="https://social.heldscal.la/user/29191" class="h-card u-url p-nickname mention" title="shp">shp</a> @<a href="https://social.heldscal.la/user/23211" class="h-card u-url p-nickname mention">lambadalambda</a> cofe.</content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/1967657"/> - <activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb> - <published>2017-04-29T18:19:34+00:00</published> - <updated>2017-04-29T18:19:34+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type> - <id>https://pleroma.soykaf.com/activities/43d12c05-db3f-4f3d-bee1-d676f264490c</id> - <title></title> - <content type="html"><a href="https://pleroma.soykaf.com/users/shp">@shp</a> <a href="https://social.heldscal.la/user/23211">@lambadalambda@social.heldscal.la</a> cofe.</content> - <link rel="alternate" type="text/html" href="https://pleroma.soykaf.com/activities/43d12c05-db3f-4f3d-bee1-d676f264490c"/> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-04-29T18:14:36+00:00</published> - <updated>2017-04-29T18:14:36+00:00</updated> - <author> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://pleroma.soykaf.com/users/lain</uri> - <name>lain</name> - <summary>Test account</summary> - <link rel="alternate" type="text/html" href="https://pleroma.soykaf.com/users/lain"/> - <link rel="avatar" type="image/jpeg" media:width="250" media:height="202" href="https://social.heldscal.la/avatar/43188-original-20170429171039.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/43188-96-20170429172422.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="48" media:height="48" href="https://social.heldscal.la/avatar/43188-48-20170429172422.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="24" media:height="24" href="https://social.heldscal.la/avatar/43188-24-20170429181411.jpeg"/> - <poco:preferredUsername>lain</poco:preferredUsername> - <poco:displayName>Lain Iwakura</poco:displayName> - <poco:note>Test account</poco:note> - <statusnet:profile_info local_id="43188"></statusnet:profile_info> - </author> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>https://pleroma.soykaf.com/activities/43d12c05-db3f-4f3d-bee1-d676f264490c</id> - <title>New note by lain</title> - <content type="html"><a href="https://pleroma.soykaf.com/users/shp">@shp</a> <a href="https://social.heldscal.la/user/23211">@lambadalambda@social.heldscal.la</a> cofe.</content> - <link rel="alternate" type="text/html" href="https://pleroma.soykaf.com/activities/43d12c05-db3f-4f3d-bee1-d676f264490c"/> - <status_net notice_id="1967581"></status_net> - </activity:object> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1007769"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/1007769" local_id="1007769" ref="tag:social.heldscal.la,2017-04-29:objectType=thread:nonce=e0b75431888efdab">tag:social.heldscal.la,2017-04-29:objectType=thread:nonce=e0b75431888efdab</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <source> - <id>https://pleroma.soykaf.com/users/lain/feed.atom</id> - <title>Lain Iwakura</title> - <link rel="alternate" type="text/html" href="https://pleroma.soykaf.com/users/lain"/> - <link rel="self" type="application/atom+xml" href="https://pleroma.soykaf.com/users/lain/feed.atom"/> - <icon>https://social.heldscal.la/avatar/43188-96-20170429172422.jpeg</icon> - <updated>2017-05-05T08:38:03+00:00</updated> - </source> - </activity:object> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1007769"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/1007769" local_id="1007769" ref="tag:social.heldscal.la,2017-04-29:objectType=thread:nonce=e0b75431888efdab">tag:social.heldscal.la,2017-04-29:objectType=thread:nonce=e0b75431888efdab</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1967657.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1967657.atom"/> - <statusnet:notice_info local_id="1967657" source="Qvitter" repeat_of="1967581"></statusnet:notice_info> -</entry> -<entry> - <id>tag:social.heldscal.la,2017-04-27:subscription:29191:person:29558:2017-04-27T17:26:37+00:00</id> - <title>shp (shp@social.heldscal.la)'s status on Thursday, 27-Apr-2017 17:26:37 UTC</title> - <content type="html"><a href="https://social.heldscal.la/shp">shp</a> started following <a href="https://gs.smuglo.li/kfist">KFist</a>.</content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/1933101"/> - <activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb> - <published>2017-04-27T17:26:37+00:00</published> - <updated>2017-04-27T17:26:37+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <id>https://gs.smuglo.li/user/28051</id> - <title>KFist</title> - <summary>I stream thanks to @nepfag. I also drink, shitpost, and fly planes. I visited Japan and it changed my life. Do you love your station?</summary> - <link rel="alternate" type="text/html" href="https://gs.smuglo.li/kfist"/> - <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/29558-original-20170302030034.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/29558-original-20170302030034.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="48" media:height="48" href="https://social.heldscal.la/avatar/29558-48-20170303232734.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="24" media:height="24" href="https://social.heldscal.la/avatar/29558-24-20170304004149.jpeg"/> - <poco:preferredUsername>kfist</poco:preferredUsername> - <poco:displayName>KFist</poco:displayName> - <poco:note>I stream thanks to @nepfag. I also drink, shitpost, and fly planes. I visited Japan and it changed my life. Do you love your station?</poco:note> - <poco:urls> - <poco:type>homepage</poco:type> - <poco:value>http://smuglo.li:8000/stream.m3u</poco:value> - <poco:primary>true</poco:primary> - </poco:urls> - </activity:object> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/988472"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/988472" local_id="988472" ref="tag:social.heldscal.la,2017-04-27:objectType=thread:nonce=f766240d13ed9c2e">tag:social.heldscal.la,2017-04-27:objectType=thread:nonce=f766240d13ed9c2e</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1933101.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1933101.atom"/> - <statusnet:notice_info local_id="1933101" source="activity"></statusnet:notice_info> -</entry> -<entry> - <id>tag:social.heldscal.la,2017-04-27:noticeId=1933030:objectType=note</id> - <title>shp repeated a notice by shpbot</title> - <content type="html">RT @<a href="https://gs.archae.me/user/4687" class="h-card u-url p-nickname mention" title="shpbot">shpbot</a> &gt;QuakeC</content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/1933030"/> - <activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb> - <published>2017-04-27T17:21:10+00:00</published> - <updated>2017-04-27T17:21:10+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type> - <id>tag:gs.archae.me,2017-04-27:noticeId=760881:objectType=note</id> - <title></title> - <content type="html"><span class='greentext'>&gt;QuakeC</span></content> - <link rel="alternate" type="text/html" href="https://gs.archae.me/notice/760881"/> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-04-27T17:15:13+00:00</published> - <updated>2017-04-27T17:15:13+00:00</updated> - <author> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://gs.archae.me/user/4687</uri> - <name>shpbot</name> - <link rel="alternate" type="text/html" href="https://gs.archae.me/shpbot"/> - <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/31581-original-20170405170019.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/31581-original-20170405170019.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="48" media:height="48" href="https://social.heldscal.la/avatar/31581-48-20170405170027.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="24" media:height="24" href="https://social.heldscal.la/avatar/31581-24-20170405170342.jpeg"/> - <poco:preferredUsername>shpbot</poco:preferredUsername> - <poco:displayName>shpbot</poco:displayName> - <statusnet:profile_info local_id="31581"></statusnet:profile_info> - </author> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:gs.archae.me,2017-04-27:noticeId=760881:objectType=note</id> - <title>New note by shpbot</title> - <content type="html"><span class='greentext'>&gt;QuakeC</span></content> - <link rel="alternate" type="text/html" href="https://gs.archae.me/notice/760881"/> - <status_net notice_id="1932941"></status_net> - </activity:object> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/988397"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/988397" local_id="988397" ref="https://gs.archae.me/conversation/318362">https://gs.archae.me/conversation/318362</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <source> - <id>https://gs.archae.me/api/statuses/user_timeline/4687.atom</id> - <title>shpbot</title> - <link rel="alternate" type="text/html" href="https://gs.archae.me/shpbot"/> - <link rel="self" type="application/atom+xml" href="https://gs.archae.me/api/statuses/user_timeline/4687.atom"/> - <icon>https://social.heldscal.la/avatar/31581-original-20170405170019.jpeg</icon> - <updated>2017-05-05T11:45:08+00:00</updated> - </source> - </activity:object> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/988397"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/988397" local_id="988397" ref="https://gs.archae.me/conversation/318362">https://gs.archae.me/conversation/318362</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1933030.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1933030.atom"/> - <statusnet:notice_info local_id="1933030" source="Qvitter" repeat_of="1932941"></statusnet:notice_info> -</entry> -<entry> - <id>tag:social.heldscal.la,2017-04-27:subscription:29191:person:23226:2017-04-27T17:20:48+00:00</id> - <title>shp (shp@social.heldscal.la)'s status on Thursday, 27-Apr-2017 17:20:48 UTC</title> - <content type="html"><a href="https://social.heldscal.la/shp">shp</a> started following <a href="http://quitter.se/taknamay">Internet Turtle Ⓐ 🏴 ✅</a>.</content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/1933025"/> - <activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb> - <published>2017-04-27T17:20:48+00:00</published> - <updated>2017-04-27T17:20:48+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <id>http://quitter.se/user/115823</id> - <title>Internet Turtle Ⓐ 🏴 ✅</title> - <summary>Scheme programmer, Novice esperantist, Spiritual naturalist - Will listen to your problems for free - XMPP: DarkDungeons94 at chatme.im</summary> - <link rel="alternate" type="text/html" href="http://quitter.se/taknamay"/> - <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/23226-original-20170427130915.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/23226-original-20170427130915.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="48" media:height="48" href="https://social.heldscal.la/avatar/23226-48-20170427130918.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="24" media:height="24" href="https://social.heldscal.la/avatar/23226-24-20170427171808.jpeg"/> - <poco:preferredUsername>taknamay</poco:preferredUsername> - <poco:displayName>Internet Turtle Ⓐ 🏴 ✅</poco:displayName> - <poco:note>Scheme programmer, Novice esperantist, Spiritual naturalist - Will listen to your problems for free - XMPP: DarkDungeons94 at chatme.im</poco:note> - <poco:address> - <poco:formatted>New Jersey, United States</poco:formatted> - </poco:address> - <poco:urls> - <poco:type>homepage</poco:type> - <poco:value>https://quitter.se/taknamay</poco:value> - <poco:primary>true</poco:primary> - </poco:urls> - </activity:object> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/988439"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/988439" local_id="988439" ref="tag:social.heldscal.la,2017-04-27:objectType=thread:nonce=a66b1fb22020c152">tag:social.heldscal.la,2017-04-27:objectType=thread:nonce=a66b1fb22020c152</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1933025.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1933025.atom"/> - <statusnet:notice_info local_id="1933025" source="activity"></statusnet:notice_info> -</entry> -<entry> - <id>tag:social.heldscal.la,2017-04-27:subscription:29191:person:29302:2017-04-27T17:20:33+00:00</id> - <title>shp (shp@social.heldscal.la)'s status on Thursday, 27-Apr-2017 17:20:33 UTC</title> - <content type="html"><a href="https://social.heldscal.la/shp">shp</a> started following <a href="https://icosahedron.website/@Trev">Chillidan Stormrave</a>.</content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/1933022"/> - <activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb> - <published>2017-04-27T17:20:33+00:00</published> - <updated>2017-04-27T17:20:33+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <id>https://icosahedron.website/users/Trev</id> - <title>Trev Prime</title> - <summary>web tech, music, ethics. radical individualist. kinda queer. love thy neighbor. always open for conversation. </summary> - <link rel="alternate" type="text/html" href="https://icosahedron.website/@Trev"/> - <link rel="avatar" type="image/png" media:width="120" media:height="120" href="https://social.heldscal.la/avatar/29302-original-20170417171941.png"/> - <link rel="avatar" type="image/png" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/29302-96-20170417171942.png"/> - <link rel="avatar" type="image/png" media:width="48" media:height="48" href="https://social.heldscal.la/avatar/29302-48-20170417171942.png"/> - <link rel="avatar" type="image/png" media:width="24" media:height="24" href="https://social.heldscal.la/avatar/29302-24-20170417180438.png"/> - <poco:preferredUsername>trev</poco:preferredUsername> - <poco:displayName>Trev Prime</poco:displayName> - <poco:note>web tech, music, ethics. radical individualist. kinda queer. love thy neighbor. always open for conversation. </poco:note> - </activity:object> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/988436"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/988436" local_id="988436" ref="tag:social.heldscal.la,2017-04-27:objectType=thread:nonce=781c05bd64ad9520">tag:social.heldscal.la,2017-04-27:objectType=thread:nonce=781c05bd64ad9520</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1933022.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1933022.atom"/> - <statusnet:notice_info local_id="1933022" source="activity"></statusnet:notice_info> -</entry> -<entry> - <id>tag:social.heldscal.la,2017-04-27:subscription:29191:person:29367:2017-04-27T17:20:27+00:00</id> - <title>shp (shp@social.heldscal.la)'s status on Thursday, 27-Apr-2017 17:20:27 UTC</title> - <content type="html"><a href="https://social.heldscal.la/shp">shp</a> started following <a href="https://gs.kawa-kun.com/aya">射命丸 文</a>.</content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/1933020"/> - <activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb> - <published>2017-04-27T17:20:27+00:00</published> - <updated>2017-04-27T17:20:27+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <id>https://gs.kawa-kun.com/user/4885</id> - <title>射命丸 文</title> - <summary>Traditional Reporter of Fantasy</summary> - <link rel="alternate" type="text/html" href="https://gs.kawa-kun.com/aya"/> - <link rel="avatar" type="image/png" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/29367-original-20170322091904.png"/> - <link rel="avatar" type="image/png" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/29367-original-20170322091904.png"/> - <link rel="avatar" type="image/png" media:width="48" media:height="48" href="https://social.heldscal.la/avatar/29367-48-20170322103327.png"/> - <link rel="avatar" type="image/png" media:width="24" media:height="24" href="https://social.heldscal.la/avatar/29367-24-20170322185131.png"/> - <poco:preferredUsername>aya</poco:preferredUsername> - <poco:displayName>射命丸 文</poco:displayName> - <poco:note>Traditional Reporter of Fantasy</poco:note> - <poco:address> - <poco:formatted>Gensōkyō</poco:formatted> - </poco:address> - <poco:urls> - <poco:type>homepage</poco:type> - <poco:value>https://danbooru.donmai.us</poco:value> - <poco:primary>true</poco:primary> - </poco:urls> - </activity:object> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/988435"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/988435" local_id="988435" ref="tag:social.heldscal.la,2017-04-27:objectType=thread:nonce=5921da7a934e47ca">tag:social.heldscal.la,2017-04-27:objectType=thread:nonce=5921da7a934e47ca</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1933020.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1933020.atom"/> - <statusnet:notice_info local_id="1933020" source="activity"></statusnet:notice_info> -</entry> -<entry> - <id>tag:social.heldscal.la,2017-04-27:subscription:29191:person:27773:2017-04-27T17:20:18+00:00</id> - <title>shp (shp@social.heldscal.la)'s status on Thursday, 27-Apr-2017 17:20:18 UTC</title> - <content type="html"><a href="https://social.heldscal.la/shp">shp</a> started following <a href="https://gs.smuglo.li/japananon">JapanAnon</a>.</content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/1933017"/> - <activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb> - <published>2017-04-27T17:20:18+00:00</published> - <updated>2017-04-27T17:20:18+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <id>https://gs.smuglo.li/user/27299</id> - <title>JapanAnon</title> - <summary>匿名でしていてね!</summary> - <link rel="alternate" type="text/html" href="https://gs.smuglo.li/japananon"/> - <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/27773-original-20170102074719.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/27773-original-20170102074719.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="48" media:height="48" href="https://social.heldscal.la/avatar/27773-48-20170103173058.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="24" media:height="24" href="https://social.heldscal.la/avatar/27773-24-20170103173058.jpeg"/> - <poco:preferredUsername>japananon</poco:preferredUsername> - <poco:displayName>JapanAnon</poco:displayName> - <poco:note>匿名でしていてね!</poco:note> - <poco:address> - <poco:formatted>ワイヤード</poco:formatted> - </poco:address> - <poco:urls> - <poco:type>homepage</poco:type> - <poco:value>http://www.anonymous-japan.org</poco:value> - <poco:primary>true</poco:primary> - </poco:urls> - </activity:object> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/988434"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/988434" local_id="988434" ref="tag:social.heldscal.la,2017-04-27:objectType=thread:nonce=ae3d819865886cba">tag:social.heldscal.la,2017-04-27:objectType=thread:nonce=ae3d819865886cba</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1933017.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1933017.atom"/> - <statusnet:notice_info local_id="1933017" source="activity"></statusnet:notice_info> -</entry> -<entry> - <id>tag:social.heldscal.la,2017-04-27:subscription:29191:person:36560:2017-04-27T17:19:30+00:00</id> - <title>shp (shp@social.heldscal.la)'s status on Thursday, 27-Apr-2017 17:19:30 UTC</title> - <content type="html"><a href="https://social.heldscal.la/shp">shp</a> started following <a href="https://shitposter.club/wareya">wareya</a>.</content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/1933001"/> - <activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb> - <published>2017-04-27T17:19:30+00:00</published> - <updated>2017-04-27T17:19:30+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <id>https://shitposter.club/user/15439</id> - <title>wareya</title> - <summary>Who are you to defy such a perfect being that is the machine? 日本語難しいけど頑張るぜ github.com/wareya wareya.moe Short: reya or war, never "ware"</summary> - <link rel="alternate" type="text/html" href="https://shitposter.club/wareya"/> - <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/36560-original-20170414073546.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/36560-original-20170414073546.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="48" media:height="48" href="https://social.heldscal.la/avatar/36560-48-20170414075036.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="24" media:height="24" href="https://social.heldscal.la/avatar/36560-24-20170427171930.jpeg"/> - <poco:preferredUsername>wareya</poco:preferredUsername> - <poco:displayName>wareya</poco:displayName> - <poco:note>Who are you to defy such a perfect being that is the machine? 日本語難しいけど頑張るぜ github.com/wareya wareya.moe Short: reya or war, never "ware"</poco:note> - </activity:object> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/988426"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/988426" local_id="988426" ref="tag:social.heldscal.la,2017-04-27:objectType=thread:nonce=bd88a3cd20b5a418">tag:social.heldscal.la,2017-04-27:objectType=thread:nonce=bd88a3cd20b5a418</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1933001.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1933001.atom"/> - <statusnet:notice_info local_id="1933001" source="activity"></statusnet:notice_info> -</entry> -<entry> - <id>tag:social.heldscal.la,2017-04-27:subscription:29191:person:41176:2017-04-27T17:19:21+00:00</id> - <title>shp (shp@social.heldscal.la)'s status on Thursday, 27-Apr-2017 17:19:21 UTC</title> - <content type="html"><a href="https://social.heldscal.la/shp">shp</a> started following <a href="https://hakui.club/takeshitakenji">竹下憲二 (白)</a>.</content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/1932999"/> - <activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb> - <published>2017-04-27T17:19:21+00:00</published> - <updated>2017-04-27T17:19:21+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <id>https://hakui.club/user/6</id> - <title>竹下憲二 (白)</title> - <summary>Oh boy.</summary> - <link rel="alternate" type="text/html" href="https://hakui.club/takeshitakenji"/> - <link rel="avatar" type="image/png" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/41176-original-20170428153916.png"/> - <link rel="avatar" type="image/png" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/41176-original-20170428153916.png"/> - <link rel="avatar" type="image/png" media:width="48" media:height="48" href="https://social.heldscal.la/avatar/41176-48-20170428153926.png"/> - <link rel="avatar" type="image/png" media:width="24" media:height="24" href="https://social.heldscal.la/avatar/41176-24-20170428160801.png"/> - <poco:preferredUsername>takeshitakenji</poco:preferredUsername> - <poco:displayName>竹下憲二 (白)</poco:displayName> - <poco:note>Oh boy.</poco:note> - <poco:address> - <poco:formatted>Seattle, WA</poco:formatted> - </poco:address> - <poco:urls> - <poco:type>homepage</poco:type> - <poco:value>http://gs.kawa-kun.com</poco:value> - <poco:primary>true</poco:primary> - </poco:urls> - </activity:object> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/988424"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/988424" local_id="988424" ref="tag:social.heldscal.la,2017-04-27:objectType=thread:nonce=b139a673deba6963">tag:social.heldscal.la,2017-04-27:objectType=thread:nonce=b139a673deba6963</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1932999.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1932999.atom"/> - <statusnet:notice_info local_id="1932999" source="activity"></statusnet:notice_info> -</entry> -<entry> - <id>tag:social.heldscal.la,2017-04-27:fave:29191:note:1932205:2017-04-27T17:17:46+00:00</id> - <title>Favorite</title> - <content type="html">shp favorited something by dolus: Looks like Merry is pussing out and caving to pressure. Sad. <a href="https://gs.smuglo.li/file/23e37de3c321248d3f322d8ec042372914568ab4c9431a94e568a61b8146587f.png" title="https://gs.smuglo.li/file/23e37de3c321248d3f322d8ec042372914568ab4c9431a94e568a61b8146587f.png" rel="nofollow noreferrer" class="attachment">https://gs.smuglo.li/attachment/432294</a> <a href="https://gs.smuglo.li/file/e5a9549a19986d59d51750090910f47c186787adf02b2b6ac58df37556887297.png" title="https://gs.smuglo.li/file/e5a9549a19986d59d51750090910f47c186787adf02b2b6ac58df37556887297.png" rel="nofollow noreferrer" class="attachment">https://gs.smuglo.li/attachment/432295</a> <a href="https://gs.smuglo.li/file/2fdfabbc8ab0b8dc135903a8c48c29b440d1f97446b98ced4ad14a54d3b5d41f.png" title="https://gs.smuglo.li/file/2fdfabbc8ab0b8dc135903a8c48c29b440d1f97446b98ced4ad14a54d3b5d41f.png" rel="nofollow noreferrer" class="attachment">https://gs.smuglo.li/attachment/432296</a> <a href="https://gs.smuglo.li/file/af605d7c6fe3a8c26c6d334c2a8e0005f7e86a266f14a5b3755e7d3ac4e226de.png" title="https://gs.smuglo.li/file/af605d7c6fe3a8c26c6d334c2a8e0005f7e86a266f14a5b3755e7d3ac4e226de.png" rel="nofollow noreferrer" class="attachment">https://gs.smuglo.li/attachment/432297</a></content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/1932976"/> - <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb> - <published>2017-04-27T17:17:46+00:00</published> - <updated>2017-04-27T17:17:46+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:gs.smuglo.li,2017-04-27:noticeId=2065465:objectType=note</id> - <title>New note by dolus</title> - <content type="html">Looks like Merry is pussing out and caving to pressure. Sad. <a href="https://gs.smuglo.li/file/23e37de3c321248d3f322d8ec042372914568ab4c9431a94e568a61b8146587f.png" title="https://gs.smuglo.li/file/23e37de3c321248d3f322d8ec042372914568ab4c9431a94e568a61b8146587f.png" rel="nofollow noreferrer" class="attachment">https://gs.smuglo.li/attachment/432294</a> <a href="https://gs.smuglo.li/file/e5a9549a19986d59d51750090910f47c186787adf02b2b6ac58df37556887297.png" title="https://gs.smuglo.li/file/e5a9549a19986d59d51750090910f47c186787adf02b2b6ac58df37556887297.png" rel="nofollow noreferrer" class="attachment">https://gs.smuglo.li/attachment/432295</a> <a href="https://gs.smuglo.li/file/2fdfabbc8ab0b8dc135903a8c48c29b440d1f97446b98ced4ad14a54d3b5d41f.png" title="https://gs.smuglo.li/file/2fdfabbc8ab0b8dc135903a8c48c29b440d1f97446b98ced4ad14a54d3b5d41f.png" rel="nofollow noreferrer" class="attachment">https://gs.smuglo.li/attachment/432296</a> <a href="https://gs.smuglo.li/file/af605d7c6fe3a8c26c6d334c2a8e0005f7e86a266f14a5b3755e7d3ac4e226de.png" title="https://gs.smuglo.li/file/af605d7c6fe3a8c26c6d334c2a8e0005f7e86a266f14a5b3755e7d3ac4e226de.png" rel="nofollow noreferrer" class="attachment">https://gs.smuglo.li/attachment/432297</a></content> - <link rel="alternate" type="text/html" href="https://gs.smuglo.li/notice/2065465"/> - <status_net notice_id="1932205"></status_net> - </activity:object> - <thr:in-reply-to ref="tag:gs.smuglo.li,2017-04-27:noticeId=2065465:objectType=note" href="https://gs.smuglo.li/notice/2065465"></thr:in-reply-to> - <link rel="related" href="https://gs.smuglo.li/notice/2065465"/> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/987894"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/987894" local_id="987894" ref="https://gs.smuglo.li/conversation/927473">https://gs.smuglo.li/conversation/927473</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1932976.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1932976.atom"/> - <statusnet:notice_info local_id="1932976" source="unknown"></statusnet:notice_info> -</entry> -<entry> - <id>tag:social.heldscal.la,2017-04-27:fave:29191:note:1932492:2017-04-27T17:13:55+00:00</id> - <title>Favorite</title> - <content type="html">shp favorited something by zemichi: <a href="https://gs.smuglo.li/file/1d45ea4ffc95f15037f361b56ad6b89f8451b70ad1ff7a03b7bb0345b8e2227c.jpg" title="https://gs.smuglo.li/file/1d45ea4ffc95f15037f361b56ad6b89f8451b70ad1ff7a03b7bb0345b8e2227c.jpg" rel="nofollow noreferrer" class="attachment">https://gs.smuglo.li/attachment/432344</a><br /> that's a lot of loli</content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/1932922"/> - <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb> - <published>2017-04-27T17:13:55+00:00</published> - <updated>2017-04-27T17:13:55+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:gs.smuglo.li,2017-04-27:noticeId=2065713:objectType=note</id> - <title>New note by zemichi</title> - <content type="html"><a href="https://gs.smuglo.li/file/1d45ea4ffc95f15037f361b56ad6b89f8451b70ad1ff7a03b7bb0345b8e2227c.jpg" title="https://gs.smuglo.li/file/1d45ea4ffc95f15037f361b56ad6b89f8451b70ad1ff7a03b7bb0345b8e2227c.jpg" rel="nofollow noreferrer" class="attachment">https://gs.smuglo.li/attachment/432344</a><br /> that's a lot of loli</content> - <link rel="alternate" type="text/html" href="https://gs.smuglo.li/notice/2065713"/> - <status_net notice_id="1932492"></status_net> - </activity:object> - <thr:in-reply-to ref="tag:gs.smuglo.li,2017-04-27:noticeId=2065713:objectType=note" href="https://gs.smuglo.li/notice/2065713"></thr:in-reply-to> - <link rel="related" href="https://gs.smuglo.li/notice/2065713"/> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/988113"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/988113" local_id="988113" ref="https://gs.smuglo.li/conversation/927673">https://gs.smuglo.li/conversation/927673</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1932922.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1932922.atom"/> - <statusnet:notice_info local_id="1932922" source="unknown"></statusnet:notice_info> -</entry> -<entry> - <id>tag:social.heldscal.la,2017-04-27:fave:29191:note:1932559:2017-04-27T17:12:46+00:00</id> - <title>Favorite</title> - <content type="html">shp favorited something by gsimg: <a href="https://gs.kawa-kun.com/file/3435c5cafda46f31cad5abb5837b3521b7b458198507073a496f4d10bad3633b.jpg" title="https://gs.kawa-kun.com/file/3435c5cafda46f31cad5abb5837b3521b7b458198507073a496f4d10bad3633b.jpg" rel="nofollow noreferrer" class="attachment">https://gs.kawa-kun.com/file/3435c5cafda46f31cad5abb5837b3521b7b458198507073a496f4d10bad3633b.jpg</a> #<span class="tag"><a href="https://gs.kawa-kun.com/tag/nsfw" rel="tag">nsfw</a></span></content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/1932894"/> - <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb> - <published>2017-04-27T17:12:46+00:00</published> - <updated>2017-04-27T17:12:46+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:gs.kawa-kun.com,2017-04-27:noticeId=1608309:objectType=note</id> - <title>New note by gsimg</title> - <content type="html"><a href="https://gs.kawa-kun.com/file/3435c5cafda46f31cad5abb5837b3521b7b458198507073a496f4d10bad3633b.jpg" title="https://gs.kawa-kun.com/file/3435c5cafda46f31cad5abb5837b3521b7b458198507073a496f4d10bad3633b.jpg" rel="nofollow noreferrer" class="attachment">https://gs.kawa-kun.com/file/3435c5cafda46f31cad5abb5837b3521b7b458198507073a496f4d10bad3633b.jpg</a> #<span class="tag"><a href="https://gs.kawa-kun.com/tag/nsfw" rel="tag">nsfw</a></span></content> - <link rel="alternate" type="text/html" href="https://gs.kawa-kun.com/notice/1608309"/> - <status_net notice_id="1932559"></status_net> - </activity:object> - <thr:in-reply-to ref="tag:gs.kawa-kun.com,2017-04-27:noticeId=1608309:objectType=note" href="https://gs.kawa-kun.com/notice/1608309"></thr:in-reply-to> - <link rel="related" href="https://gs.kawa-kun.com/notice/1608309"/> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/988157"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/988157" local_id="988157" ref="https://gs.kawa-kun.com/conversation/690817">https://gs.kawa-kun.com/conversation/690817</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1932894.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1932894.atom"/> - <statusnet:notice_info local_id="1932894" source="unknown"></statusnet:notice_info> -</entry> -<entry> - <id>tag:social.heldscal.la,2017-04-27:fave:29191:note:1932601:2017-04-27T17:12:28+00:00</id> - <title>Favorite</title> - <content type="html">shp favorited something by zemichi: <a href="https://gs.smuglo.li/file/5d9114fafea7b9866c9d852bcfeaf66aade65ae26149758346bc5ade7e3fa8f0.jpg" title="https://gs.smuglo.li/file/5d9114fafea7b9866c9d852bcfeaf66aade65ae26149758346bc5ade7e3fa8f0.jpg" rel="nofollow noreferrer" class="attachment">https://gs.smuglo.li/attachment/432372</a></content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/1932888"/> - <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb> - <published>2017-04-27T17:12:28+00:00</published> - <updated>2017-04-27T17:12:28+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:gs.smuglo.li,2017-04-27:noticeId=2065821:objectType=note</id> - <title>New note by zemichi</title> - <content type="html"><a href="https://gs.smuglo.li/file/5d9114fafea7b9866c9d852bcfeaf66aade65ae26149758346bc5ade7e3fa8f0.jpg" title="https://gs.smuglo.li/file/5d9114fafea7b9866c9d852bcfeaf66aade65ae26149758346bc5ade7e3fa8f0.jpg" rel="nofollow noreferrer" class="attachment">https://gs.smuglo.li/attachment/432372</a></content> - <link rel="alternate" type="text/html" href="https://gs.smuglo.li/notice/2065821"/> - <status_net notice_id="1932601"></status_net> - </activity:object> - <thr:in-reply-to ref="tag:gs.smuglo.li,2017-04-27:noticeId=2065821:objectType=note" href="https://gs.smuglo.li/notice/2065821"></thr:in-reply-to> - <link rel="related" href="https://gs.smuglo.li/notice/2065821"/> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/988189"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/988189" local_id="988189" ref="https://gs.smuglo.li/conversation/927760">https://gs.smuglo.li/conversation/927760</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1932888.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1932888.atom"/> - <statusnet:notice_info local_id="1932888" source="unknown"></statusnet:notice_info> -</entry> -<entry> - <id>tag:social.heldscal.la,2017-04-27:noticeId=1932867:objectType=note</id> - <title>shp repeated a notice by shpbot</title> - <content type="html">RT @<a href="https://gs.archae.me/user/4687" class="h-card u-url p-nickname mention" title="shpbot">shpbot</a> <a href="https://shitposter.club/file/cbf7fbbee1127a9870e871305ca7de70f1eb1bbb79ffe5b3b0f33e37514d14d8.jpg" title="https://shitposter.club/file/cbf7fbbee1127a9870e871305ca7de70f1eb1bbb79ffe5b3b0f33e37514d14d8.jpg" rel="nofollow external noreferrer" class="attachment" id="attachment-237676">https://shitposter.club/file/cbf7fbbee1127a9870e871305ca7de70f1eb1bbb79ffe5b3b0f33e37514d14d8.jpg</a> #<span class="tag"><a href="https://social.heldscal.la/tag/2hu" rel="tag">2hu</a></span> #<span class="tag"><a href="https://social.heldscal.la/tag/ordinarymagician" rel="tag">ordinarymagician</a></span> :thinking: <a href="https://shitposter.club/file/abf3f82d9ce28d2293d858af26c75bb5d4fdd091c0d90ca7bc72ea7efba220e4.jpg" title="https://shitposter.club/file/abf3f82d9ce28d2293d858af26c75bb5d4fdd091c0d90ca7bc72ea7efba220e4.jpg" rel="nofollow external noreferrer" class="attachment" id="attachment-312306">https://shitposter.club/file/abf3f82d9ce28d2293d858af26c75bb5d4fdd091c0d90ca7bc72ea7efba220e4.jpg</a></content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/1932867"/> - <activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb> - <published>2017-04-27T17:11:35+00:00</published> - <updated>2017-04-27T17:11:35+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type> - <id>tag:gs.archae.me,2017-04-27:noticeId=760830:objectType=note</id> - <title></title> - <content type="html"><a href="https://shitposter.club/file/cbf7fbbee1127a9870e871305ca7de70f1eb1bbb79ffe5b3b0f33e37514d14d8.jpg" title="https://shitposter.club/file/cbf7fbbee1127a9870e871305ca7de70f1eb1bbb79ffe5b3b0f33e37514d14d8.jpg" rel="nofollow noreferrer" class="attachment">https://shitposter.club/file/cbf7fbbee1127a9870e871305ca7de70f1eb1bbb79ffe5b3b0f33e37514d14d8.jpg</a> #<span class="tag"><a href="https://gs.archae.me/tag/2hu" rel="tag">2hu</a></span> #<span class="tag"><a href="https://gs.archae.me/tag/ordinarymagician" rel="tag">ordinarymagician</a></span> :thinking: <a href="https://shitposter.club/file/abf3f82d9ce28d2293d858af26c75bb5d4fdd091c0d90ca7bc72ea7efba220e4.jpg" title="https://shitposter.club/file/abf3f82d9ce28d2293d858af26c75bb5d4fdd091c0d90ca7bc72ea7efba220e4.jpg" rel="nofollow noreferrer" class="attachment">https://shitposter.club/file/abf3f82d9ce28d2293d858af26c75bb5d4fdd091c0d90ca7bc72ea7efba220e4.jpg</a></content> - <link rel="alternate" type="text/html" href="https://gs.archae.me/notice/760830"/> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-04-27T17:00:08+00:00</published> - <updated>2017-04-27T17:00:08+00:00</updated> - <author> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://gs.archae.me/user/4687</uri> - <name>shpbot</name> - <link rel="alternate" type="text/html" href="https://gs.archae.me/shpbot"/> - <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/31581-original-20170405170019.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/31581-original-20170405170019.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="48" media:height="48" href="https://social.heldscal.la/avatar/31581-48-20170405170027.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="24" media:height="24" href="https://social.heldscal.la/avatar/31581-24-20170405170342.jpeg"/> - <poco:preferredUsername>shpbot</poco:preferredUsername> - <poco:displayName>shpbot</poco:displayName> - <statusnet:profile_info local_id="31581"></statusnet:profile_info> - </author> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:gs.archae.me,2017-04-27:noticeId=760830:objectType=note</id> - <title>New note by shpbot</title> - <content type="html"><a href="https://shitposter.club/file/cbf7fbbee1127a9870e871305ca7de70f1eb1bbb79ffe5b3b0f33e37514d14d8.jpg" title="https://shitposter.club/file/cbf7fbbee1127a9870e871305ca7de70f1eb1bbb79ffe5b3b0f33e37514d14d8.jpg" rel="nofollow noreferrer" class="attachment">https://shitposter.club/file/cbf7fbbee1127a9870e871305ca7de70f1eb1bbb79ffe5b3b0f33e37514d14d8.jpg</a> #<span class="tag"><a href="https://gs.archae.me/tag/2hu" rel="tag">2hu</a></span> #<span class="tag"><a href="https://gs.archae.me/tag/ordinarymagician" rel="tag">ordinarymagician</a></span> :thinking: <a href="https://shitposter.club/file/abf3f82d9ce28d2293d858af26c75bb5d4fdd091c0d90ca7bc72ea7efba220e4.jpg" title="https://shitposter.club/file/abf3f82d9ce28d2293d858af26c75bb5d4fdd091c0d90ca7bc72ea7efba220e4.jpg" rel="nofollow noreferrer" class="attachment">https://shitposter.club/file/abf3f82d9ce28d2293d858af26c75bb5d4fdd091c0d90ca7bc72ea7efba220e4.jpg</a></content> - <link rel="alternate" type="text/html" href="https://gs.archae.me/notice/760830"/> - <status_net notice_id="1932673"></status_net> - </activity:object> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/988229"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/988229" local_id="988229" ref="https://gs.archae.me/conversation/318317">https://gs.archae.me/conversation/318317</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <category term="2hu"></category> - <category term="ordinarymagician"></category> - <source> - <id>https://gs.archae.me/api/statuses/user_timeline/4687.atom</id> - <title>shpbot</title> - <link rel="alternate" type="text/html" href="https://gs.archae.me/shpbot"/> - <link rel="self" type="application/atom+xml" href="https://gs.archae.me/api/statuses/user_timeline/4687.atom"/> - <icon>https://social.heldscal.la/avatar/31581-original-20170405170019.jpeg</icon> - <updated>2017-05-05T11:45:08+00:00</updated> - </source> - </activity:object> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/988229"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/988229" local_id="988229" ref="https://gs.archae.me/conversation/318317">https://gs.archae.me/conversation/318317</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1932867.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1932867.atom"/> - <statusnet:notice_info local_id="1932867" source="api" repeat_of="1932673"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:social.heldscal.la,2017-04-27:noticeId=1932815:objectType=note</id> - <title>New note by shp</title> - <content type="html">federation issues with SPC atm it seems</content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/1932815"/> - <status_net notice_id="1932815"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-04-27T17:08:55+00:00</published> - <updated>2017-04-27T17:08:55+00:00</updated> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/988321"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/988321" local_id="988321" ref="tag:social.heldscal.la,2017-04-27:objectType=thread:nonce=645a13c841f51769">tag:social.heldscal.la,2017-04-27:objectType=thread:nonce=645a13c841f51769</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1932815.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1932815.atom"/> - <statusnet:notice_info local_id="1932815" source="Pleroma FE"></statusnet:notice_info> -</entry> -<entry> - <id>tag:social.heldscal.la,2017-04-26:fave:29191:note:1907285:2017-04-26T06:59:07+00:00</id> - <title>Favorite</title> - <content type="html">shp favorited something by lambadalambda: Is this the most offensive video on the net? <a href="https://social.heldscal.la/file/4c34bfb81a8155c265031bc48f7e69c29eb0d2941c57daf63f80e17b0e2e5f47.webm" title="https://social.heldscal.la/file/4c34bfb81a8155c265031bc48f7e69c29eb0d2941c57daf63f80e17b0e2e5f47.webm" rel="nofollow noreferrer" class="attachment">https://social.heldscal.la/attachment/402251</a></content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/1907959"/> - <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb> - <published>2017-04-26T06:59:07+00:00</published> - <updated>2017-04-26T06:59:07+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:social.heldscal.la,2017-04-26:noticeId=1907285:objectType=note</id> - <title>New note by lambadalambda</title> - <content type="html">Is this the most offensive video on the net? <a href="https://social.heldscal.la/file/4c34bfb81a8155c265031bc48f7e69c29eb0d2941c57daf63f80e17b0e2e5f47.webm" title="https://social.heldscal.la/file/4c34bfb81a8155c265031bc48f7e69c29eb0d2941c57daf63f80e17b0e2e5f47.webm" rel="nofollow external noreferrer" class="attachment" id="attachment-402251">https://social.heldscal.la/attachment/402251</a></content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/1907285"/> - <status_net notice_id="1907285"></status_net> - </activity:object> - <thr:in-reply-to ref="tag:social.heldscal.la,2017-04-26:noticeId=1907285:objectType=note" href="https://social.heldscal.la/notice/1907285"></thr:in-reply-to> - <link rel="related" href="https://social.heldscal.la/notice/1907285"/> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/972605"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/972605" local_id="972605" ref="tag:social.heldscal.la,2017-04-26:objectType=thread:nonce=07b02e1328f456af">tag:social.heldscal.la,2017-04-26:objectType=thread:nonce=07b02e1328f456af</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1907959.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1907959.atom"/> - <statusnet:notice_info local_id="1907959" source="unknown"></statusnet:notice_info> -</entry> -<entry> - <id>tag:social.heldscal.la,2017-04-26:noticeId=1907951:objectType=note</id> - <title>shp repeated a notice by shpbot</title> - <content type="html">RT @<a href="https://gs.archae.me/user/4687" class="h-card u-url p-nickname mention" title="shpbot">shpbot</a> <a href="https://shitposter.club/file/718db06b564841331c72f9df767f8c9459e20c4dddbf0d4e61cd08ecbee7739d.jpg" title="https://shitposter.club/file/718db06b564841331c72f9df767f8c9459e20c4dddbf0d4e61cd08ecbee7739d.jpg" rel="nofollow external noreferrer" class="attachment" id="attachment-346198">https://shitposter.club/file/718db06b564841331c72f9df767f8c9459e20c4dddbf0d4e61cd08ecbee7739d.jpg</a></content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/1907951"/> - <activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb> - <published>2017-04-26T06:58:19+00:00</published> - <updated>2017-04-26T06:58:19+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type> - <id>tag:gs.archae.me,2017-04-26:noticeId=752596:objectType=note</id> - <title></title> - <content type="html"><a href="https://shitposter.club/file/718db06b564841331c72f9df767f8c9459e20c4dddbf0d4e61cd08ecbee7739d.jpg" title="https://shitposter.club/file/718db06b564841331c72f9df767f8c9459e20c4dddbf0d4e61cd08ecbee7739d.jpg" rel="nofollow noreferrer" class="attachment">https://shitposter.club/file/718db06b564841331c72f9df767f8c9459e20c4dddbf0d4e61cd08ecbee7739d.jpg</a></content> - <link rel="alternate" type="text/html" href="https://gs.archae.me/notice/752596"/> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-04-26T06:15:07+00:00</published> - <updated>2017-04-26T06:15:07+00:00</updated> - <author> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://gs.archae.me/user/4687</uri> - <name>shpbot</name> - <link rel="alternate" type="text/html" href="https://gs.archae.me/shpbot"/> - <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/31581-original-20170405170019.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/31581-original-20170405170019.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="48" media:height="48" href="https://social.heldscal.la/avatar/31581-48-20170405170027.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="24" media:height="24" href="https://social.heldscal.la/avatar/31581-24-20170405170342.jpeg"/> - <poco:preferredUsername>shpbot</poco:preferredUsername> - <poco:displayName>shpbot</poco:displayName> - <statusnet:profile_info local_id="31581"></statusnet:profile_info> - </author> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:gs.archae.me,2017-04-26:noticeId=752596:objectType=note</id> - <title>New note by shpbot</title> - <content type="html"><a href="https://shitposter.club/file/718db06b564841331c72f9df767f8c9459e20c4dddbf0d4e61cd08ecbee7739d.jpg" title="https://shitposter.club/file/718db06b564841331c72f9df767f8c9459e20c4dddbf0d4e61cd08ecbee7739d.jpg" rel="nofollow noreferrer" class="attachment">https://shitposter.club/file/718db06b564841331c72f9df767f8c9459e20c4dddbf0d4e61cd08ecbee7739d.jpg</a></content> - <link rel="alternate" type="text/html" href="https://gs.archae.me/notice/752596"/> - <status_net notice_id="1907331"></status_net> - </activity:object> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/972636"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/972636" local_id="972636" ref="https://gs.archae.me/conversation/314010">https://gs.archae.me/conversation/314010</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <source> - <id>https://gs.archae.me/api/statuses/user_timeline/4687.atom</id> - <title>shpbot</title> - <link rel="alternate" type="text/html" href="https://gs.archae.me/shpbot"/> - <link rel="self" type="application/atom+xml" href="https://gs.archae.me/api/statuses/user_timeline/4687.atom"/> - <icon>https://social.heldscal.la/avatar/31581-original-20170405170019.jpeg</icon> - <updated>2017-05-05T11:45:08+00:00</updated> - </source> - </activity:object> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/972636"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/972636" local_id="972636" ref="https://gs.archae.me/conversation/314010">https://gs.archae.me/conversation/314010</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1907951.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1907951.atom"/> - <statusnet:notice_info local_id="1907951" source="api" repeat_of="1907331"></statusnet:notice_info> -</entry> -<entry> - <id>tag:social.heldscal.la,2017-04-26:fave:29191:note:1907341:2017-04-26T06:58:16+00:00</id> - <title>Favorite</title> - <content type="html">shp favorited something by moonman: <a href="https://shitposter.club/file/1377b0894e983599c11e739e406243cabed9f8af7961a2550ecaf97e32de8e60.jpg" title="https://shitposter.club/file/1377b0894e983599c11e739e406243cabed9f8af7961a2550ecaf97e32de8e60.jpg" class="attachment" rel="nofollow">https://shitposter.club/attachment/630989</a></content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/1907949"/> - <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb> - <published>2017-04-26T06:58:16+00:00</published> - <updated>2017-04-26T06:58:16+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:shitposter.club,2017-04-26:noticeId=2681941:objectType=note</id> - <title>New note by moonman</title> - <content type="html"><a href="https://shitposter.club/file/1377b0894e983599c11e739e406243cabed9f8af7961a2550ecaf97e32de8e60.jpg" title="https://shitposter.club/file/1377b0894e983599c11e739e406243cabed9f8af7961a2550ecaf97e32de8e60.jpg" class="attachment" rel="nofollow">https://shitposter.club/attachment/630989</a></content> - <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2681941"/> - <status_net notice_id="1907341"></status_net> - </activity:object> - <thr:in-reply-to ref="tag:shitposter.club,2017-04-26:noticeId=2681941:objectType=note" href="https://shitposter.club/notice/2681941"></thr:in-reply-to> - <link rel="related" href="https://shitposter.club/notice/2681941"/> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/972646"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/972646" local_id="972646" ref="https://shitposter.club/conversation/1300990">https://shitposter.club/conversation/1300990</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1907949.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1907949.atom"/> - <statusnet:notice_info local_id="1907949" source="unknown"></statusnet:notice_info> -</entry> -<entry> - <id>tag:social.heldscal.la,2017-04-26:fave:29191:comment:1907412:2017-04-26T06:57:56+00:00</id> - <title>Favorite</title> - <content type="html">shp favorited something by lambadalambda: @<a href="https://gs.smuglo.li/user/2" class="h-card u-url p-nickname mention" title="nepfag">nepfag</a> <a href="https://cherubini.casa/why-i-shut-down-wizards-town-and-left-mastodon-6d4e631346b3?source=linkShare-89c2f851e979-1493184822&amp;gi=a6a47c5466a0" title="https://cherubini.casa/why-i-shut-down-wizards-town-and-left-mastodon-6d4e631346b3?source=linkShare-89c2f851e979-1493184822&amp;gi=a6a47c5466a0" rel="nofollow noreferrer" class="attachment">https://social.heldscal.la/url/402273</a></content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/1907947"/> - <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb> - <published>2017-04-26T06:57:56+00:00</published> - <updated>2017-04-26T06:57:56+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>tag:social.heldscal.la,2017-04-26:noticeId=1907412:objectType=comment</id> - <title>New comment by lambadalambda</title> - <content type="html">@<a href="https://gs.smuglo.li/user/2" class="h-card u-url p-nickname mention" title="nepfag">nepfag</a> <a href="https://cherubini.casa/why-i-shut-down-wizards-town-and-left-mastodon-6d4e631346b3?source=linkShare-89c2f851e979-1493184822&amp;gi=a6a47c5466a0" title="https://cherubini.casa/why-i-shut-down-wizards-town-and-left-mastodon-6d4e631346b3?source=linkShare-89c2f851e979-1493184822&amp;gi=a6a47c5466a0" rel="nofollow external noreferrer" class="attachment" id="attachment-402273">https://social.heldscal.la/url/402273</a></content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/1907412"/> - <status_net notice_id="1907412"></status_net> - </activity:object> - <thr:in-reply-to ref="tag:social.heldscal.la,2017-04-26:noticeId=1907412:objectType=comment" href="https://social.heldscal.la/notice/1907412"></thr:in-reply-to> - <link rel="related" href="https://social.heldscal.la/notice/1907412"/> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/972634"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/972634" local_id="972634" ref="tag:social.heldscal.la,2017-04-26:objectType=thread:nonce=85c21eda7aaa7259">tag:social.heldscal.la,2017-04-26:objectType=thread:nonce=85c21eda7aaa7259</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1907947.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1907947.atom"/> - <statusnet:notice_info local_id="1907947" source="unknown"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:social.heldscal.la,2017-04-26:noticeId=1907942:objectType=note</id> - <title>New note by shp</title> - <content type="html">#<span class="tag"><a href="https://social.heldscal.la/tag/cofe" rel="tag">cofe</a></span> time my friends <a href="https://social.heldscal.la/file/ec254b45b3a86ff74bc08bc7e065cb681d77cf7d4cedc9cdcf59e16adf311da3.png" title="https://social.heldscal.la/file/ec254b45b3a86ff74bc08bc7e065cb681d77cf7d4cedc9cdcf59e16adf311da3.png" rel="nofollow external noreferrer" class="attachment" id="attachment-402381">https://social.heldscal.la/attachment/402381</a></content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/1907942"/> - <status_net notice_id="1907942"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2017-04-26T06:57:18+00:00</published> - <updated>2017-04-26T06:57:18+00:00</updated> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/973042"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/973042" local_id="973042" ref="tag:social.heldscal.la,2017-04-26:objectType=thread:nonce=9c9d9373bccfaf70">tag:social.heldscal.la,2017-04-26:objectType=thread:nonce=9c9d9373bccfaf70</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <category term="cofe"></category> - <link rel="enclosure" href="https://social.heldscal.la/file/ec254b45b3a86ff74bc08bc7e065cb681d77cf7d4cedc9cdcf59e16adf311da3.png" type="image/png" length="3179103"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1907942.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1907942.atom"/> - <statusnet:notice_info local_id="1907942" source="Pleroma FE"></statusnet:notice_info> -</entry> -</feed> diff --git a/test/fixtures/tesla_mock/lemmy-page.json b/test/fixtures/tesla_mock/lemmy-page.json new file mode 100644 index 000000000..f07097a0e --- /dev/null +++ b/test/fixtures/tesla_mock/lemmy-page.json @@ -0,0 +1,17 @@ +{ + "commentsEnabled": true, + "sensitive": false, + "stickied": false, + "attributedTo": "https://enterprise.lemmy.ml/u/nutomic", + "summary": "Hello Federation!", + "url": "https://enterprise.lemmy.ml/pictrs/image/US52d9DPvf.jpg", + "image": { + "type": "Image", + "url": "https://enterprise.lemmy.ml/pictrs/image/lwFAcXHUjS.jpg" + }, + "published": "2020-09-14T15:03:11.909105+00:00", + "to": "https://enterprise.lemmy.ml/c/main", + "@context": "https://www.w3.org/ns/activitystreams", + "id": "https://enterprise.lemmy.ml/post/3", + "type": "Page" +} diff --git a/test/fixtures/tesla_mock/lemmy-user.json b/test/fixtures/tesla_mock/lemmy-user.json new file mode 100644 index 000000000..d0e9066ac --- /dev/null +++ b/test/fixtures/tesla_mock/lemmy-user.json @@ -0,0 +1,27 @@ +{ + "publicKey": { + "id": "https://enterprise.lemmy.ml/u/nutomic#main-key", + "owner": "https://enterprise.lemmy.ml/u/nutomic", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvfwAYPxp1gOk2HcCRoUd\nupoecvmnpzRc5Gu6/N3YQyOyRsrYuiYLNQq2cgM3kcU80ZeEetkwkYgXkRJOKu/b\nBWb7i1zt2tdr5k6lUdW8dfCyjht8ooFPQdov8J3QYHfgBHyUYxuCNfSujryxx2wu\nLQcdjRQa5NIWcomSO8OXmCF5/Yhg2XWCbtnlxEq6Y+AFddr1mAlTOy5pBr5d+xZz\njLw/U3CioNJ79yGi/sJhgp6IyJqtUSoN3b4BgRIEts2QVvn44W1rQy9wCbRYQrO1\nBcB9Wel4k3rJJK8uHg+LpHVMaZppkNaWGkMBhMbzr8qmIlcNWNi7cbMK/p5vyviy\nSwIDAQAB\n-----END PUBLIC KEY-----\n" + }, + "inbox": "https://enterprise.lemmy.ml/u/nutomic/inbox", + "preferredUsername": "Nutomic", + "endpoints": { + "sharedInbox": "https://enterprise.lemmy.ml/inbox" + }, + "summary": "some bio", + "icon": { + "type": "Image", + "url": "https://enterprise.lemmy.ml/pictrs/image/F6Z7QcWZRJ.jpg" + }, + "image": { + "type": "Image", + "url": "https://enterprise.lemmy.ml:/pictrs/image/Q79N9oCDEG.png" + }, + "published": "2020-09-14T14:54:53.080949+00:00", + "updated": "2020-10-14T10:58:28.139178+00:00", + "@context": "https://www.w3.org/ns/activitystreams", + "id": "https://enterprise.lemmy.ml/u/nutomic", + "type": "Person", + "name": "nutomic" +} diff --git a/test/fixtures/tesla_mock/sakamoto.atom b/test/fixtures/tesla_mock/sakamoto.atom deleted file mode 100644 index 648946795..000000000 --- a/test/fixtures/tesla_mock/sakamoto.atom +++ /dev/null @@ -1 +0,0 @@ -<?xml version="1.0"?><entry xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:ostatus="http://ostatus.org/schema/1.0"><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb><id>https://social.sakamoto.gq/objects/0ccc1a2c-66b0-4305-b23a-7f7f2b040056</id><title>New note by eal</title><content type="html"><a href='https://shitposter.club/user/5381'>@shpuld</a> <a href='https://pleroma.hjkos.com/users/hj'>@hj</a> IM NOT GAY DAD</content><published>2017-08-04T12:51:26.130592Z</published><updated>2017-08-04T12:51:26.130592Z</updated><ostatus:conversation>https://pleroma.hjkos.com/contexts/53093c74-2100-4bf4-aac6-66d1973d03ef</ostatus:conversation><link ref="https://pleroma.hjkos.com/contexts/53093c74-2100-4bf4-aac6-66d1973d03ef" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://social.sakamoto.gq/objects/0ccc1a2c-66b0-4305-b23a-7f7f2b040056" rel="self"/><link type="text/html" href="https://social.sakamoto.gq/objects/0ccc1a2c-66b0-4305-b23a-7f7f2b040056" rel="alternate"/><thr:in-reply-to ref="tag:shitposter.club,2017-08-04:noticeId=4027863:objectType=comment" href="https://shitposter.club/notice/4027863"/><author><id>https://social.sakamoto.gq/users/eal</id><activity:object>http://activitystrea.ms/schema/1.0/person</activity:object><uri>https://social.sakamoto.gq/users/eal</uri><poco:preferredUsername>eal</poco:preferredUsername><poco:displayName>坂本</poco:displayName><poco:note>(・ヮ・)</poco:note><name>eal</name><link rel="avatar" href="https://social.sakamoto.gq/media/7646c027-3614-4ee1-93f9-eea8f244a0d7/1A2EFE3153B9C9C3826DB511D043A26597C9F7178C8A4899FBBF808972D1659F.png"/></author><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://shitposter.club/user/5381"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://pleroma.hjkos.com/users/hj"/></entry>
\ No newline at end of file diff --git a/test/fixtures/tesla_mock/sakamoto_eal_feed.atom b/test/fixtures/tesla_mock/sakamoto_eal_feed.atom deleted file mode 100644 index 9340d9038..000000000 --- a/test/fixtures/tesla_mock/sakamoto_eal_feed.atom +++ /dev/null @@ -1 +0,0 @@ -<?xml version="1.0"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:ostatus="http://ostatus.org/schema/1.0"><id>https://social.sakamoto.gq/users/eal/feed.atom</id><title>eal's timeline</title><updated>2017-08-04T14:19:12.683854</updated><link rel="hub" href="https://social.sakamoto.gq/push/hub/eal"/><link rel="salmon" href="https://social.sakamoto.gq/users/eal/salmon"/><link rel="self" href="https://social.sakamoto.gq/users/eal/feed.atom" type="application/atom+xml"/><author><id>https://social.sakamoto.gq/users/eal</id><activity:object>http://activitystrea.ms/schema/1.0/person</activity:object><uri>https://social.sakamoto.gq/users/eal</uri><poco:preferredUsername>eal</poco:preferredUsername><poco:displayName>坂本</poco:displayName><poco:note>(・ヮ・)</poco:note><name>eal</name><link rel="avatar" href="https://social.sakamoto.gq/media/7646c027-3614-4ee1-93f9-eea8f244a0d7/1A2EFE3153B9C9C3826DB511D043A26597C9F7178C8A4899FBBF808972D1659F.png"/></author><entry><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb><id>https://social.sakamoto.gq/objects/b79a1721-23f3-45a5-9610-adb08c2afae5</id><title>New note by eal</title><content type="html">Honestly, I like all smileys that are not emoji.</content><published>2017-08-04T14:19:12.675999Z</published><updated>2017-08-04T14:19:12.675999Z</updated><ostatus:conversation>https://social.sakamoto.gq/contexts/e05ede92-8db9-4963-8b8e-e71a5797d68f</ostatus:conversation><link ref="https://social.sakamoto.gq/contexts/e05ede92-8db9-4963-8b8e-e71a5797d68f" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://social.sakamoto.gq/objects/b79a1721-23f3-45a5-9610-adb08c2afae5" rel="self"/><link type="text/html" href="https://social.sakamoto.gq/objects/b79a1721-23f3-45a5-9610-adb08c2afae5" rel="alternate"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/></entry><entry><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb><id>https://social.sakamoto.gq/objects/45475bf3-2dfc-4d9e-8eae-1f4f86f48982</id><title>New note by eal</title><content type="html">Then again, I like all smileys/emoticons that are not emoji.<br></content><published>2017-08-04T14:19:10.113373Z</published><updated>2017-08-04T14:19:10.113373Z</updated><ostatus:conversation>https://social.sakamoto.gq/contexts/852d1605-4dcb-4ba7-9ba4-dfc37ed62fbc</ostatus:conversation><link ref="https://social.sakamoto.gq/contexts/852d1605-4dcb-4ba7-9ba4-dfc37ed62fbc" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://social.sakamoto.gq/objects/45475bf3-2dfc-4d9e-8eae-1f4f86f48982" rel="self"/><link type="text/html" href="https://social.sakamoto.gq/objects/45475bf3-2dfc-4d9e-8eae-1f4f86f48982" rel="alternate"/><thr:in-reply-to ref="https://social.sakamoto.gq/objects/8f8fd6d6-cc63-40c6-a5d0-1c0e4f919368" href="https://social.sakamoto.gq/objects/8f8fd6d6-cc63-40c6-a5d0-1c0e4f919368"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://social.sakamoto.gq/users/eal"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/></entry><entry><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb><id>https://social.sakamoto.gq/objects/8f8fd6d6-cc63-40c6-a5d0-1c0e4f919368</id><title>New note by eal</title><content type="html">I love the russian-style smiley.</content><published>2017-08-04T14:18:30.478552Z</published><updated>2017-08-04T14:18:30.478552Z</updated><ostatus:conversation>https://social.sakamoto.gq/contexts/852d1605-4dcb-4ba7-9ba4-dfc37ed62fbc</ostatus:conversation><link ref="https://social.sakamoto.gq/contexts/852d1605-4dcb-4ba7-9ba4-dfc37ed62fbc" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://social.sakamoto.gq/objects/8f8fd6d6-cc63-40c6-a5d0-1c0e4f919368" rel="self"/><link type="text/html" href="https://social.sakamoto.gq/objects/8f8fd6d6-cc63-40c6-a5d0-1c0e4f919368" rel="alternate"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/></entry><entry><activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb><id>https://social.sakamoto.gq/activities/6e69df95-f2ad-4b8e-af4a-e93ff93d64e1</id><title>eal started following https://cybre.space/users/0x3F</title><content type="html">eal started following https://cybre.space/users/0x3F</content><published>2017-08-04T14:17:24.942193Z</published><updated>2017-08-04T14:17:24.942193Z</updated><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type><id>https://cybre.space/users/0x3F</id><uri>https://cybre.space/users/0x3F</uri></activity:object><link rel="self" type="application/atom+xml" href="https://social.sakamoto.gq/activities/6e69df95-f2ad-4b8e-af4a-e93ff93d64e1"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://cybre.space/users/0x3F"/></entry><entry><activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb><id>https://social.sakamoto.gq/activities/54c5e260-0185-4267-a2a6-f5dd9c76c2c9</id><title>eal started following https://niu.moe/users/rye</title><content type="html">eal started following https://niu.moe/users/rye</content><published>2017-08-04T14:16:35.604739Z</published><updated>2017-08-04T14:16:35.604739Z</updated><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type><id>https://niu.moe/users/rye</id><uri>https://niu.moe/users/rye</uri></activity:object><link rel="self" type="application/atom+xml" href="https://social.sakamoto.gq/activities/54c5e260-0185-4267-a2a6-f5dd9c76c2c9"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://niu.moe/users/rye"/></entry><entry><activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb><id>https://social.sakamoto.gq/activities/092ca863-19a8-416c-85d7-d3f23b3c0203</id><title>eal started following https://mastodon.xyz/users/rafudesu</title><content type="html">eal started following https://mastodon.xyz/users/rafudesu</content><published>2017-08-04T14:16:10.993429Z</published><updated>2017-08-04T14:16:10.993429Z</updated><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type><id>https://mastodon.xyz/users/rafudesu</id><uri>https://mastodon.xyz/users/rafudesu</uri></activity:object><link rel="self" type="application/atom+xml" href="https://social.sakamoto.gq/activities/092ca863-19a8-416c-85d7-d3f23b3c0203"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.xyz/users/rafudesu"/></entry><entry><activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb><id>https://social.sakamoto.gq/activities/be5cf702-b127-423b-a6be-5f78f01a4289</id><title>eal started following https://gs.kawa-kun.com/user/2</title><content type="html">eal started following https://gs.kawa-kun.com/user/2</content><published>2017-08-04T14:15:41.804611Z</published><updated>2017-08-04T14:15:41.804611Z</updated><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type><id>https://gs.kawa-kun.com/user/2</id><uri>https://gs.kawa-kun.com/user/2</uri></activity:object><link rel="self" type="application/atom+xml" href="https://social.sakamoto.gq/activities/be5cf702-b127-423b-a6be-5f78f01a4289"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://gs.kawa-kun.com/user/2"/></entry><entry><activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb><id>https://social.sakamoto.gq/activities/4951e2a1-9bae-4e87-8e98-e6d2f8a52338</id><title>eal started following https://gs.kawa-kun.com/user/4885</title><content type="html">eal started following https://gs.kawa-kun.com/user/4885</content><published>2017-08-04T14:15:00.135352Z</published><updated>2017-08-04T14:15:00.135352Z</updated><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type><id>https://gs.kawa-kun.com/user/4885</id><uri>https://gs.kawa-kun.com/user/4885</uri></activity:object><link rel="self" type="application/atom+xml" href="https://social.sakamoto.gq/activities/4951e2a1-9bae-4e87-8e98-e6d2f8a52338"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://gs.kawa-kun.com/user/4885"/></entry><entry><activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb><id>https://social.sakamoto.gq/activities/cadf8745-b9ee-4f6c-af32-bfddb70e4607</id><title>eal started following https://mastodon.social/users/Murassa</title><content type="html">eal started following https://mastodon.social/users/Murassa</content><published>2017-08-04T14:14:36.339560Z</published><updated>2017-08-04T14:14:36.339560Z</updated><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type><id>https://mastodon.social/users/Murassa</id><uri>https://mastodon.social/users/Murassa</uri></activity:object><link rel="self" type="application/atom+xml" href="https://social.sakamoto.gq/activities/cadf8745-b9ee-4f6c-af32-bfddb70e4607"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.social/users/Murassa"/></entry><entry><activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb><id>https://social.sakamoto.gq/activities/a52c9aab-f0e6-4ccb-8dd3-9f417e72a41c</id><title>eal started following https://mastodon.social/users/rysiek</title><content type="html">eal started following https://mastodon.social/users/rysiek</content><published>2017-08-04T14:13:04.061572Z</published><updated>2017-08-04T14:13:04.061572Z</updated><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type><id>https://mastodon.social/users/rysiek</id><uri>https://mastodon.social/users/rysiek</uri></activity:object><link rel="self" type="application/atom+xml" href="https://social.sakamoto.gq/activities/a52c9aab-f0e6-4ccb-8dd3-9f417e72a41c"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.social/users/rysiek"/></entry><entry><activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb><id>https://social.sakamoto.gq/activities/738bc887-4cca-4b36-8c86-2b54d4c54732</id><title>eal started following https://mastodon.hasameli.com/users/munin</title><content type="html">eal started following https://mastodon.hasameli.com/users/munin</content><published>2017-08-04T14:12:10.514155Z</published><updated>2017-08-04T14:12:10.514155Z</updated><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type><id>https://mastodon.hasameli.com/users/munin</id><uri>https://mastodon.hasameli.com/users/munin</uri></activity:object><link rel="self" type="application/atom+xml" href="https://social.sakamoto.gq/activities/738bc887-4cca-4b36-8c86-2b54d4c54732"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.hasameli.com/users/munin"/></entry><entry><activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb><id>https://social.sakamoto.gq/activities/dc66ad5a-b776-4180-a8aa-e4c1bf7cb703</id><title>eal started following https://cybre.space/users/nightpool</title><content type="html">eal started following https://cybre.space/users/nightpool</content><published>2017-08-04T14:11:16.046148Z</published><updated>2017-08-04T14:11:16.046148Z</updated><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type><id>https://cybre.space/users/nightpool</id><uri>https://cybre.space/users/nightpool</uri></activity:object><link rel="self" type="application/atom+xml" href="https://social.sakamoto.gq/activities/dc66ad5a-b776-4180-a8aa-e4c1bf7cb703"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://cybre.space/users/nightpool"/></entry><entry><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb><id>https://social.sakamoto.gq/objects/9c5c00d7-3ce4-4c11-b965-dc5c2bda86c5</id><title>New note by eal</title><content type="html"><a href='https://mastodon.zombocloud.com/users/staticsafe'>@staticsafe</a> privet )))</content><published>2017-08-04T14:10:08.812247Z</published><updated>2017-08-04T14:10:08.812247Z</updated><ostatus:conversation>https://social.sakamoto.gq/contexts/12a33823-0327-4c1c-a591-850ea79331b5</ostatus:conversation><link ref="https://social.sakamoto.gq/contexts/12a33823-0327-4c1c-a591-850ea79331b5" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://social.sakamoto.gq/objects/9c5c00d7-3ce4-4c11-b965-dc5c2bda86c5" rel="self"/><link type="text/html" href="https://social.sakamoto.gq/objects/9c5c00d7-3ce4-4c11-b965-dc5c2bda86c5" rel="alternate"/><thr:in-reply-to ref="tag:mastodon.zombocloud.com,2017-08-04:objectId=995766:objectType=Status" href="https://mastodon.zombocloud.com/users/staticsafe/updates/4900"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.zombocloud.com/users/staticsafe"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/></entry><entry><activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb><id>https://social.sakamoto.gq/activities/49798053-1f40-4a71-ad33-106e90630863</id><title>eal started following https://social.homunyan.com/users/animeirl</title><content type="html">eal started following https://social.homunyan.com/users/animeirl</content><published>2017-08-04T14:09:44.904792Z</published><updated>2017-08-04T14:09:44.904792Z</updated><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type><id>https://social.homunyan.com/users/animeirl</id><uri>https://social.homunyan.com/users/animeirl</uri></activity:object><link rel="self" type="application/atom+xml" href="https://social.sakamoto.gq/activities/49798053-1f40-4a71-ad33-106e90630863"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://social.homunyan.com/users/animeirl"/></entry><entry><activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb><id>https://social.sakamoto.gq/activities/2d83a1c5-70a6-45d3-9b84-59d6a70fbb17</id><title>New favorite by eal</title><content type="html">eal favorited something</content><published>2017-08-04T14:07:27.210044Z</published><updated>2017-08-04T14:07:27.210044Z</updated><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><id>https://pleroma.soykaf.com/objects/b831e52f-4ed4-438e-95b4-888897f64f09</id></activity:object><ostatus:conversation>https://pleroma.hjkos.com/contexts/3ed48205-1e72-4e19-a618-89a0d2ca811e</ostatus:conversation><link ref="https://pleroma.hjkos.com/contexts/3ed48205-1e72-4e19-a618-89a0d2ca811e" rel="ostatus:conversation"/><link rel="self" type="application/atom+xml" href="https://social.sakamoto.gq/activities/2d83a1c5-70a6-45d3-9b84-59d6a70fbb17"/><thr:in-reply-to ref="https://pleroma.soykaf.com/objects/b831e52f-4ed4-438e-95b4-888897f64f09"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://pleroma.soykaf.com/users/lain"/></entry><entry><activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb><id>https://social.sakamoto.gq/activities/06d28bed-544a-496b-8414-1c6d439273b5</id><title>New favorite by eal</title><content type="html">eal favorited something</content><published>2017-08-04T14:05:37.280200Z</published><updated>2017-08-04T14:05:37.280200Z</updated><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><id>tag:toot-lab.reclaim.technology,2017-08-04:objectId=1166030:objectType=Status</id></activity:object><ostatus:conversation>tag:p2px.me,2017-08-04:objectType=thread:nonce=f8bfc4d13db6ce91</ostatus:conversation><link ref="tag:p2px.me,2017-08-04:objectType=thread:nonce=f8bfc4d13db6ce91" rel="ostatus:conversation"/><link rel="self" type="application/atom+xml" href="https://social.sakamoto.gq/activities/06d28bed-544a-496b-8414-1c6d439273b5"/><thr:in-reply-to ref="tag:toot-lab.reclaim.technology,2017-08-04:objectId=1166030:objectType=Status"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://toot-lab.reclaim.technology/users/djsundog"/></entry><entry><activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb><id>https://social.sakamoto.gq/activities/72bf19d4-9ad4-4b2f-9cd0-f0d70f4e931b</id><title>eal started following https://mstdn.jp/users/nullkal</title><content type="html">eal started following https://mstdn.jp/users/nullkal</content><published>2017-08-04T14:05:04.148904Z</published><updated>2017-08-04T14:05:04.148904Z</updated><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type><id>https://mstdn.jp/users/nullkal</id><uri>https://mstdn.jp/users/nullkal</uri></activity:object><link rel="self" type="application/atom+xml" href="https://social.sakamoto.gq/activities/72bf19d4-9ad4-4b2f-9cd0-f0d70f4e931b"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mstdn.jp/users/nullkal"/></entry><entry><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb><id>https://social.sakamoto.gq/objects/b0e89515-7621-4e09-b23d-83e192324107</id><title>New note by eal</title><content type="html"><a href='https://p2px.me/user/1'>@stitchxd</a> test also</content><published>2017-08-04T14:04:38.699051Z</published><updated>2017-08-04T14:04:38.699051Z</updated><ostatus:conversation>tag:p2px.me,2017-08-04:objectType=thread:nonce=f8bfc4d13db6ce91</ostatus:conversation><link ref="tag:p2px.me,2017-08-04:objectType=thread:nonce=f8bfc4d13db6ce91" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://social.sakamoto.gq/objects/b0e89515-7621-4e09-b23d-83e192324107" rel="self"/><link type="text/html" href="https://social.sakamoto.gq/objects/b0e89515-7621-4e09-b23d-83e192324107" rel="alternate"/><thr:in-reply-to ref="tag:p2px.me,2017-08-04:noticeId=222109:objectType=note" href="https://p2px.me/notice/222109"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://p2px.me/user/1"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/></entry><entry><activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb><id>https://social.sakamoto.gq/activities/d8d2006b-6b23-45d6-ba27-39d27587777d</id><title>New favorite by eal</title><content type="html">eal favorited something</content><published>2017-08-04T14:04:32.106626Z</published><updated>2017-08-04T14:04:32.106626Z</updated><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><id>tag:p2px.me,2017-08-04:noticeId=222109:objectType=note</id></activity:object><ostatus:conversation>tag:p2px.me,2017-08-04:objectType=thread:nonce=f8bfc4d13db6ce91</ostatus:conversation><link ref="tag:p2px.me,2017-08-04:objectType=thread:nonce=f8bfc4d13db6ce91" rel="ostatus:conversation"/><link rel="self" type="application/atom+xml" href="https://social.sakamoto.gq/activities/d8d2006b-6b23-45d6-ba27-39d27587777d"/><thr:in-reply-to ref="tag:p2px.me,2017-08-04:noticeId=222109:objectType=note"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://p2px.me/user/1"/></entry><entry><activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb><id>https://social.sakamoto.gq/activities/cb9db95d-ec27-41fa-bebd-5375fc13acb9</id><title>eal started following https://mastodon.social/users/Gargron</title><content type="html">eal started following https://mastodon.social/users/Gargron</content><published>2017-08-04T14:04:04.325531Z</published><updated>2017-08-04T14:04:04.325531Z</updated><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type><id>https://mastodon.social/users/Gargron</id><uri>https://mastodon.social/users/Gargron</uri></activity:object><link rel="self" type="application/atom+xml" href="https://social.sakamoto.gq/activities/cb9db95d-ec27-41fa-bebd-5375fc13acb9"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.social/users/Gargron"/></entry></feed>
\ No newline at end of file diff --git a/test/fixtures/tesla_mock/shp@pleroma.soykaf.com.feed b/test/fixtures/tesla_mock/shp@pleroma.soykaf.com.feed deleted file mode 100644 index b24ef7ab6..000000000 --- a/test/fixtures/tesla_mock/shp@pleroma.soykaf.com.feed +++ /dev/null @@ -1 +0,0 @@ -<?xml version="1.0"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:ostatus="http://ostatus.org/schema/1.0"><id>https://pleroma.soykaf.com/users/shp/feed.atom</id><title>shp's timeline</title><updated>2017-09-14T08:31:48.911686</updated><link rel="hub" href="https://pleroma.soykaf.com/push/hub/shp"/><link rel="salmon" href="https://pleroma.soykaf.com/users/shp/salmon"/><link rel="self" href="https://pleroma.soykaf.com/users/shp/feed.atom" type="application/atom+xml"/><author><id>https://pleroma.soykaf.com/users/shp</id><activity:object>http://activitystrea.ms/schema/1.0/person</activity:object><uri>https://pleroma.soykaf.com/users/shp</uri><poco:preferredUsername>shp</poco:preferredUsername><poco:displayName>shp</poco:displayName><poco:note>cofe</poco:note><name>shp</name><link rel="avatar" href="https://pleroma.soykaf.com/media/745e4713-008c-4f54-bc26-4f59c37cea0e/43B7A3B2F0B9C0AA097F1B01E9EF05F7C1DCFA6868566D8A9AC211E483498643.png"/></author><entry><activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb><id>https://pleroma.soykaf.com/activities/0b5f5ef2-020a-4f9e-a92b-a2bf21224644</id><title>shp started following https://pleroma.soykaf.com/users/gooz</title><content type="html">shp started following https://pleroma.soykaf.com/users/gooz</content><published>2017-09-14T08:31:48.911226Z</published><updated>2017-09-14T08:31:48.911226Z</updated><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type><id>https://pleroma.soykaf.com/users/gooz</id><uri>https://pleroma.soykaf.com/users/gooz</uri></activity:object><link rel="self" type="application/atom+xml" href="https://pleroma.soykaf.com/activities/0b5f5ef2-020a-4f9e-a92b-a2bf21224644"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://pleroma.soykaf.com/users/gooz"/></entry><entry><activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb><id>https://pleroma.soykaf.com/activities/d928b7f7-dc10-478c-859b-cd604770da60</id><title>shp started following https://niu.moe/users/xiaoyongmao</title><content type="html">shp started following https://niu.moe/users/xiaoyongmao</content><published>2017-09-14T08:16:52.674253Z</published><updated>2017-09-14T08:16:52.674253Z</updated><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type><id>https://niu.moe/users/xiaoyongmao</id><uri>https://niu.moe/users/xiaoyongmao</uri></activity:object><link rel="self" type="application/atom+xml" href="https://pleroma.soykaf.com/activities/d928b7f7-dc10-478c-859b-cd604770da60"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://niu.moe/users/xiaoyongmao"/></entry><entry><activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb><id>https://pleroma.soykaf.com/activities/3f5089b3-f1e5-47b6-8bfe-a9c4a860e724</id><title>New favorite by shp</title><content type="html">shp favorited something</content><published>2017-09-14T08:12:18.213055Z</published><updated>2017-09-14T08:12:18.213055Z</updated><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><id>https://mastodon.xyz/users/Azurolu/statuses/8346804</id></activity:object><ostatus:conversation ref="tag:mastodon.xyz,2017-09-14:objectId=3669709:objectType=Conversation">tag:mastodon.xyz,2017-09-14:objectId=3669709:objectType=Conversation</ostatus:conversation><link ref="tag:mastodon.xyz,2017-09-14:objectId=3669709:objectType=Conversation" rel="ostatus:conversation"/><link rel="self" type="application/atom+xml" href="https://pleroma.soykaf.com/activities/3f5089b3-f1e5-47b6-8bfe-a9c4a860e724"/><thr:in-reply-to ref="https://mastodon.xyz/users/Azurolu/statuses/8346804"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.xyz/users/Azurolu"/></entry><entry><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb><id>https://pleroma.soykaf.com/objects/0def9b19-6b0f-44e0-96b3-543fa06a4010</id><title>New note by shp</title><content type="html"><a href='https://niu.moe/users/Pasty'>@Pasty</a> I love the peach<br><a href="https://pleroma.soykaf.com/media/7e8bd209-dbd4-481a-a62c-d302d68df16d/__hinanawi_tenshi_touhou_drawn_by_e_o__8c6824f52dd494f6026607570179265f.jpg" class='attachment'>__hinanawi_tenshi_touhou_drawn_…</a></content><published>2017-09-14T08:12:04.367142Z</published><updated>2017-09-14T08:12:04.367142Z</updated><ostatus:conversation ref="tag:niu.moe,2017-09-14:objectId=1660781:objectType=Conversation">tag:niu.moe,2017-09-14:objectId=1660781:objectType=Conversation</ostatus:conversation><link ref="tag:niu.moe,2017-09-14:objectId=1660781:objectType=Conversation" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://pleroma.soykaf.com/objects/0def9b19-6b0f-44e0-96b3-543fa06a4010" rel="self"/><link type="text/html" href="https://pleroma.soykaf.com/objects/0def9b19-6b0f-44e0-96b3-543fa06a4010" rel="alternate"/><link rel="enclosure" href="https://pleroma.soykaf.com/media/7e8bd209-dbd4-481a-a62c-d302d68df16d/__hinanawi_tenshi_touhou_drawn_by_e_o__8c6824f52dd494f6026607570179265f.jpg" type="image/jpeg"/><thr:in-reply-to ref="https://niu.moe/users/Pasty/statuses/3211030" href="https://niu.moe/@Pasty/3211030"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://niu.moe/users/Pasty"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/></entry><entry><activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb><id>https://pleroma.soykaf.com/activities/a4170edf-d273-4b82-931d-662aaf3872f3</id><title>New favorite by shp</title><content type="html">shp favorited something</content><published>2017-09-14T08:10:26.205104Z</published><updated>2017-09-14T08:10:26.205104Z</updated><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><id>https://niu.moe/users/NekoiNemo/statuses/3210992</id></activity:object><ostatus:conversation ref="tag:niu.moe,2017-09-14:objectId=1660761:objectType=Conversation">tag:niu.moe,2017-09-14:objectId=1660761:objectType=Conversation</ostatus:conversation><link ref="tag:niu.moe,2017-09-14:objectId=1660761:objectType=Conversation" rel="ostatus:conversation"/><link rel="self" type="application/atom+xml" href="https://pleroma.soykaf.com/activities/a4170edf-d273-4b82-931d-662aaf3872f3"/><thr:in-reply-to ref="https://niu.moe/users/NekoiNemo/statuses/3210992"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://niu.moe/users/NekoiNemo"/></entry><entry><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb><id>https://pleroma.soykaf.com/objects/c50c47a0-fac5-4781-a7e6-f20e7226d5fc</id><title>New note by shp</title><content type="html"><a href='https://freezepeach.xyz/user/3458'>@hakui</a> <a href='https://pleroma.soykaf.com/users/lain'>@lain</a> you guys are forgetting the pancakes jeez</content><published>2017-09-14T08:09:30.088418Z</published><updated>2017-09-14T08:09:30.088418Z</updated><ostatus:conversation ref="https://pleroma.soykaf.com/contexts/ac9c98ee-3eca-4b4b-9620-64b5e85e2623">https://pleroma.soykaf.com/contexts/ac9c98ee-3eca-4b4b-9620-64b5e85e2623</ostatus:conversation><link ref="https://pleroma.soykaf.com/contexts/ac9c98ee-3eca-4b4b-9620-64b5e85e2623" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://pleroma.soykaf.com/objects/c50c47a0-fac5-4781-a7e6-f20e7226d5fc" rel="self"/><link type="text/html" href="https://pleroma.soykaf.com/objects/c50c47a0-fac5-4781-a7e6-f20e7226d5fc" rel="alternate"/><thr:in-reply-to ref="tag:freezepeach.xyz,2017-09-14:noticeId=3926191:objectType=comment" href="https://freezepeach.xyz/notice/3926191"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://freezepeach.xyz/user/3458"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://pleroma.soykaf.com/users/lain"/></entry><entry><activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb><id>https://pleroma.soykaf.com/activities/2af9f622-5986-483c-83a1-ac59a9035b50</id><title>New favorite by shp</title><content type="html">shp favorited something</content><published>2017-09-14T08:09:16.346235Z</published><updated>2017-09-14T08:09:16.346235Z</updated><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><id>tag:freezepeach.xyz,2017-09-14:noticeId=3926191:objectType=comment</id></activity:object><ostatus:conversation ref="https://pleroma.soykaf.com/contexts/ac9c98ee-3eca-4b4b-9620-64b5e85e2623">https://pleroma.soykaf.com/contexts/ac9c98ee-3eca-4b4b-9620-64b5e85e2623</ostatus:conversation><link ref="https://pleroma.soykaf.com/contexts/ac9c98ee-3eca-4b4b-9620-64b5e85e2623" rel="ostatus:conversation"/><link rel="self" type="application/atom+xml" href="https://pleroma.soykaf.com/activities/2af9f622-5986-483c-83a1-ac59a9035b50"/><thr:in-reply-to ref="tag:freezepeach.xyz,2017-09-14:noticeId=3926191:objectType=comment"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://freezepeach.xyz/user/3458"/></entry><entry><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb><id>https://pleroma.soykaf.com/objects/f52aad69-5828-4e0e-bb7b-f2f0869d3ff0</id><title>New note by shp</title><content type="html"><a href='https://gs.smuglo.li/user/253'>@kro</a> I'll probs try some of those 2hu mangos</content><published>2017-09-14T08:09:13.262835Z</published><updated>2017-09-14T08:09:13.262835Z</updated><ostatus:conversation ref="tag:gs.smuglo.li,2017-09-14:objectType=thread:nonce=c4ac2016e07c4123">tag:gs.smuglo.li,2017-09-14:objectType=thread:nonce=c4ac2016e07c4123</ostatus:conversation><link ref="tag:gs.smuglo.li,2017-09-14:objectType=thread:nonce=c4ac2016e07c4123" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://pleroma.soykaf.com/objects/f52aad69-5828-4e0e-bb7b-f2f0869d3ff0" rel="self"/><link type="text/html" href="https://pleroma.soykaf.com/objects/f52aad69-5828-4e0e-bb7b-f2f0869d3ff0" rel="alternate"/><thr:in-reply-to ref="tag:gs.smuglo.li,2017-09-14:noticeId=4113226:objectType=comment" href="https://gs.smuglo.li/notice/4113226"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://gs.smuglo.li/user/253"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/></entry><entry><activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb><id>https://pleroma.soykaf.com/activities/35743658-efee-46cf-9cdf-487b95709cd5</id><title>New favorite by shp</title><content type="html">shp favorited something</content><published>2017-09-14T08:09:00.517534Z</published><updated>2017-09-14T08:09:00.517534Z</updated><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><id>tag:gs.smuglo.li,2017-09-14:noticeId=4113226:objectType=comment</id></activity:object><ostatus:conversation ref="tag:gs.smuglo.li,2017-09-14:objectType=thread:nonce=c4ac2016e07c4123">tag:gs.smuglo.li,2017-09-14:objectType=thread:nonce=c4ac2016e07c4123</ostatus:conversation><link ref="tag:gs.smuglo.li,2017-09-14:objectType=thread:nonce=c4ac2016e07c4123" rel="ostatus:conversation"/><link rel="self" type="application/atom+xml" href="https://pleroma.soykaf.com/activities/35743658-efee-46cf-9cdf-487b95709cd5"/><thr:in-reply-to ref="tag:gs.smuglo.li,2017-09-14:noticeId=4113226:objectType=comment"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://gs.smuglo.li/user/253"/></entry><entry><activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb><id>https://pleroma.soykaf.com/activities/22258ba8-58dc-4e09-b476-fe28d3307377</id><title>New favorite by shp</title><content type="html">shp favorited something</content><published>2017-09-14T08:08:38.087136Z</published><updated>2017-09-14T08:08:38.087136Z</updated><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><id>https://pleroma.soykaf.com/objects/13d7809e-5dca-4117-8738-887759392f2c</id></activity:object><ostatus:conversation ref="https://pleroma.soykaf.com/contexts/ac9c98ee-3eca-4b4b-9620-64b5e85e2623">https://pleroma.soykaf.com/contexts/ac9c98ee-3eca-4b4b-9620-64b5e85e2623</ostatus:conversation><link ref="https://pleroma.soykaf.com/contexts/ac9c98ee-3eca-4b4b-9620-64b5e85e2623" rel="ostatus:conversation"/><link rel="self" type="application/atom+xml" href="https://pleroma.soykaf.com/activities/22258ba8-58dc-4e09-b476-fe28d3307377"/><thr:in-reply-to ref="https://pleroma.soykaf.com/objects/13d7809e-5dca-4117-8738-887759392f2c"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://pleroma.soykaf.com/users/lain"/></entry><entry><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb><id>https://pleroma.soykaf.com/objects/f56d640a-0dbd-48af-80b1-06d0dbd26774</id><title>New note by shp</title><content type="html"><a href='https://social.sakamoto.gq/users/eal'>@eal</a> ...but neither does my phone<br><br>low brightness, very dark wallpaper (pic related, but even darker, couldn't find the actual version)<br><a href="https://pleroma.soykaf.com/media/6d1b8d57-80ae-41d6-bdea-58fea09ecdf4/phonewallpaper.png" class='attachment'>phonewallpaper.png</a></content><published>2017-09-14T08:07:23.081214Z</published><updated>2017-09-14T08:07:23.081214Z</updated><ostatus:conversation ref="https://pleroma.soykaf.com/contexts/f4c5d56e-fc58-467b-a8a5-10515c012355">https://pleroma.soykaf.com/contexts/f4c5d56e-fc58-467b-a8a5-10515c012355</ostatus:conversation><link ref="https://pleroma.soykaf.com/contexts/f4c5d56e-fc58-467b-a8a5-10515c012355" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://pleroma.soykaf.com/objects/f56d640a-0dbd-48af-80b1-06d0dbd26774" rel="self"/><link type="text/html" href="https://pleroma.soykaf.com/objects/f56d640a-0dbd-48af-80b1-06d0dbd26774" rel="alternate"/><link rel="enclosure" href="https://pleroma.soykaf.com/media/6d1b8d57-80ae-41d6-bdea-58fea09ecdf4/phonewallpaper.png" type="image/png"/><thr:in-reply-to ref="https://social.sakamoto.gq/objects/3fa38f35-47ef-4286-ad22-c953643f0bbb" href="https://social.sakamoto.gq/objects/3fa38f35-47ef-4286-ad22-c953643f0bbb"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://social.sakamoto.gq/users/eal"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/></entry><entry><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb><id>https://pleroma.soykaf.com/objects/d313df1d-121c-4ab8-abd1-e6aedcf55cbd</id><title>New note by shp</title><content type="html"><a href='https://niu.moe/users/Pasty'>@Pasty</a> y-you too</content><published>2017-09-14T07:55:26.153486Z</published><updated>2017-09-14T07:55:26.153486Z</updated><ostatus:conversation ref="tag:niu.moe,2017-09-14:objectId=1660616:objectType=Conversation">tag:niu.moe,2017-09-14:objectId=1660616:objectType=Conversation</ostatus:conversation><link ref="tag:niu.moe,2017-09-14:objectId=1660616:objectType=Conversation" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://pleroma.soykaf.com/objects/d313df1d-121c-4ab8-abd1-e6aedcf55cbd" rel="self"/><link type="text/html" href="https://pleroma.soykaf.com/objects/d313df1d-121c-4ab8-abd1-e6aedcf55cbd" rel="alternate"/><thr:in-reply-to ref="https://niu.moe/users/Pasty/statuses/3210773" href="https://niu.moe/@Pasty/3210773"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://niu.moe/users/Pasty"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/></entry><entry><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb><id>https://pleroma.soykaf.com/objects/7b642424-4edb-48cc-8711-1eafb4745269</id><title>New note by shp</title><content type="html"><a href='https://social.sakamoto.gq/users/eal'>@eal</a> bothers me more when sleeping, wore one for nearly 2 years</content><published>2017-09-14T07:54:53.449227Z</published><updated>2017-09-14T07:54:53.449227Z</updated><ostatus:conversation ref="https://pleroma.soykaf.com/contexts/f4c5d56e-fc58-467b-a8a5-10515c012355">https://pleroma.soykaf.com/contexts/f4c5d56e-fc58-467b-a8a5-10515c012355</ostatus:conversation><link ref="https://pleroma.soykaf.com/contexts/f4c5d56e-fc58-467b-a8a5-10515c012355" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://pleroma.soykaf.com/objects/7b642424-4edb-48cc-8711-1eafb4745269" rel="self"/><link type="text/html" href="https://pleroma.soykaf.com/objects/7b642424-4edb-48cc-8711-1eafb4745269" rel="alternate"/><thr:in-reply-to ref="https://social.sakamoto.gq/objects/ac9e8340-5427-44d3-b29e-ef006133daaa" href="https://social.sakamoto.gq/objects/ac9e8340-5427-44d3-b29e-ef006133daaa"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://social.sakamoto.gq/users/eal"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/></entry><entry><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb><id>https://pleroma.soykaf.com/objects/5bc1bff1-88c3-489d-8efd-7e4755690a18</id><title>New note by shp</title><content type="html">quick test</content><published>2017-09-14T07:54:09.045525Z</published><updated>2017-09-14T07:54:09.045525Z</updated><ostatus:conversation ref="https://pleroma.soykaf.com/contexts/cd770c2a-408e-4895-988c-60319298f219">https://pleroma.soykaf.com/contexts/cd770c2a-408e-4895-988c-60319298f219</ostatus:conversation><link ref="https://pleroma.soykaf.com/contexts/cd770c2a-408e-4895-988c-60319298f219" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://pleroma.soykaf.com/objects/5bc1bff1-88c3-489d-8efd-7e4755690a18" rel="self"/><link type="text/html" href="https://pleroma.soykaf.com/objects/5bc1bff1-88c3-489d-8efd-7e4755690a18" rel="alternate"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/></entry><entry><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb><id>https://pleroma.soykaf.com/objects/956f1fb5-6f2f-433e-ab71-7f732b76f4be</id><title>New note by shp</title><content type="html">had some trouble getting sleep last night. only used phone to check the time a few times (v essential to have a near-black wallpaper to not blind yourself when you do that). can't rember the last time I rolled in the bed for longer than an hour like that</content><published>2017-09-14T07:51:23.557775Z</published><updated>2017-09-14T07:51:23.557775Z</updated><ostatus:conversation ref="https://pleroma.soykaf.com/contexts/f4c5d56e-fc58-467b-a8a5-10515c012355">https://pleroma.soykaf.com/contexts/f4c5d56e-fc58-467b-a8a5-10515c012355</ostatus:conversation><link ref="https://pleroma.soykaf.com/contexts/f4c5d56e-fc58-467b-a8a5-10515c012355" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://pleroma.soykaf.com/objects/956f1fb5-6f2f-433e-ab71-7f732b76f4be" rel="self"/><link type="text/html" href="https://pleroma.soykaf.com/objects/956f1fb5-6f2f-433e-ab71-7f732b76f4be" rel="alternate"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/></entry><entry><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb><id>https://pleroma.soykaf.com/objects/d935d9f2-ebc7-4ff2-b65a-fbf418a60935</id><title>New note by shp</title><content type="html"><a href='https://gs.smuglo.li/user/253'>@kro</a> doesn't sound like a bad idea at all</content><published>2017-09-14T07:49:55.702555Z</published><updated>2017-09-14T07:49:55.702555Z</updated><ostatus:conversation ref="tag:gs.smuglo.li,2017-09-14:objectType=thread:nonce=c4ac2016e07c4123">tag:gs.smuglo.li,2017-09-14:objectType=thread:nonce=c4ac2016e07c4123</ostatus:conversation><link ref="tag:gs.smuglo.li,2017-09-14:objectType=thread:nonce=c4ac2016e07c4123" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://pleroma.soykaf.com/objects/d935d9f2-ebc7-4ff2-b65a-fbf418a60935" rel="self"/><link type="text/html" href="https://pleroma.soykaf.com/objects/d935d9f2-ebc7-4ff2-b65a-fbf418a60935" rel="alternate"/><thr:in-reply-to ref="tag:gs.smuglo.li,2017-09-14:noticeId=4113170:objectType=comment" href="https://gs.smuglo.li/notice/4113170"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://gs.smuglo.li/user/253"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/></entry><entry><activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb><id>https://pleroma.soykaf.com/activities/342c8803-ee16-487d-9488-a39d763073f6</id><title>New favorite by shp</title><content type="html">shp favorited something</content><published>2017-09-14T07:49:41.875840Z</published><updated>2017-09-14T07:49:41.875840Z</updated><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><id>tag:anticapitalist.party,2017-09-14:objectId=3322865:objectType=Status</id></activity:object><ostatus:conversation ref="tag:anticapitalist.party,2017-09-14:objectId=1251751:objectType=Conversation">tag:anticapitalist.party,2017-09-14:objectId=1251751:objectType=Conversation</ostatus:conversation><link ref="tag:anticapitalist.party,2017-09-14:objectId=1251751:objectType=Conversation" rel="ostatus:conversation"/><link rel="self" type="application/atom+xml" href="https://pleroma.soykaf.com/activities/342c8803-ee16-487d-9488-a39d763073f6"/><thr:in-reply-to ref="tag:anticapitalist.party,2017-09-14:objectId=3322865:objectType=Status"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://anticapitalist.party/users/Concerned_Commy"/></entry><entry><activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb><id>https://pleroma.soykaf.com/activities/5d98a19b-dd55-4077-9841-142937c613ad</id><title>New favorite by shp</title><content type="html">shp favorited something</content><published>2017-09-14T07:49:30.584265Z</published><updated>2017-09-14T07:49:30.584265Z</updated><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><id>tag:gs.smuglo.li,2017-09-14:noticeId=4113170:objectType=comment</id></activity:object><ostatus:conversation ref="tag:gs.smuglo.li,2017-09-14:objectType=thread:nonce=c4ac2016e07c4123">tag:gs.smuglo.li,2017-09-14:objectType=thread:nonce=c4ac2016e07c4123</ostatus:conversation><link ref="tag:gs.smuglo.li,2017-09-14:objectType=thread:nonce=c4ac2016e07c4123" rel="ostatus:conversation"/><link rel="self" type="application/atom+xml" href="https://pleroma.soykaf.com/activities/5d98a19b-dd55-4077-9841-142937c613ad"/><thr:in-reply-to ref="tag:gs.smuglo.li,2017-09-14:noticeId=4113170:objectType=comment"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://gs.smuglo.li/user/253"/></entry><entry><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb><id>https://pleroma.soykaf.com/objects/fdf3626a-50ba-458b-9bf7-b5f2cfa505fc</id><title>New note by shp</title><content type="html"><a href='https://pleroma.hjkos.com/users/hj'>@hj</a> c time</content><published>2017-09-14T07:48:52.805422Z</published><updated>2017-09-14T07:48:52.805422Z</updated><ostatus:conversation ref="https://pleroma.hjkos.com/contexts/dc4a3a3e-d366-4c0c-8789-8a9bee3537d9">https://pleroma.hjkos.com/contexts/dc4a3a3e-d366-4c0c-8789-8a9bee3537d9</ostatus:conversation><link ref="https://pleroma.hjkos.com/contexts/dc4a3a3e-d366-4c0c-8789-8a9bee3537d9" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://pleroma.soykaf.com/objects/fdf3626a-50ba-458b-9bf7-b5f2cfa505fc" rel="self"/><link type="text/html" href="https://pleroma.soykaf.com/objects/fdf3626a-50ba-458b-9bf7-b5f2cfa505fc" rel="alternate"/><thr:in-reply-to ref="https://pleroma.hjkos.com/objects/581c2769-8981-43d1-b47b-815aa1282c26" href="https://pleroma.hjkos.com/objects/581c2769-8981-43d1-b47b-815aa1282c26"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://pleroma.hjkos.com/users/hj"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/></entry><entry><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb><id>https://pleroma.soykaf.com/objects/c7c8eb17-b669-4827-9fbc-90f1fc54e4b1</id><title>New note by shp</title><content type="html"><a href='https://sunshinegardens.org/users/tbny'>@tbny</a> err.. mediterranean from finnish*</content><published>2017-09-14T07:46:52.764234Z</published><updated>2017-09-14T07:46:52.764234Z</updated><ostatus:conversation ref="https://pleroma.soykaf.com/contexts/ac9c98ee-3eca-4b4b-9620-64b5e85e2623">https://pleroma.soykaf.com/contexts/ac9c98ee-3eca-4b4b-9620-64b5e85e2623</ostatus:conversation><link ref="https://pleroma.soykaf.com/contexts/ac9c98ee-3eca-4b4b-9620-64b5e85e2623" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://pleroma.soykaf.com/objects/c7c8eb17-b669-4827-9fbc-90f1fc54e4b1" rel="self"/><link type="text/html" href="https://pleroma.soykaf.com/objects/c7c8eb17-b669-4827-9fbc-90f1fc54e4b1" rel="alternate"/><thr:in-reply-to ref="https://pleroma.soykaf.com/objects/15ea896c-c943-4b65-8f31-d6cda91a52fd" href="https://pleroma.soykaf.com/objects/15ea896c-c943-4b65-8f31-d6cda91a52fd"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://pleroma.soykaf.com/users/shp"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://sunshinegardens.org/users/tbny"/></entry></feed>
\ No newline at end of file diff --git a/test/fixtures/tesla_mock/spc_5381.atom b/test/fixtures/tesla_mock/spc_5381.atom deleted file mode 100644 index c3288e97b..000000000 --- a/test/fixtures/tesla_mock/spc_5381.atom +++ /dev/null @@ -1,438 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:georss="http://www.georss.org/georss" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:media="http://purl.org/syndication/atommedia" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:statusnet="http://status.net/schema/api/1/"> - <generator uri="https://gnu.io/social" version="1.2.0-beta4">GNU social</generator> - <id>https://shitposter.club/api/statuses/user_timeline/5381.atom</id> - <title>shpuld timeline</title> - <subtitle>Updates from shpuld on Shitposter Club!</subtitle> - <logo>https://shitposter.club/avatar/5381-96-20171230093854.png</logo> - <updated>2018-02-23T13:42:22+00:00</updated> -<author> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://shitposter.club/user/5381</uri> - <name>shpuld</name> - <link rel="alternate" type="text/html" href="https://shitposter.club/shpuld"/> - <link rel="avatar" type="image/png" media:width="864" media:height="864" href="https://shitposter.club/avatar/5381-original-20171230093854.png"/> - <link rel="avatar" type="image/png" media:width="96" media:height="96" href="https://shitposter.club/avatar/5381-96-20171230093854.png"/> - <link rel="avatar" type="image/png" media:width="48" media:height="48" href="https://shitposter.club/avatar/5381-48-20171230093854.png"/> - <link rel="avatar" type="image/png" media:width="24" media:height="24" href="https://shitposter.club/avatar/5381-24-20171230093900.png"/> - <poco:preferredUsername>shpuld</poco:preferredUsername> - <poco:displayName>shp</poco:displayName> - <followers url="https://shitposter.club/shpuld/subscribers"></followers> - <statusnet:profile_info local_id="5381"></statusnet:profile_info> -</author> - <link href="https://shitposter.club/shpuld" rel="alternate" type="text/html"/> - <link href="https://shitposter.club/main/sup" rel="http://api.friendfeed.com/2008/03#sup" type="application/json"/> - <link href="https://shitposter.club/api/statuses/user_timeline/5381.atom?max_id=7387342" rel="next" type="application/atom+xml"/> - <link href="https://shitposter.club/main/push/hub" rel="hub"/> - <link href="https://shitposter.club/main/salmon/user/5381" rel="salmon"/> - <link href="https://shitposter.club/main/salmon/user/5381" rel="http://salmon-protocol.org/ns/salmon-replies"/> - <link href="https://shitposter.club/main/salmon/user/5381" rel="http://salmon-protocol.org/ns/salmon-mention"/> - <link href="https://shitposter.club/api/statuses/user_timeline/5381.atom" rel="self" type="application/atom+xml"/> -<entry> - <id>tag:shitposter.club,2018-02-23:fave:5381:comment:7387801:2018-02-23T13:39:40+00:00</id> - <title>Favorite</title> - <content type="html">shpuld favorited something by mayuutann: <p><span class="h-card"><a href="https://freezepeach.xyz/hakui" class="u-url mention">@<span>hakui</span></a></span> <span class="h-card"><a href="https://gs.smuglo.li/histoire" class="u-url mention">@<span>histoire</span></a></span> <span class="h-card"><a href="https://shitposter.club/shpuld" class="u-url mention">@<span>shpuld</span></a></span> <a href="https://mstdn.io/media/_Ee-x91XN0udpfZVO_U" rel="nofollow"><span class="invisible">https://</span><span class="ellipsis">mstdn.io/media/_Ee-x91XN0udpfZ</span><span class="invisible">VO_U</span></a></p></content> - <link rel="alternate" type="text/html" href="https://shitposter.club/notice/7387804"/> - <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb> - <published>2018-02-23T13:39:40+00:00</published> - <updated>2018-02-23T13:39:40+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>https://mstdn.io/users/mayuutann/statuses/99574950785668071</id> - <title>New comment by mayuutann</title> - <content type="html"><p><span class="h-card"><a href="https://freezepeach.xyz/hakui" class="u-url mention">@<span>hakui</span></a></span> <span class="h-card"><a href="https://gs.smuglo.li/histoire" class="u-url mention">@<span>histoire</span></a></span> <span class="h-card"><a href="https://shitposter.club/shpuld" class="u-url mention">@<span>shpuld</span></a></span> <a href="https://mstdn.io/media/_Ee-x91XN0udpfZVO_U" rel="nofollow"><span class="invisible">https://</span><span class="ellipsis">mstdn.io/media/_Ee-x91XN0udpfZ</span><span class="invisible">VO_U</span></a></p></content> - <link rel="alternate" type="text/html" href="https://mstdn.io/@mayuutann/99574950785668071"/> - <status_net notice_id="7387801"></status_net> - </activity:object> - <thr:in-reply-to ref="https://mstdn.io/users/mayuutann/statuses/99574950785668071" href="https://mstdn.io/@mayuutann/99574950785668071"></thr:in-reply-to> - <link rel="related" href="https://mstdn.io/@mayuutann/99574950785668071"/> - <link rel="ostatus:conversation" href="https://shitposter.club/conversation/4389848"/> - <ostatus:conversation href="https://shitposter.club/conversation/4389848" local_id="4389848" ref="https://freezepeach.xyz/conversation/4182511">https://freezepeach.xyz/conversation/4182511</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387804.atom"/> - <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387804.atom"/> - <statusnet:notice_info local_id="7387804" source="unknown"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>tag:shitposter.club,2018-02-23:noticeId=7387723:objectType=comment</id> - <title>New comment by shpuld</title> - <content type="html">@<a href="https://freezepeach.xyz/user/3458" class="h-card mention" title="&#x5FA1;&#x5712;&#x306F;&#x304F;&#x3044;">hakui</a> @<a href="https://pleroma.soykaf.com/users/lain" class="h-card mention" title="&#x2468; lain &#x2468;">lain</a> how naive~</content> - <link rel="alternate" type="text/html" href="https://shitposter.club/notice/7387723"/> - <status_net notice_id="7387723"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2018-02-23T13:30:15+00:00</published> - <updated>2018-02-23T13:30:15+00:00</updated> - <thr:in-reply-to ref="tag:freezepeach.xyz,2018-02-23:noticeId=6451587:objectType=comment" href="https://freezepeach.xyz/notice/6451587"></thr:in-reply-to> - <link rel="related" href="https://freezepeach.xyz/notice/6451587"/> - <link rel="ostatus:conversation" href="https://shitposter.club/conversation/4389967"/> - <ostatus:conversation href="https://shitposter.club/conversation/4389967" local_id="4389967" ref="tag:shitposter.club,2018-02-23:objectType=thread:nonce=2f09acf104aebfe3">tag:shitposter.club,2018-02-23:objectType=thread:nonce=2f09acf104aebfe3</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://freezepeach.xyz/user/3458"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://pleroma.soykaf.com/users/lain"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387723.atom"/> - <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387723.atom"/> - <statusnet:notice_info local_id="7387723" source="Pleroma FE"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>tag:shitposter.club,2018-02-23:noticeId=7387703:objectType=comment</id> - <title>New comment by shpuld</title> - <content type="html">@<a href="https://freezepeach.xyz/user/3458" class="h-card mention" title="&#x5FA1;&#x5712;&#x306F;&#x304F;&#x3044;">hakui</a> @<a href="https://pleroma.soykaf.com/users/lain" class="h-card mention" title="&#x2468; lain &#x2468;">lain</a> you expect anyone to believe that??</content> - <link rel="alternate" type="text/html" href="https://shitposter.club/notice/7387703"/> - <status_net notice_id="7387703"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2018-02-23T13:28:08+00:00</published> - <updated>2018-02-23T13:28:08+00:00</updated> - <thr:in-reply-to ref="tag:freezepeach.xyz,2018-02-23:noticeId=6451569:objectType=comment" href="https://freezepeach.xyz/notice/6451569"></thr:in-reply-to> - <link rel="related" href="https://freezepeach.xyz/notice/6451569"/> - <link rel="ostatus:conversation" href="https://shitposter.club/conversation/4389967"/> - <ostatus:conversation href="https://shitposter.club/conversation/4389967" local_id="4389967" ref="tag:shitposter.club,2018-02-23:objectType=thread:nonce=2f09acf104aebfe3">tag:shitposter.club,2018-02-23:objectType=thread:nonce=2f09acf104aebfe3</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://freezepeach.xyz/user/3458"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://pleroma.soykaf.com/users/lain"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387703.atom"/> - <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387703.atom"/> - <statusnet:notice_info local_id="7387703" source="Pleroma FE"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>tag:shitposter.club,2018-02-23:noticeId=7387639:objectType=comment</id> - <title>New comment by shpuld</title> - <content type="html">@<a href="https://mstdn.io/users/mayuutann" class="h-card mention" title="Mayutan&#x2615;">mayuutann</a> @<a href="https://freezepeach.xyz/user/3458" class="h-card mention" title="&#x5FA1;&#x5712;&#x306F;&#x304F;&#x3044;">hakui</a> pacyuri!! <a href="https://shitposter.club/file/eea140be45df3f993c4533026bf9a78fe8facd296d2fa0c6d02b2e347c5dc30e.jpg" title="https://shitposter.club/file/eea140be45df3f993c4533026bf9a78fe8facd296d2fa0c6d02b2e347c5dc30e.jpg" class="attachment" id="attachment-1589462" rel="nofollow external">https://shitposter.club/attachment/1589462</a></content> - <link rel="alternate" type="text/html" href="https://shitposter.club/notice/7387639"/> - <status_net notice_id="7387639"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2018-02-23T13:20:38+00:00</published> - <updated>2018-02-23T13:20:38+00:00</updated> - <thr:in-reply-to ref="https://mstdn.io/users/mayuutann/statuses/99574870416888767" href="https://mstdn.io/@mayuutann/99574870416888767"></thr:in-reply-to> - <link rel="related" href="https://mstdn.io/@mayuutann/99574870416888767"/> - <link rel="ostatus:conversation" href="https://shitposter.club/conversation/4390261"/> - <ostatus:conversation href="https://shitposter.club/conversation/4390261" local_id="4390261" ref="https://freezepeach.xyz/conversation/4183220">https://freezepeach.xyz/conversation/4183220</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://freezepeach.xyz/user/3458"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mstdn.io/users/mayuutann"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="enclosure" href="https://shitposter.club/file/eea140be45df3f993c4533026bf9a78fe8facd296d2fa0c6d02b2e347c5dc30e.jpg" type="image/jpeg" length="42186"/> - <link rel="self" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387639.atom"/> - <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387639.atom"/> - <statusnet:notice_info local_id="7387639" source="Pleroma FE"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>tag:shitposter.club,2018-02-23:noticeId=7387611:objectType=comment</id> - <title>New comment by shpuld</title> - <content type="html">@<a href="https://freezepeach.xyz/user/3458" class="h-card mention" title="&#x5FA1;&#x5712;&#x306F;&#x304F;&#x3044;">hakui</a> why is pacyu eating a pizza so cute</content> - <link rel="alternate" type="text/html" href="https://shitposter.club/notice/7387611"/> - <status_net notice_id="7387611"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2018-02-23T13:18:07+00:00</published> - <updated>2018-02-23T13:18:07+00:00</updated> - <thr:in-reply-to ref="tag:freezepeach.xyz,2018-02-23:noticeId=6451402:objectType=comment" href="https://freezepeach.xyz/notice/6451402"></thr:in-reply-to> - <link rel="related" href="https://freezepeach.xyz/notice/6451402"/> - <link rel="ostatus:conversation" href="https://shitposter.club/conversation/4390261"/> - <ostatus:conversation href="https://shitposter.club/conversation/4390261" local_id="4390261" ref="https://freezepeach.xyz/conversation/4183220">https://freezepeach.xyz/conversation/4183220</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://freezepeach.xyz/user/3458"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387611.atom"/> - <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387611.atom"/> - <statusnet:notice_info local_id="7387611" source="Pleroma FE"></statusnet:notice_info> -</entry> -<entry> - <id>tag:shitposter.club,2018-02-23:fave:5381:comment:7387600:2018-02-23T13:17:52+00:00</id> - <title>Favorite</title> - <content type="html">shpuld favorited something by mayuutann: <p><span class="h-card"><a href="https://shitposter.club/shpuld" class="u-url mention">@<span>shpuld</span></a></span> <span class="h-card"><a href="https://gs.smuglo.li/histoire" class="u-url mention">@<span>histoire</span></a></span> <span class="h-card"><a href="https://freezepeach.xyz/hakui" class="u-url mention">@<span>hakui</span></a></span> pichu! <a href="https://mstdn.io/media/Crv5eubz1KO0dgBEulI" rel="nofollow"><span class="invisible">https://</span><span class="ellipsis">mstdn.io/media/Crv5eubz1KO0dgB</span><span class="invisible">EulI</span></a></p></content> - <link rel="alternate" type="text/html" href="https://shitposter.club/notice/7387606"/> - <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb> - <published>2018-02-23T13:17:52+00:00</published> - <updated>2018-02-23T13:17:52+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>https://mstdn.io/users/mayuutann/statuses/99574863865459283</id> - <title>New comment by mayuutann</title> - <content type="html"><p><span class="h-card"><a href="https://shitposter.club/shpuld" class="u-url mention">@<span>shpuld</span></a></span> <span class="h-card"><a href="https://gs.smuglo.li/histoire" class="u-url mention">@<span>histoire</span></a></span> <span class="h-card"><a href="https://freezepeach.xyz/hakui" class="u-url mention">@<span>hakui</span></a></span> pichu! <a href="https://mstdn.io/media/Crv5eubz1KO0dgBEulI" rel="nofollow"><span class="invisible">https://</span><span class="ellipsis">mstdn.io/media/Crv5eubz1KO0dgB</span><span class="invisible">EulI</span></a></p></content> - <link rel="alternate" type="text/html" href="https://mstdn.io/@mayuutann/99574863865459283"/> - <status_net notice_id="7387600"></status_net> - </activity:object> - <thr:in-reply-to ref="https://mstdn.io/users/mayuutann/statuses/99574863865459283" href="https://mstdn.io/@mayuutann/99574863865459283"></thr:in-reply-to> - <link rel="related" href="https://mstdn.io/@mayuutann/99574863865459283"/> - <link rel="ostatus:conversation" href="https://shitposter.club/conversation/4389848"/> - <ostatus:conversation href="https://shitposter.club/conversation/4389848" local_id="4389848" ref="https://freezepeach.xyz/conversation/4182511">https://freezepeach.xyz/conversation/4182511</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387606.atom"/> - <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387606.atom"/> - <statusnet:notice_info local_id="7387606" source="unknown"></statusnet:notice_info> -</entry> -<entry> - <id>tag:shitposter.club,2018-02-23:fave:5381:comment:7387544:2018-02-23T13:12:43+00:00</id> - <title>Favorite</title> - <content type="html">shpuld favorited something by mayuutann: <p><span class="h-card"><a href="https://shitposter.club/shpuld" class="u-url mention">@<span>shpuld</span></a></span> wa~~i!! :blobcheer:</p></content> - <link rel="alternate" type="text/html" href="https://shitposter.club/notice/7387557"/> - <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb> - <published>2018-02-23T13:12:43+00:00</published> - <updated>2018-02-23T13:12:43+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>https://mstdn.io/users/mayuutann/statuses/99574840290947233</id> - <title>New comment by mayuutann</title> - <content type="html"><p><span class="h-card"><a href="https://shitposter.club/shpuld" class="u-url mention">@<span>shpuld</span></a></span> wa~~i!! :blobcheer:</p></content> - <link rel="alternate" type="text/html" href="https://mstdn.io/@mayuutann/99574840290947233"/> - <status_net notice_id="7387544"></status_net> - </activity:object> - <thr:in-reply-to ref="https://mstdn.io/users/mayuutann/statuses/99574840290947233" href="https://mstdn.io/@mayuutann/99574840290947233"></thr:in-reply-to> - <link rel="related" href="https://mstdn.io/@mayuutann/99574840290947233"/> - <link rel="ostatus:conversation" href="https://shitposter.club/conversation/4390030"/> - <ostatus:conversation href="https://shitposter.club/conversation/4390030" local_id="4390030" ref="tag:shitposter.club,2018-02-23:objectType=thread:nonce=d05e2b056274c5ab">tag:shitposter.club,2018-02-23:objectType=thread:nonce=d05e2b056274c5ab</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387557.atom"/> - <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387557.atom"/> - <statusnet:notice_info local_id="7387557" source="unknown"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>tag:shitposter.club,2018-02-23:noticeId=7387555:objectType=comment</id> - <title>New comment by shpuld</title> - <content type="html">@<a href="https://freezepeach.xyz/user/3458" class="h-card mention" title="&#x5FA1;&#x5712;&#x306F;&#x304F;&#x3044;">hakui</a> more!!</content> - <link rel="alternate" type="text/html" href="https://shitposter.club/notice/7387555"/> - <status_net notice_id="7387555"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2018-02-23T13:12:23+00:00</published> - <updated>2018-02-23T13:12:23+00:00</updated> - <thr:in-reply-to ref="tag:freezepeach.xyz,2018-02-23:noticeId=6451332:objectType=note" href="https://freezepeach.xyz/notice/6451332"></thr:in-reply-to> - <link rel="related" href="https://freezepeach.xyz/notice/6451332"/> - <link rel="ostatus:conversation" href="https://shitposter.club/conversation/4390261"/> - <ostatus:conversation href="https://shitposter.club/conversation/4390261" local_id="4390261" ref="https://freezepeach.xyz/conversation/4183220">https://freezepeach.xyz/conversation/4183220</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://freezepeach.xyz/user/3458"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387555.atom"/> - <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387555.atom"/> - <statusnet:notice_info local_id="7387555" source="Pleroma FE"></statusnet:notice_info> -</entry> -<entry> - <id>tag:shitposter.club,2018-02-23:fave:5381:note:7387537:2018-02-23T13:12:19+00:00</id> - <title>Favorite</title> - <content type="html">shpuld favorited something by hakui: you have pacyupacyu'd for: 45 minutes 03 seconds</content> - <link rel="alternate" type="text/html" href="https://shitposter.club/notice/7387553"/> - <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb> - <published>2018-02-23T13:12:19+00:00</published> - <updated>2018-02-23T13:12:19+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:freezepeach.xyz,2018-02-23:noticeId=6451332:objectType=note</id> - <title>New note by hakui</title> - <content type="html">you have pacyupacyu'd for: 45 minutes 03 seconds</content> - <link rel="alternate" type="text/html" href="https://freezepeach.xyz/notice/6451332"/> - <status_net notice_id="7387537"></status_net> - </activity:object> - <thr:in-reply-to ref="tag:freezepeach.xyz,2018-02-23:noticeId=6451332:objectType=note" href="https://freezepeach.xyz/notice/6451332"></thr:in-reply-to> - <link rel="related" href="https://freezepeach.xyz/notice/6451332"/> - <link rel="ostatus:conversation" href="https://shitposter.club/conversation/4390261"/> - <ostatus:conversation href="https://shitposter.club/conversation/4390261" local_id="4390261" ref="https://freezepeach.xyz/conversation/4183220">https://freezepeach.xyz/conversation/4183220</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387553.atom"/> - <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387553.atom"/> - <statusnet:notice_info local_id="7387553" source="unknown"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>tag:shitposter.club,2018-02-23:noticeId=7387539:objectType=comment</id> - <title>New comment by shpuld</title> - <content type="html">@<a href="https://mstdn.io/users/mayuutann" class="h-card mention" title="Mayutan&#x2615;">mayuutann</a> ndndnd~</content> - <link rel="alternate" type="text/html" href="https://shitposter.club/notice/7387539"/> - <status_net notice_id="7387539"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2018-02-23T13:11:04+00:00</published> - <updated>2018-02-23T13:11:04+00:00</updated> - <thr:in-reply-to ref="https://mstdn.io/users/mayuutann/statuses/99574837619821505" href="https://mstdn.io/@mayuutann/99574837619821505"></thr:in-reply-to> - <link rel="related" href="https://mstdn.io/@mayuutann/99574837619821505"/> - <link rel="ostatus:conversation" href="https://shitposter.club/conversation/4390030"/> - <ostatus:conversation href="https://shitposter.club/conversation/4390030" local_id="4390030" ref="tag:shitposter.club,2018-02-23:objectType=thread:nonce=d05e2b056274c5ab">tag:shitposter.club,2018-02-23:objectType=thread:nonce=d05e2b056274c5ab</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mstdn.io/users/mayuutann"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387539.atom"/> - <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387539.atom"/> - <statusnet:notice_info local_id="7387539" source="Pleroma FE"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>tag:shitposter.club,2018-02-23:noticeId=7387518:objectType=comment</id> - <title>New comment by shpuld</title> - <content type="html">@<a href="https://mstdn.io/users/mayuutann" class="h-card mention" title="Mayutan&#x2615;">mayuutann</a> well done! mayumayu is so energetic</content> - <link rel="alternate" type="text/html" href="https://shitposter.club/notice/7387518"/> - <status_net notice_id="7387518"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2018-02-23T13:08:50+00:00</published> - <updated>2018-02-23T13:08:50+00:00</updated> - <thr:in-reply-to ref="https://mstdn.io/users/mayuutann/statuses/99574826506801503" href="https://mstdn.io/@mayuutann/99574826506801503"></thr:in-reply-to> - <link rel="related" href="https://mstdn.io/@mayuutann/99574826506801503"/> - <link rel="ostatus:conversation" href="https://shitposter.club/conversation/4390030"/> - <ostatus:conversation href="https://shitposter.club/conversation/4390030" local_id="4390030" ref="tag:shitposter.club,2018-02-23:objectType=thread:nonce=d05e2b056274c5ab">tag:shitposter.club,2018-02-23:objectType=thread:nonce=d05e2b056274c5ab</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mstdn.io/users/mayuutann"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387518.atom"/> - <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387518.atom"/> - <statusnet:notice_info local_id="7387518" source="Pleroma FE"></statusnet:notice_info> -</entry> -<entry> - <id>tag:shitposter.club,2018-02-23:fave:5381:note:7387503:2018-02-23T13:08:00+00:00</id> - <title>Favorite</title> - <content type="html">shpuld favorited something by mayuutann: <p>done with FIGURE MAT!!<br /> (Posted with IFTTT)</p></content> - <link rel="alternate" type="text/html" href="https://shitposter.club/notice/7387511"/> - <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb> - <published>2018-02-23T13:08:00+00:00</published> - <updated>2018-02-23T13:08:00+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>https://mstdn.io/users/mayuutann/statuses/99574825526201897</id> - <title>New note by mayuutann</title> - <content type="html"><p>done with FIGURE MAT!!<br /> (Posted with IFTTT)</p></content> - <link rel="alternate" type="text/html" href="https://mstdn.io/@mayuutann/99574825526201897"/> - <status_net notice_id="7387503"></status_net> - </activity:object> - <thr:in-reply-to ref="https://mstdn.io/users/mayuutann/statuses/99574825526201897" href="https://mstdn.io/@mayuutann/99574825526201897"></thr:in-reply-to> - <link rel="related" href="https://mstdn.io/@mayuutann/99574825526201897"/> - <link rel="ostatus:conversation" href="https://shitposter.club/conversation/4390240"/> - <ostatus:conversation href="https://shitposter.club/conversation/4390240" local_id="4390240" ref="tag:shitposter.club,2018-02-23:objectType=thread:nonce=c6aaa9b91e8d242f">tag:shitposter.club,2018-02-23:objectType=thread:nonce=c6aaa9b91e8d242f</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387511.atom"/> - <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387511.atom"/> - <statusnet:notice_info local_id="7387511" source="unknown"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>tag:shitposter.club,2018-02-23:noticeId=7387486:objectType=comment</id> - <title>New comment by shpuld</title> - <content type="html">@<a href="https://freezepeach.xyz/user/3458" class="h-card mention" title="&#x5FA1;&#x5712;&#x306F;&#x304F;&#x3044;">hakui</a> @<a href="https://a.weirder.earth/users/mutstd" class="h-card mention" title="Mutant Standard">mutstd</a> @<a href="https://donphan.social/users/Siphonay" class="h-card mention" title="Siphonay">siphonay</a> jokes on you I'm oppressively shitposting myself</content> - <link rel="alternate" type="text/html" href="https://shitposter.club/notice/7387486"/> - <status_net notice_id="7387486"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2018-02-23T13:05:44+00:00</published> - <updated>2018-02-23T13:05:44+00:00</updated> - <thr:in-reply-to ref="tag:freezepeach.xyz,2018-02-23:noticeId=6451272:objectType=comment" href="https://freezepeach.xyz/notice/6451272"></thr:in-reply-to> - <link rel="related" href="https://freezepeach.xyz/notice/6451272"/> - <link rel="ostatus:conversation" href="https://shitposter.club/conversation/4389665"/> - <ostatus:conversation href="https://shitposter.club/conversation/4389665" local_id="4389665" ref="tag:shitposter.club,2018-02-23:objectType=thread:nonce=5d306467336c9661">tag:shitposter.club,2018-02-23:objectType=thread:nonce=5d306467336c9661</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://freezepeach.xyz/user/3458"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://a.weirder.earth/users/mutstd"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://donphan.social/users/Siphonay"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387486.atom"/> - <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387486.atom"/> - <statusnet:notice_info local_id="7387486" source="Pleroma FE"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>tag:shitposter.club,2018-02-23:noticeId=7387466:objectType=comment</id> - <title>New comment by shpuld</title> - <content type="html">@<a href="https://freezepeach.xyz/user/3458" class="h-card mention" title="&#x5FA1;&#x5712;&#x306F;&#x304F;&#x3044;">hakui</a> @<a href="https://a.weirder.earth/users/mutstd" class="h-card mention" title="Mutant Standard">mutstd</a> @<a href="https://donphan.social/users/Siphonay" class="h-card mention" title="Siphonay">siphonay</a> how does it feel being hostile</content> - <link rel="alternate" type="text/html" href="https://shitposter.club/notice/7387466"/> - <status_net notice_id="7387466"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2018-02-23T13:04:10+00:00</published> - <updated>2018-02-23T13:04:10+00:00</updated> - <thr:in-reply-to ref="tag:freezepeach.xyz,2018-02-23:noticeId=6451260:objectType=comment" href="https://freezepeach.xyz/notice/6451260"></thr:in-reply-to> - <link rel="related" href="https://freezepeach.xyz/notice/6451260"/> - <link rel="ostatus:conversation" href="https://shitposter.club/conversation/4389665"/> - <ostatus:conversation href="https://shitposter.club/conversation/4389665" local_id="4389665" ref="tag:shitposter.club,2018-02-23:objectType=thread:nonce=5d306467336c9661">tag:shitposter.club,2018-02-23:objectType=thread:nonce=5d306467336c9661</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://freezepeach.xyz/user/3458"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://a.weirder.earth/users/mutstd"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://donphan.social/users/Siphonay"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387466.atom"/> - <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387466.atom"/> - <statusnet:notice_info local_id="7387466" source="Pleroma FE"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>tag:shitposter.club,2018-02-23:noticeId=7387459:objectType=comment</id> - <title>New comment by shpuld</title> - <content type="html">@<a href="https://freezepeach.xyz/user/3458" class="h-card mention" title="&#x5FA1;&#x5712;&#x306F;&#x304F;&#x3044;">hakui</a> gorogoro</content> - <link rel="alternate" type="text/html" href="https://shitposter.club/notice/7387459"/> - <status_net notice_id="7387459"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2018-02-23T13:03:32+00:00</published> - <updated>2018-02-23T13:03:32+00:00</updated> - <thr:in-reply-to ref="tag:freezepeach.xyz,2018-02-23:noticeId=6451248:objectType=comment" href="https://freezepeach.xyz/notice/6451248"></thr:in-reply-to> - <link rel="related" href="https://freezepeach.xyz/notice/6451248"/> - <link rel="ostatus:conversation" href="https://shitposter.club/conversation/4389271"/> - <ostatus:conversation href="https://shitposter.club/conversation/4389271" local_id="4389271" ref="https://freezepeach.xyz/conversation/4181784">https://freezepeach.xyz/conversation/4181784</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://freezepeach.xyz/user/3458"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387459.atom"/> - <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387459.atom"/> - <statusnet:notice_info local_id="7387459" source="Pleroma FE"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>tag:shitposter.club,2018-02-23:noticeId=7387432:objectType=comment</id> - <title>New comment by shpuld</title> - <content type="html">@<a href="https://freezepeach.xyz/user/3458" class="h-card mention" title="&#x5FA1;&#x5712;&#x306F;&#x304F;&#x3044;">hakui</a> ndnd</content> - <link rel="alternate" type="text/html" href="https://shitposter.club/notice/7387432"/> - <status_net notice_id="7387432"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2018-02-23T13:02:05+00:00</published> - <updated>2018-02-23T13:02:05+00:00</updated> - <thr:in-reply-to ref="tag:freezepeach.xyz,2018-02-23:noticeId=6451204:objectType=comment" href="https://freezepeach.xyz/notice/6451204"></thr:in-reply-to> - <link rel="related" href="https://freezepeach.xyz/notice/6451204"/> - <link rel="ostatus:conversation" href="https://shitposter.club/conversation/4389271"/> - <ostatus:conversation href="https://shitposter.club/conversation/4389271" local_id="4389271" ref="https://freezepeach.xyz/conversation/4181784">https://freezepeach.xyz/conversation/4181784</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://freezepeach.xyz/user/3458"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387432.atom"/> - <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387432.atom"/> - <statusnet:notice_info local_id="7387432" source="Pleroma FE"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:shitposter.club,2018-02-23:noticeId=7387367:objectType=note</id> - <title>New note by shpuld</title> - <content type="html">dear diary: I'm trying to do work but I can only think of tenshi eating a corndog</content> - <link rel="alternate" type="text/html" href="https://shitposter.club/notice/7387367"/> - <status_net notice_id="7387367"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2018-02-23T12:56:03+00:00</published> - <updated>2018-02-23T12:56:03+00:00</updated> - <link rel="ostatus:conversation" href="https://shitposter.club/conversation/4390142"/> - <ostatus:conversation href="https://shitposter.club/conversation/4390142" local_id="4390142" ref="tag:shitposter.club,2018-02-23:objectType=thread:nonce=57f316da416743fc">tag:shitposter.club,2018-02-23:objectType=thread:nonce=57f316da416743fc</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387367.atom"/> - <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387367.atom"/> - <statusnet:notice_info local_id="7387367" source="Pleroma FE"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type> - <id>tag:shitposter.club,2018-02-23:noticeId=7387354:objectType=note</id> - <title>New note by shpuld</title> - <content type="html">jesus christ it's such a fridey at work</content> - <link rel="alternate" type="text/html" href="https://shitposter.club/notice/7387354"/> - <status_net notice_id="7387354"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2018-02-23T12:53:50+00:00</published> - <updated>2018-02-23T12:53:50+00:00</updated> - <link rel="ostatus:conversation" href="https://shitposter.club/conversation/4390131"/> - <ostatus:conversation href="https://shitposter.club/conversation/4390131" local_id="4390131" ref="tag:shitposter.club,2018-02-23:objectType=thread:nonce=c05eb5e91bdcbdb7">tag:shitposter.club,2018-02-23:objectType=thread:nonce=c05eb5e91bdcbdb7</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387354.atom"/> - <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387354.atom"/> - <statusnet:notice_info local_id="7387354" source="Pleroma FE"></statusnet:notice_info> -</entry> -<entry> - <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type> - <id>tag:shitposter.club,2018-02-23:noticeId=7387343:objectType=comment</id> - <title>New comment by shpuld</title> - <content type="html">@<a href="https://gs.smuglo.li/user/589" class="h-card mention" title="&#x16DE;&#x16A9;&#x16B3;&#x16C1;&#x16DE;&#x16A9;&#x16B3;&#x16C1;">dokidoki</a> give them free upgrades to krokodil</content> - <link rel="alternate" type="text/html" href="https://shitposter.club/notice/7387343"/> - <status_net notice_id="7387343"></status_net> - <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb> - <published>2018-02-23T12:53:15+00:00</published> - <updated>2018-02-23T12:53:15+00:00</updated> - <thr:in-reply-to ref="tag:gs.smuglo.li,2018-02-23:noticeId=6201061:objectType=note" href="https://gs.smuglo.li/notice/6201061"></thr:in-reply-to> - <link rel="related" href="https://gs.smuglo.li/notice/6201061"/> - <link rel="ostatus:conversation" href="https://shitposter.club/conversation/4390117"/> - <ostatus:conversation href="https://shitposter.club/conversation/4390117" local_id="4390117" ref="https://gs.smuglo.li/conversation/3934774">https://gs.smuglo.li/conversation/3934774</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://gs.smuglo.li/user/589"/> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387343.atom"/> - <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387343.atom"/> - <statusnet:notice_info local_id="7387343" source="Pleroma FE"></statusnet:notice_info> -</entry> -</feed> diff --git a/test/fixtures/tesla_mock/wedistribute-create-article.json b/test/fixtures/tesla_mock/wedistribute-create-article.json new file mode 100644 index 000000000..3cfef8b99 --- /dev/null +++ b/test/fixtures/tesla_mock/wedistribute-create-article.json @@ -0,0 +1 @@ +{"@context":["https:\/\/www.w3.org\/ns\/activitystreams"],"type":"Create","actor":"https:\/\/wedistribute.org\/wp-json\/pterotype\/v1\/actor\/-blog","object":{"@context":["https:\/\/www.w3.org\/ns\/activitystreams"],"type":"Article","name":"The end is near: Mastodon plans to drop OStatus support","content":"<!-- wp:paragraph {\"dropCap\":true} -->\n<p class=\"has-drop-cap\">The days of OStatus are numbered. The venerable protocol has served as a glue between many different types of servers since the early days of the Fediverse, connecting StatusNet (now GNU Social) to Friendica, Hubzilla, Mastodon, and Pleroma.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>Now that many fediverse platforms support ActivityPub as a successor protocol, Mastodon appears to be drawing a line in the sand. In <a href=\"https:\/\/www.patreon.com\/posts\/mastodon-2-9-and-28121681\">a Patreon update<\/a>, Eugen Rochko writes:<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:quote -->\n<blockquote class=\"wp-block-quote\"><p>...OStatus...has overstayed its welcome in the code...and now that most of the network uses ActivityPub, it's time for it to go. <\/p><cite>Eugen Rochko, Mastodon creator<\/cite><\/blockquote>\n<!-- \/wp:quote -->\n\n<!-- wp:paragraph -->\n<p>The <a href=\"https:\/\/github.com\/tootsuite\/mastodon\/pull\/11205\">pull request<\/a> to remove Pubsubhubbub and Salmon, two of the main components of OStatus, has already been merged into Mastodon's master branch.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>Some projects will be left in the dark as a side effect of this. GNU Social and PostActiv, for example, both only communicate using OStatus. While <a href=\"https:\/\/mastodon.social\/@dansup\/102076573310057902\">some discussion<\/a> exists regarding adopting ActivityPub for GNU Social, and <a href=\"https:\/\/notabug.org\/diogo\/gnu-social\/src\/activitypub\/plugins\/ActivityPub\">a plugin is in development<\/a>, it hasn't been formally adopted yet. We just hope that the <a href=\"https:\/\/status.fsf.org\/main\/public\">Free Software Foundation's instance<\/a> gets updated in time!<\/p>\n<!-- \/wp:paragraph -->","summary":"One of the largest platforms in the federated social web is dropping the protocol that it started with.","attributedTo":"https:\/\/wedistribute.org\/wp-json\/pterotype\/v1\/actor\/-blog","url":"https:\/\/wedistribute.org\/2019\/07\/mastodon-drops-ostatus\/","to":["https:\/\/www.w3.org\/ns\/activitystreams#Public","https:\/\/wedistribute.org\/wp-json\/pterotype\/v1\/actor\/-blog\/followers"],"id":"https:\/\/wedistribute.org\/wp-json\/pterotype\/v1\/object\/85810","likes":"https:\/\/wedistribute.org\/wp-json\/pterotype\/v1\/object\/85810\/likes","shares":"https:\/\/wedistribute.org\/wp-json\/pterotype\/v1\/object\/85810\/shares"},"to":["https:\/\/www.w3.org\/ns\/activitystreams#Public","https:\/\/wedistribute.org\/wp-json\/pterotype\/v1\/actor\/-blog\/followers"],"id":"https:\/\/wedistribute.org\/wp-json\/pterotype\/v1\/object\/85809"}
\ No newline at end of file diff --git a/test/fixtures/tesla_mock/xn--q9jyb4c_host_meta b/test/fixtures/tesla_mock/xn--q9jyb4c_host_meta deleted file mode 100644 index 45d260e55..000000000 --- a/test/fixtures/tesla_mock/xn--q9jyb4c_host_meta +++ /dev/null @@ -1,4 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0"> - <Link rel="lrdd" template="https://zetsubou.xn--q9jyb4c/.well-known/webfinger?resource={uri}" type="application/xrd+xml" /> -</XRD> diff --git a/test/fixtures/unfollow.xml b/test/fixtures/unfollow.xml deleted file mode 100644 index 7a8f8fd2e..000000000 --- a/test/fixtures/unfollow.xml +++ /dev/null @@ -1,68 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:georss="http://www.georss.org/georss" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:media="http://purl.org/syndication/atommedia" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:statusnet="http://status.net/schema/api/1/"> - <generator uri="https://gnu.io/social" version="1.0.2-dev">GNU social</generator> - <id>https://social.heldscal.la/api/statuses/user_timeline/23211.atom</id> - <title>lambadalambda timeline</title> - <subtitle>Updates from lambadalambda on social.heldscal.la!</subtitle> - <logo>https://social.heldscal.la/avatar/23211-96-20170416114255.jpeg</logo> - <updated>2017-05-07T09:54:49+00:00</updated> -<author> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <uri>https://social.heldscal.la/user/23211</uri> - <name>lambadalambda</name> - <summary>Call me Deacon Blues.</summary> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/lambadalambda"/> - <link rel="avatar" type="image/jpeg" media:width="236" media:height="236" href="https://social.heldscal.la/avatar/23211-original-20170416114255.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/23211-96-20170416114255.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="48" media:height="48" href="https://social.heldscal.la/avatar/23211-48-20170416114255.jpeg"/> - <link rel="avatar" type="image/jpeg" media:width="24" media:height="24" href="https://social.heldscal.la/avatar/23211-24-20170416114257.jpeg"/> - <poco:preferredUsername>lambadalambda</poco:preferredUsername> - <poco:displayName>Constance Variable</poco:displayName> - <poco:note>Call me Deacon Blues.</poco:note> - <poco:address> - <poco:formatted>Berlin</poco:formatted> - </poco:address> - <poco:urls> - <poco:type>homepage</poco:type> - <poco:value>https://heldscal.la</poco:value> - <poco:primary>true</poco:primary> - </poco:urls> - <followers url="https://social.heldscal.la/lambadalambda/subscribers"></followers> - <statusnet:profile_info local_id="23211"></statusnet:profile_info> -</author> - <link href="https://social.heldscal.la/lambadalambda" rel="alternate" type="text/html"/> - <link href="https://social.heldscal.la/main/sup" rel="http://api.friendfeed.com/2008/03#sup" type="application/json"/> - <link href="https://social.heldscal.la/main/push/hub" rel="hub"/> - <link href="https://social.heldscal.la/main/salmon/user/23211" rel="salmon"/> - <link href="https://social.heldscal.la/main/salmon/user/23211" rel="http://salmon-protocol.org/ns/salmon-replies"/> - <link href="https://social.heldscal.la/main/salmon/user/23211" rel="http://salmon-protocol.org/ns/salmon-mention"/> - <link href="https://social.heldscal.la/api/statuses/user_timeline/23211.atom" rel="self" type="application/atom+xml"/> -<entry> - <id>undo:tag:social.heldscal.la,2017-05-07:subscription:23211:person:44803:2017-05-07T09:54:48+00:00</id> - <title>Constance Variable (lambadalambda@social.heldscal.la)'s status on Sunday, 07-May-2017 09:54:49 UTC</title> - <content type="html"><a href="https://social.heldscal.la/lambadalambda">Constance Variable</a> stopped following <a href="https://pawoo.net/@pekorino">mono</a>.</content> - <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2092981"/> - <activity:verb>http://activitystrea.ms/schema/1.0/unfollow</activity:verb> - <published>2017-05-07T09:54:49+00:00</published> - <updated>2017-05-07T09:54:49+00:00</updated> - <activity:object> - <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type> - <id>https://pawoo.net/users/pekorino</id> - <title>mono</title> - <summary>http://shitposter.club/mono 孤独のグルメ</summary> - <link rel="alternate" type="text/html" href="https://pawoo.net/@pekorino"/> - <link rel="avatar" type="image/png" media:width="96" media:height="96" href="http://social.heldscal.la/theme/neo-gnu/default-avatar-profile.png"/> - <link rel="avatar" type="image/png" media:width="48" media:height="48" href="http://social.heldscal.la/theme/neo-gnu/default-avatar-stream.png"/> - <link rel="avatar" type="image/png" media:width="24" media:height="24" href="http://social.heldscal.la/theme/neo-gnu/default-avatar-mini.png"/> - <poco:preferredUsername>pekorino</poco:preferredUsername> - <poco:displayName>mono</poco:displayName> - <poco:note>http://shitposter.club/mono 孤独のグルメ</poco:note> - </activity:object> - <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1079786"/> - <ostatus:conversation href="https://social.heldscal.la/conversation/1079786" local_id="1079786" ref="tag:social.heldscal.la,2017-05-07:objectType=thread:nonce=6e80caf94e03029f">tag:social.heldscal.la,2017-05-07:objectType=thread:nonce=6e80caf94e03029f</ostatus:conversation> - <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/> - <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2092981.atom"/> - <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2092981.atom"/> - <statusnet:notice_info local_id="2092981" source="activity"></statusnet:notice_info> -</entry> -</feed> diff --git a/test/fixtures/users_mock/localhost.json b/test/fixtures/users_mock/localhost.json deleted file mode 100644 index a49935db1..000000000 --- a/test/fixtures/users_mock/localhost.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "@context": [ - "https://www.w3.org/ns/activitystreams", - "http://localhost:4001/schemas/litepub-0.1.jsonld", - { - "@language": "und" - } - ], - "attachment": [], - "endpoints": { - "oauthAuthorizationEndpoint": "http://localhost:4001/oauth/authorize", - "oauthRegistrationEndpoint": "http://localhost:4001/api/v1/apps", - "oauthTokenEndpoint": "http://localhost:4001/oauth/token", - "sharedInbox": "http://localhost:4001/inbox" - }, - "followers": "http://localhost:4001/users/{{nickname}}/followers", - "following": "http://localhost:4001/users/{{nickname}}/following", - "icon": { - "type": "Image", - "url": "http://localhost:4001/media/4e914f5b84e4a259a3f6c2d2edc9ab642f2ab05f3e3d9c52c81fc2d984b3d51e.jpg" - }, - "id": "http://localhost:4001/users/{{nickname}}", - "image": { - "type": "Image", - "url": "http://localhost:4001/media/f739efddefeee49c6e67e947c4811fdc911785c16ae43da4c3684051fbf8da6a.jpg?name=f739efddefeee49c6e67e947c4811fdc911785c16ae43da4c3684051fbf8da6a.jpg" - }, - "inbox": "http://localhost:4001/users/{{nickname}}/inbox", - "manuallyApprovesFollowers": false, - "name": "{{nickname}}", - "outbox": "http://localhost:4001/users/{{nickname}}/outbox", - "preferredUsername": "{{nickname}}", - "publicKey": { - "id": "http://localhost:4001/users/{{nickname}}#main-key", - "owner": "http://localhost:4001/users/{{nickname}}", - "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5DLtwGXNZElJyxFGfcVc\nXANhaMadj/iYYQwZjOJTV9QsbtiNBeIK54PJrYuU0/0YIdrvS1iqheX5IwXRhcwa\nhm3ZyLz7XeN9st7FBni4BmZMBtMpxAuYuu5p/jbWy13qAiYOhPreCx0wrWgm/lBD\n9mkgaxIxPooBE0S4ZWEJIDIV1Vft3AWcRUyWW1vIBK0uZzs6GYshbQZB952S0yo4\nFzI1hABGHncH8UvuFauh4EZ8tY7/X5I0pGRnDOcRN1dAht5w5yTA+6r5kebiFQjP\nIzN/eCO/a9Flrj9YGW7HDNtjSOH0A31PLRGlJtJO3yK57dnf5ppyCZGfL4emShQo\ncQIDAQAB\n-----END PUBLIC KEY-----\n\n" - }, - "summary": "your friendly neighborhood pleroma developer<br>I like cute things and distributed systems, and really hate delete and redrafts", - "tag": [], - "type": "Person", - "url": "http://localhost:4001/users/{{nickname}}" -}
\ No newline at end of file diff --git a/test/fixtures/users_mock/masto_featured.json b/test/fixtures/users_mock/masto_featured.json new file mode 100644 index 000000000..646a343ad --- /dev/null +++ b/test/fixtures/users_mock/masto_featured.json @@ -0,0 +1,18 @@ +{ + "@context": [ + "https://www.w3.org/ns/activitystreams", + { + "ostatus": "http://ostatus.org#", + "atomUri": "ostatus:atomUri", + "inReplyToAtomUri": "ostatus:inReplyToAtomUri", + "conversation": "ostatus:conversation", + "sensitive": "as:sensitive", + "toot": "http://joinmastodon.org/ns#", + "votersCount": "toot:votersCount" + } + ], + "id": "https://{{domain}}/users/{{nickname}}/collections/featured", + "type": "OrderedCollection", + "totalItems": 0, + "orderedItems": [] +} diff --git a/test/fixtures/users_mock/user.json b/test/fixtures/users_mock/user.json new file mode 100644 index 000000000..c722a1145 --- /dev/null +++ b/test/fixtures/users_mock/user.json @@ -0,0 +1,42 @@ +{ + "@context": [ + "https://www.w3.org/ns/activitystreams", + "https://example.com/schemas/litepub-0.1.jsonld", + { + "@language": "und" + } + ], + "attachment": [], + "endpoints": { + "oauthAuthorizationEndpoint": "https://example.com/oauth/authorize", + "oauthRegistrationEndpoint": "https://example.com/api/v1/apps", + "oauthTokenEndpoint": "https://example.com/oauth/token", + "sharedInbox": "https://example.com/inbox" + }, + "followers": "https://example.com/users/{{nickname}}/followers", + "following": "https://example.com/users/{{nickname}}/following", + "icon": { + "type": "Image", + "url": "https://example.com/media/4e914f5b84e4a259a3f6c2d2edc9ab642f2ab05f3e3d9c52c81fc2d984b3d51e.jpg" + }, + "id": "https://example.com/users/{{nickname}}", + "image": { + "type": "Image", + "url": "https://example.com/media/f739efddefeee49c6e67e947c4811fdc911785c16ae43da4c3684051fbf8da6a.jpg?name=f739efddefeee49c6e67e947c4811fdc911785c16ae43da4c3684051fbf8da6a.jpg" + }, + "inbox": "https://example.com/users/{{nickname}}/inbox", + "manuallyApprovesFollowers": false, + "name": "{{nickname}}", + "outbox": "https://example.com/users/{{nickname}}/outbox", + "preferredUsername": "{{nickname}}", + "publicKey": { + "id": "https://example.com/users/{{nickname}}#main-key", + "owner": "https://example.com/users/{{nickname}}", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5DLtwGXNZElJyxFGfcVc\nXANhaMadj/iYYQwZjOJTV9QsbtiNBeIK54PJrYuU0/0YIdrvS1iqheX5IwXRhcwa\nhm3ZyLz7XeN9st7FBni4BmZMBtMpxAuYuu5p/jbWy13qAiYOhPreCx0wrWgm/lBD\n9mkgaxIxPooBE0S4ZWEJIDIV1Vft3AWcRUyWW1vIBK0uZzs6GYshbQZB952S0yo4\nFzI1hABGHncH8UvuFauh4EZ8tY7/X5I0pGRnDOcRN1dAht5w5yTA+6r5kebiFQjP\nIzN/eCO/a9Flrj9YGW7HDNtjSOH0A31PLRGlJtJO3yK57dnf5ppyCZGfL4emShQo\ncQIDAQAB\n-----END PUBLIC KEY-----\n\n" + }, + "featured": "https://example.com/users/{{nickname}}/collections/featured", + "summary": "your friendly neighborhood pleroma developer<br>I like cute things and distributed systems, and really hate delete and redrafts", + "tag": [], + "type": "Person", + "url": "https://example.com/users/{{nickname}}" +} diff --git a/test/fixtures/video.mp4 b/test/fixtures/video.mp4 Binary files differnew file mode 100644 index 000000000..2021e3a5b --- /dev/null +++ b/test/fixtures/video.mp4 diff --git a/test/instance_static/emoji/blobs.gg/blank.png b/test/instance_static/emoji/blobs.gg/blank.png Binary files differnew file mode 100644 index 000000000..8f50fa023 --- /dev/null +++ b/test/instance_static/emoji/blobs.gg/blank.png diff --git a/test/instance_static/emoji/blobs.gg/pack.json b/test/instance_static/emoji/blobs.gg/pack.json new file mode 100644 index 000000000..481891b08 --- /dev/null +++ b/test/instance_static/emoji/blobs.gg/pack.json @@ -0,0 +1,11 @@ +{ + "files": { + "blank": "blank.png" + }, + "pack": { + "description": "Test description", + "homepage": "https://pleroma.social", + "license": "Test license", + "share-files": true + } +}
\ No newline at end of file diff --git a/test/tasks/pleroma_test.exs b/test/mix/pleroma_test.exs index c3e47b285..af62cc1d9 100644 --- a/test/tasks/pleroma_test.exs +++ b/test/mix/pleroma_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Mix.PleromaTest do diff --git a/test/tasks/app_test.exs b/test/mix/tasks/pleroma/app_test.exs index 71a84ac8e..9eabd32af 100644 --- a/test/tasks/app_test.exs +++ b/test/mix/tasks/pleroma/app_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Mix.Tasks.Pleroma.AppTest do diff --git a/test/mix/tasks/pleroma/config_test.exs b/test/mix/tasks/pleroma/config_test.exs new file mode 100644 index 000000000..2b8252db7 --- /dev/null +++ b/test/mix/tasks/pleroma/config_test.exs @@ -0,0 +1,343 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Mix.Tasks.Pleroma.ConfigTest do + use Pleroma.DataCase + + import Pleroma.Factory + + alias Mix.Tasks.Pleroma.Config, as: MixTask + alias Pleroma.ConfigDB + alias Pleroma.Repo + + setup_all do + Mix.shell(Mix.Shell.Process) + + on_exit(fn -> + Mix.shell(Mix.Shell.IO) + Application.delete_env(:pleroma, :first_setting) + Application.delete_env(:pleroma, :second_setting) + end) + + :ok + end + + defp config_records do + ConfigDB + |> Repo.all() + |> Enum.sort() + end + + defp insert_config_record(group, key, value) do + insert(:config, + group: group, + key: key, + value: value + ) + end + + test "error if file with custom settings doesn't exist" do + MixTask.migrate_to_db("config/non_existent_config_file.exs") + + msg = + "To migrate settings, you must define custom settings in config/non_existent_config_file.exs." + + assert_receive {:mix_shell, :info, [^msg]}, 15 + end + + describe "migrate_to_db/1" do + setup do + clear_config(:configurable_from_database, true) + clear_config([:quack, :level]) + end + + @tag capture_log: true + test "config migration refused when deprecated settings are found" do + clear_config([:media_proxy, :whitelist], ["domain_without_scheme.com"]) + assert config_records() == [] + + MixTask.migrate_to_db("test/fixtures/config/temp.secret.exs") + + assert_received {:mix_shell, :error, [message]} + + assert message =~ + "Migration is not allowed until all deprecation warnings have been resolved." + end + + test "filtered settings are migrated to db" do + assert config_records() == [] + + MixTask.migrate_to_db("test/fixtures/config/temp.secret.exs") + + config1 = ConfigDB.get_by_params(%{group: ":pleroma", key: ":first_setting"}) + config2 = ConfigDB.get_by_params(%{group: ":pleroma", key: ":second_setting"}) + config3 = ConfigDB.get_by_params(%{group: ":quack", key: ":level"}) + refute ConfigDB.get_by_params(%{group: ":pleroma", key: "Pleroma.Repo"}) + refute ConfigDB.get_by_params(%{group: ":postgrex", key: ":json_library"}) + refute ConfigDB.get_by_params(%{group: ":pleroma", key: ":database"}) + + assert config1.value == [key: "value", key2: [Repo]] + assert config2.value == [key: "value2", key2: ["Activity"]] + assert config3.value == :info + end + + test "config table is truncated before migration" do + insert_config_record(:pleroma, :first_setting, key: "value", key2: ["Activity"]) + assert length(config_records()) == 1 + + MixTask.migrate_to_db("test/fixtures/config/temp.secret.exs") + + config = ConfigDB.get_by_params(%{group: ":pleroma", key: ":first_setting"}) + assert config.value == [key: "value", key2: [Repo]] + end + end + + describe "with deletion of temp file" do + setup do + clear_config(:configurable_from_database, true) + temp_file = "config/temp.exported_from_db.secret.exs" + + on_exit(fn -> + :ok = File.rm(temp_file) + end) + + {:ok, temp_file: temp_file} + end + + test "settings are migrated to file and deleted from db", %{temp_file: temp_file} do + insert_config_record(:pleroma, :setting_first, key: "value", key2: ["Activity"]) + insert_config_record(:pleroma, :setting_second, key: "value2", key2: [Repo]) + insert_config_record(:quack, :level, :info) + + MixTask.run(["migrate_from_db", "--env", "temp", "-d"]) + + assert config_records() == [] + + file = File.read!(temp_file) + assert file =~ "config :pleroma, :setting_first," + assert file =~ "config :pleroma, :setting_second," + assert file =~ "config :quack, :level, :info" + end + + test "load a settings with large values and pass to file", %{temp_file: temp_file} do + insert(:config, + key: :instance, + value: [ + name: "Pleroma", + email: "example@example.com", + notify_email: "noreply@example.com", + description: "A Pleroma instance, an alternative fediverse server", + limit: 5_000, + chat_limit: 5_000, + remote_limit: 100_000, + upload_limit: 16_000_000, + avatar_upload_limit: 2_000_000, + background_upload_limit: 4_000_000, + banner_upload_limit: 4_000_000, + poll_limits: %{ + max_options: 20, + max_option_chars: 200, + min_expiration: 0, + max_expiration: 365 * 24 * 60 * 60 + }, + registrations_open: true, + federating: true, + federation_incoming_replies_max_depth: 100, + federation_reachability_timeout_days: 7, + federation_publisher_modules: [Pleroma.Web.ActivityPub.Publisher], + allow_relay: true, + public: true, + quarantined_instances: [], + managed_config: true, + static_dir: "instance/static/", + allowed_post_formats: ["text/plain", "text/html", "text/markdown", "text/bbcode"], + autofollowed_nicknames: [], + max_pinned_statuses: 1, + attachment_links: false, + max_report_comment_size: 1000, + safe_dm_mentions: false, + healthcheck: false, + remote_post_retention_days: 90, + skip_thread_containment: true, + limit_to_local_content: :unauthenticated, + user_bio_length: 5000, + user_name_length: 100, + max_account_fields: 10, + max_remote_account_fields: 20, + account_field_name_length: 512, + account_field_value_length: 2048, + external_user_synchronization: true, + extended_nickname_format: true, + multi_factor_authentication: [ + totp: [ + digits: 6, + period: 30 + ], + backup_codes: [ + number: 2, + length: 6 + ] + ] + ] + ) + + MixTask.run(["migrate_from_db", "--env", "temp", "-d"]) + + assert config_records() == [] + assert File.exists?(temp_file) + {:ok, file} = File.read(temp_file) + + assert file == + "import Config\n\nconfig :pleroma, :instance,\n name: \"Pleroma\",\n email: \"example@example.com\",\n notify_email: \"noreply@example.com\",\n description: \"A Pleroma instance, an alternative fediverse server\",\n limit: 5000,\n chat_limit: 5000,\n remote_limit: 100_000,\n upload_limit: 16_000_000,\n avatar_upload_limit: 2_000_000,\n background_upload_limit: 4_000_000,\n banner_upload_limit: 4_000_000,\n poll_limits: %{\n max_expiration: 31_536_000,\n max_option_chars: 200,\n max_options: 20,\n min_expiration: 0\n },\n registrations_open: true,\n federating: true,\n federation_incoming_replies_max_depth: 100,\n federation_reachability_timeout_days: 7,\n federation_publisher_modules: [Pleroma.Web.ActivityPub.Publisher],\n allow_relay: true,\n public: true,\n quarantined_instances: [],\n managed_config: true,\n static_dir: \"instance/static/\",\n allowed_post_formats: [\"text/plain\", \"text/html\", \"text/markdown\", \"text/bbcode\"],\n autofollowed_nicknames: [],\n max_pinned_statuses: 1,\n attachment_links: false,\n max_report_comment_size: 1000,\n safe_dm_mentions: false,\n healthcheck: false,\n remote_post_retention_days: 90,\n skip_thread_containment: true,\n limit_to_local_content: :unauthenticated,\n user_bio_length: 5000,\n user_name_length: 100,\n max_account_fields: 10,\n max_remote_account_fields: 20,\n account_field_name_length: 512,\n account_field_value_length: 2048,\n external_user_synchronization: true,\n extended_nickname_format: true,\n multi_factor_authentication: [\n totp: [digits: 6, period: 30],\n backup_codes: [number: 2, length: 6]\n ]\n" + end + end + + describe "migrate_from_db/1" do + setup do: clear_config(:configurable_from_database, true) + + setup do + insert_config_record(:pleroma, :setting_first, key: "value", key2: ["Activity"]) + insert_config_record(:pleroma, :setting_second, key: "value2", key2: [Repo]) + insert_config_record(:quack, :level, :info) + + path = "test/instance_static" + file_path = Path.join(path, "temp.exported_from_db.secret.exs") + + on_exit(fn -> File.rm!(file_path) end) + + [file_path: file_path] + end + + test "with path parameter", %{file_path: file_path} do + MixTask.run(["migrate_from_db", "--env", "temp", "--path", Path.dirname(file_path)]) + + file = File.read!(file_path) + assert file =~ "config :pleroma, :setting_first," + assert file =~ "config :pleroma, :setting_second," + assert file =~ "config :quack, :level, :info" + end + + test "release", %{file_path: file_path} do + clear_config(:release, true) + clear_config(:config_path, file_path) + + MixTask.run(["migrate_from_db", "--env", "temp"]) + + file = File.read!(file_path) + assert file =~ "config :pleroma, :setting_first," + assert file =~ "config :pleroma, :setting_second," + assert file =~ "config :quack, :level, :info" + end + end + + describe "operations on database config" do + setup do: clear_config(:configurable_from_database, true) + + test "dumping a specific group" do + insert_config_record(:pleroma, :instance, name: "Pleroma Test") + + insert_config_record(:web_push_encryption, :vapid_details, + subject: "mailto:administrator@example.com", + public_key: + "BOsPL-_KjNnjj_RMvLeR3dTOrcndi4TbMR0cu56gLGfGaT5m1gXxSfRHOcC4Dd78ycQL1gdhtx13qgKHmTM5xAI", + private_key: "Ism6FNdS31nLCA94EfVbJbDdJXCxAZ8cZiB1JQPN_t4" + ) + + MixTask.run(["dump", "pleroma"]) + + assert_receive {:mix_shell, :info, + ["config :pleroma, :instance, [name: \"Pleroma Test\"]\r\n\r\n"]} + + refute_receive { + :mix_shell, + :info, + [ + "config :web_push_encryption, :vapid_details, [subject: \"mailto:administrator@example.com\", public_key: \"BOsPL-_KjNnjj_RMvLeR3dTOrcndi4TbMR0cu56gLGfGaT5m1gXxSfRHOcC4Dd78ycQL1gdhtx13qgKHmTM5xAI\", private_key: \"Ism6FNdS31nLCA94EfVbJbDdJXCxAZ8cZiB1JQPN_t4\"]\r\n\r\n" + ] + } + + # Ensure operations work when using atom syntax + MixTask.run(["dump", ":pleroma"]) + + assert_receive {:mix_shell, :info, + ["config :pleroma, :instance, [name: \"Pleroma Test\"]\r\n\r\n"]} + end + + test "dumping a specific key in a group" do + insert_config_record(:pleroma, :instance, name: "Pleroma Test") + insert_config_record(:pleroma, Pleroma.Captcha, enabled: false) + + MixTask.run(["dump", "pleroma", "Pleroma.Captcha"]) + + refute_receive {:mix_shell, :info, + ["config :pleroma, :instance, [name: \"Pleroma Test\"]\r\n\r\n"]} + + assert_receive {:mix_shell, :info, + ["config :pleroma, Pleroma.Captcha, [enabled: false]\r\n\r\n"]} + end + + test "dumps all configuration successfully" do + insert_config_record(:pleroma, :instance, name: "Pleroma Test") + insert_config_record(:pleroma, Pleroma.Captcha, enabled: false) + + MixTask.run(["dump"]) + + assert_receive {:mix_shell, :info, + ["config :pleroma, :instance, [name: \"Pleroma Test\"]\r\n\r\n"]} + + assert_receive {:mix_shell, :info, + ["config :pleroma, Pleroma.Captcha, [enabled: false]\r\n\r\n"]} + end + end + + describe "when configdb disabled" do + test "refuses to dump" do + clear_config(:configurable_from_database, false) + + insert_config_record(:pleroma, :instance, name: "Pleroma Test") + + MixTask.run(["dump"]) + + msg = + "ConfigDB not enabled. Please check the value of :configurable_from_database in your configuration." + + assert_receive {:mix_shell, :error, [^msg]} + end + end + + describe "destructive operations" do + setup do: clear_config(:configurable_from_database, true) + + setup do + insert_config_record(:pleroma, :instance, name: "Pleroma Test") + insert_config_record(:pleroma, Pleroma.Captcha, enabled: false) + insert_config_record(:pleroma2, :key2, z: 1) + + assert length(config_records()) == 3 + + :ok + end + + test "deletes group of settings" do + MixTask.run(["delete", "--force", "pleroma"]) + + assert [%ConfigDB{group: :pleroma2, key: :key2}] = config_records() + end + + test "deletes specified key" do + MixTask.run(["delete", "--force", "pleroma", "Pleroma.Captcha"]) + + assert [ + %ConfigDB{group: :pleroma, key: :instance}, + %ConfigDB{group: :pleroma2, key: :key2} + ] = config_records() + end + + test "resets entire config" do + MixTask.run(["reset", "--force"]) + + assert config_records() == [] + end + end +end diff --git a/test/tasks/count_statuses_test.exs b/test/mix/tasks/pleroma/count_statuses_test.exs index c5cd16960..80ec206b8 100644 --- a/test/tasks/count_statuses_test.exs +++ b/test/mix/tasks/pleroma/count_statuses_test.exs @@ -1,8 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Mix.Tasks.Pleroma.CountStatusesTest do + # Uses log capture, has to stay synchronous use Pleroma.DataCase alias Pleroma.User diff --git a/test/tasks/database_test.exs b/test/mix/tasks/pleroma/database_test.exs index 3a28aa133..7a1a759da 100644 --- a/test/tasks/database_test.exs +++ b/test/mix/tasks/pleroma/database_test.exs @@ -1,16 +1,17 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Mix.Tasks.Pleroma.DatabaseTest do + use Pleroma.DataCase, async: true + use Oban.Testing, repo: Pleroma.Repo + alias Pleroma.Activity alias Pleroma.Object alias Pleroma.Repo alias Pleroma.User alias Pleroma.Web.CommonAPI - use Pleroma.DataCase - import Pleroma.Factory setup_all do @@ -72,7 +73,7 @@ defmodule Mix.Tasks.Pleroma.DatabaseTest do describe "running update_users_following_followers_counts" do test "following and followers count are updated" do [user, user2] = insert_pair(:user) - {:ok, %User{} = user} = User.follow(user, user2) + {:ok, %User{} = user, _user2} = User.follow(user, user2) following = User.following(user) @@ -86,7 +87,8 @@ defmodule Mix.Tasks.Pleroma.DatabaseTest do assert user.follower_count == 3 - assert :ok == Mix.Tasks.Pleroma.Database.run(["update_users_following_followers_counts"]) + assert {:ok, :ok} == + Mix.Tasks.Pleroma.Database.run(["update_users_following_followers_counts"]) user = User.get_by_id(user.id) @@ -130,40 +132,45 @@ defmodule Mix.Tasks.Pleroma.DatabaseTest do describe "ensure_expiration" do test "it adds to expiration old statuses" do - %{id: activity_id1} = insert(:note_activity) + activity1 = insert(:note_activity) - %{id: activity_id2} = - insert(:note_activity, %{inserted_at: NaiveDateTime.from_iso8601!("2015-01-23 23:50:07")}) + {:ok, inserted_at, 0} = DateTime.from_iso8601("2015-01-23T23:50:07Z") + activity2 = insert(:note_activity, %{inserted_at: inserted_at}) - %{id: activity_id3} = activity3 = insert(:note_activity) + %{id: activity_id3} = insert(:note_activity) - expires_at = - NaiveDateTime.utc_now() - |> NaiveDateTime.add(60 * 61, :second) - |> NaiveDateTime.truncate(:second) + expires_at = DateTime.add(DateTime.utc_now(), 60 * 61) - Pleroma.ActivityExpiration.create(activity3, expires_at) + Pleroma.Workers.PurgeExpiredActivity.enqueue(%{ + activity_id: activity_id3, + expires_at: expires_at + }) Mix.Tasks.Pleroma.Database.run(["ensure_expiration"]) - expirations = - Pleroma.ActivityExpiration - |> order_by(:activity_id) - |> Repo.all() - - assert [ - %Pleroma.ActivityExpiration{ - activity_id: ^activity_id1 - }, - %Pleroma.ActivityExpiration{ - activity_id: ^activity_id2, - scheduled_at: ~N[2016-01-23 23:50:07] - }, - %Pleroma.ActivityExpiration{ - activity_id: ^activity_id3, - scheduled_at: ^expires_at - } - ] = expirations + assert_enqueued( + worker: Pleroma.Workers.PurgeExpiredActivity, + args: %{activity_id: activity1.id}, + scheduled_at: + activity1.inserted_at + |> DateTime.from_naive!("Etc/UTC") + |> Timex.shift(days: 365) + ) + + assert_enqueued( + worker: Pleroma.Workers.PurgeExpiredActivity, + args: %{activity_id: activity2.id}, + scheduled_at: + activity2.inserted_at + |> DateTime.from_naive!("Etc/UTC") + |> Timex.shift(days: 365) + ) + + assert_enqueued( + worker: Pleroma.Workers.PurgeExpiredActivity, + args: %{activity_id: activity_id3}, + scheduled_at: expires_at + ) end end end diff --git a/test/tasks/digest_test.exs b/test/mix/tasks/pleroma/digest_test.exs index 0b444c86d..4a9e461a9 100644 --- a/test/tasks/digest_test.exs +++ b/test/mix/tasks/pleroma/digest_test.exs @@ -1,3 +1,7 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + defmodule Mix.Tasks.Pleroma.DigestTest do use Pleroma.DataCase diff --git a/test/tasks/ecto/migrate_test.exs b/test/mix/tasks/pleroma/ecto/migrate_test.exs index 43df176a1..3bfdde1c0 100644 --- a/test/tasks/ecto/migrate_test.exs +++ b/test/mix/tasks/pleroma/ecto/migrate_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-onl defmodule Mix.Tasks.Pleroma.Ecto.MigrateTest do - use Pleroma.DataCase, async: true + use Pleroma.DataCase import ExUnit.CaptureLog require Logger @@ -13,7 +13,7 @@ defmodule Mix.Tasks.Pleroma.Ecto.MigrateTest do assert capture_log(fn -> Mix.Tasks.Pleroma.Ecto.Migrate.run() - end) =~ "[info] Already up" + end) =~ "[info] Migrations already up" Logger.configure(level: level) end diff --git a/test/tasks/ecto/rollback_test.exs b/test/mix/tasks/pleroma/ecto/rollback_test.exs index 0236e35d5..f8a37bd49 100644 --- a/test/tasks/ecto/rollback_test.exs +++ b/test/mix/tasks/pleroma/ecto/rollback_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Mix.Tasks.Pleroma.Ecto.RollbackTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true import ExUnit.CaptureLog require Logger @@ -12,7 +12,7 @@ defmodule Mix.Tasks.Pleroma.Ecto.RollbackTest do Logger.configure(level: :warn) assert capture_log(fn -> - Mix.Tasks.Pleroma.Ecto.Rollback.run() + Mix.Tasks.Pleroma.Ecto.Rollback.run(["--env", "test"]) end) =~ "[info] Rollback succesfully" Logger.configure(level: level) diff --git a/test/tasks/ecto/ecto_test.exs b/test/mix/tasks/pleroma/ecto_test.exs index 3a028df83..0164da5a8 100644 --- a/test/tasks/ecto/ecto_test.exs +++ b/test/mix/tasks/pleroma/ecto_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Mix.Tasks.Pleroma.EctoTest do diff --git a/test/mix/tasks/pleroma/email_test.exs b/test/mix/tasks/pleroma/email_test.exs new file mode 100644 index 000000000..ce68b88de --- /dev/null +++ b/test/mix/tasks/pleroma/email_test.exs @@ -0,0 +1,127 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Mix.Tasks.Pleroma.EmailTest do + use Pleroma.DataCase + + import Swoosh.TestAssertions + + alias Pleroma.Config + alias Pleroma.Tests.ObanHelpers + + import Pleroma.Factory + + setup_all do + Mix.shell(Mix.Shell.Process) + + on_exit(fn -> + Mix.shell(Mix.Shell.IO) + end) + + :ok + end + + setup do: clear_config([Pleroma.Emails.Mailer, :enabled], true) + setup do: clear_config([:instance, :account_activation_required], true) + + describe "pleroma.email test" do + test "Sends test email with no given address" do + mail_to = Config.get([:instance, :email]) + + :ok = Mix.Tasks.Pleroma.Email.run(["test"]) + + ObanHelpers.perform_all() + + assert_receive {:mix_shell, :info, [message]} + assert message =~ "Test email has been sent" + + assert_email_sent( + to: mail_to, + html_body: ~r/a test email was requested./i + ) + end + + test "Sends test email with given address" do + mail_to = "hewwo@example.com" + + :ok = Mix.Tasks.Pleroma.Email.run(["test", "--to", mail_to]) + + ObanHelpers.perform_all() + + assert_receive {:mix_shell, :info, [message]} + assert message =~ "Test email has been sent" + + assert_email_sent( + to: mail_to, + html_body: ~r/a test email was requested./i + ) + end + + test "Sends confirmation emails" do + local_user1 = + insert(:user, %{ + is_confirmed: false, + confirmation_token: "mytoken", + is_active: true, + email: "local1@pleroma.com", + local: true + }) + + local_user2 = + insert(:user, %{ + is_confirmed: false, + confirmation_token: "mytoken", + is_active: true, + email: "local2@pleroma.com", + local: true + }) + + :ok = Mix.Tasks.Pleroma.Email.run(["resend_confirmation_emails"]) + + ObanHelpers.perform_all() + + assert_email_sent(to: {local_user1.name, local_user1.email}) + assert_email_sent(to: {local_user2.name, local_user2.email}) + end + + test "Does not send confirmation email to inappropriate users" do + # confirmed user + insert(:user, %{ + is_confirmed: true, + confirmation_token: "mytoken", + is_active: true, + email: "confirmed@pleroma.com", + local: true + }) + + # remote user + insert(:user, %{ + is_active: true, + email: "remote@not-pleroma.com", + local: false + }) + + # deactivated user = + insert(:user, %{ + is_active: false, + email: "deactivated@pleroma.com", + local: false + }) + + # invisible user + insert(:user, %{ + is_active: true, + email: "invisible@pleroma.com", + local: true, + invisible: true + }) + + :ok = Mix.Tasks.Pleroma.Email.run(["resend_confirmation_emails"]) + + ObanHelpers.perform_all() + + refute_email_sent() + end + end +end diff --git a/test/tasks/emoji_test.exs b/test/mix/tasks/pleroma/emoji_test.exs index 499f098c2..bd20f285c 100644 --- a/test/tasks/emoji_test.exs +++ b/test/mix/tasks/pleroma/emoji_test.exs @@ -1,3 +1,7 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + defmodule Mix.Tasks.Pleroma.EmojiTest do use ExUnit.Case, async: true diff --git a/test/tasks/frontend_test.exs b/test/mix/tasks/pleroma/frontend_test.exs index 022ae51be..aa4b25ebb 100644 --- a/test/tasks/frontend_test.exs +++ b/test/mix/tasks/pleroma/frontend_test.exs @@ -1,8 +1,8 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.FrontendTest do +defmodule Mix.Tasks.Pleroma.FrontendTest do use Pleroma.DataCase alias Mix.Tasks.Pleroma.Frontend diff --git a/test/tasks/instance_test.exs b/test/mix/tasks/pleroma/instance_test.exs index 3b4c041d9..5a5a68053 100644 --- a/test/tasks/instance_test.exs +++ b/test/mix/tasks/pleroma/instance_test.exs @@ -1,9 +1,10 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.InstanceTest do - use ExUnit.Case +defmodule Mix.Tasks.Pleroma.InstanceTest do + # Modifies the Application Environment, has to stay synchronous. + use Pleroma.DataCase setup do File.mkdir_p!(tmp_path()) @@ -15,15 +16,17 @@ defmodule Pleroma.InstanceTest do if File.exists?(static_dir) do File.rm_rf(Path.join(static_dir, "robots.txt")) end - - Pleroma.Config.put([:instance, :static_dir], static_dir) end) + # Is being modified by the mix task. + clear_config([:instance, :static_dir]) + :ok end + @uuid Ecto.UUID.generate() defp tmp_path do - "/tmp/generated_files/" + "/tmp/generated_files/#{@uuid}/" end test "running gen" do @@ -63,7 +66,13 @@ defmodule Pleroma.InstanceTest do "--uploads-dir", "test/uploads", "--static-dir", - "./test/../test/instance/static/" + "./test/../test/instance/static/", + "--strip-uploads", + "y", + "--dedupe-uploads", + "n", + "--anonymize-uploads", + "n" ]) end @@ -82,6 +91,7 @@ defmodule Pleroma.InstanceTest do assert generated_config =~ "password: \"dbpass\"" assert generated_config =~ "configurable_from_database: true" assert generated_config =~ "http: [ip: {127, 0, 0, 1}, port: 4000]" + assert generated_config =~ "filters: [Pleroma.Upload.Filter.Exiftool]" assert File.read!(tmp_path() <> "setup.psql") == generated_setup_psql() assert File.exists?(Path.expand("./test/instance/static/robots.txt")) end diff --git a/test/tasks/refresh_counter_cache_test.exs b/test/mix/tasks/pleroma/refresh_counter_cache_test.exs index 6a1a9ac17..fe9e5cfeb 100644 --- a/test/tasks/refresh_counter_cache_test.exs +++ b/test/mix/tasks/pleroma/refresh_counter_cache_test.exs @@ -1,8 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Mix.Tasks.Pleroma.RefreshCounterCacheTest do + # Uses log capture, has to stay synchronous use Pleroma.DataCase alias Pleroma.Web.CommonAPI import ExUnit.CaptureIO, only: [capture_io: 1] diff --git a/test/tasks/relay_test.exs b/test/mix/tasks/pleroma/relay_test.exs index e5225b64c..db75b3630 100644 --- a/test/tasks/relay_test.exs +++ b/test/mix/tasks/pleroma/relay_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Mix.Tasks.Pleroma.RelayTest do @@ -81,6 +81,80 @@ defmodule Mix.Tasks.Pleroma.RelayTest do assert undo_activity.data["object"]["id"] == cancelled_activity.data["id"] refute "#{target_instance}/followers" in User.following(local_user) end + + test "unfollow when relay is dead" do + user = insert(:user) + target_instance = user.ap_id + + Mix.Tasks.Pleroma.Relay.run(["follow", target_instance]) + + %User{ap_id: follower_id} = local_user = Relay.get_actor() + target_user = User.get_cached_by_ap_id(target_instance) + follow_activity = Utils.fetch_latest_follow(local_user, target_user) + User.follow(local_user, target_user) + + assert "#{target_instance}/followers" in User.following(local_user) + + Tesla.Mock.mock(fn %{method: :get, url: ^target_instance} -> + %Tesla.Env{status: 404} + end) + + Pleroma.Repo.delete(user) + User.invalidate_cache(user) + + Mix.Tasks.Pleroma.Relay.run(["unfollow", target_instance]) + + cancelled_activity = Activity.get_by_ap_id(follow_activity.data["id"]) + assert cancelled_activity.data["state"] == "accept" + + assert [] == + ActivityPub.fetch_activities( + [], + %{ + type: "Undo", + actor_id: follower_id, + skip_preload: true, + invisible_actors: true + } + ) + end + + test "force unfollow when relay is dead" do + user = insert(:user) + target_instance = user.ap_id + + Mix.Tasks.Pleroma.Relay.run(["follow", target_instance]) + + %User{ap_id: follower_id} = local_user = Relay.get_actor() + target_user = User.get_cached_by_ap_id(target_instance) + follow_activity = Utils.fetch_latest_follow(local_user, target_user) + User.follow(local_user, target_user) + + assert "#{target_instance}/followers" in User.following(local_user) + + Tesla.Mock.mock(fn %{method: :get, url: ^target_instance} -> + %Tesla.Env{status: 404} + end) + + Pleroma.Repo.delete(user) + User.invalidate_cache(user) + + Mix.Tasks.Pleroma.Relay.run(["unfollow", target_instance, "--force"]) + + cancelled_activity = Activity.get_by_ap_id(follow_activity.data["id"]) + assert cancelled_activity.data["state"] == "cancelled" + + [undo_activity] = + ActivityPub.fetch_activities( + [], + %{type: "Undo", actor_id: follower_id, skip_preload: true, invisible_actors: true} + ) + + assert undo_activity.data["type"] == "Undo" + assert undo_activity.data["actor"] == local_user.ap_id + assert undo_activity.data["object"]["id"] == cancelled_activity.data["id"] + refute "#{target_instance}/followers" in User.following(local_user) + end end describe "mix pleroma.relay list" do diff --git a/test/tasks/robots_txt_test.exs b/test/mix/tasks/pleroma/robots_txt_test.exs index 7040a0e4e..028aa4ccc 100644 --- a/test/tasks/robots_txt_test.exs +++ b/test/mix/tasks/pleroma/robots_txt_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Mix.Tasks.Pleroma.RobotsTxtTest do @@ -12,7 +12,7 @@ defmodule Mix.Tasks.Pleroma.RobotsTxtTest do test "creates new dir" do path = "test/fixtures/new_dir/" file_path = path <> "robots.txt" - Pleroma.Config.put([:instance, :static_dir], path) + clear_config([:instance, :static_dir], path) on_exit(fn -> {:ok, ["test/fixtures/new_dir/", "test/fixtures/new_dir/robots.txt"]} = File.rm_rf(path) @@ -29,7 +29,7 @@ defmodule Mix.Tasks.Pleroma.RobotsTxtTest do test "to existance folder" do path = "test/fixtures/" file_path = path <> "robots.txt" - Pleroma.Config.put([:instance, :static_dir], path) + clear_config([:instance, :static_dir], path) on_exit(fn -> :ok = File.rm(file_path) diff --git a/test/tasks/uploads_test.exs b/test/mix/tasks/pleroma/uploads_test.exs index d69e149a8..a7d15e0fa 100644 --- a/test/tasks/uploads_test.exs +++ b/test/mix/tasks/pleroma/uploads_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Mix.Tasks.Pleroma.UploadsTest do diff --git a/test/tasks/user_test.exs b/test/mix/tasks/pleroma/user_test.exs index ce43a9cc7..a2178bbd1 100644 --- a/test/tasks/user_test.exs +++ b/test/mix/tasks/pleroma/user_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Mix.Tasks.Pleroma.UserTest do @@ -36,7 +36,7 @@ defmodule Mix.Tasks.Pleroma.UserTest do unsaved = build(:user) # prepare to answer yes - send(self(), {:mix_shell_input, :yes?, true}) + send(self(), {:mix_shell_input, :prompt, "Y"}) Mix.Tasks.Pleroma.User.run([ "new", @@ -55,7 +55,7 @@ defmodule Mix.Tasks.Pleroma.UserTest do assert_received {:mix_shell, :info, [message]} assert message =~ "user will be created" - assert_received {:mix_shell, :yes?, [message]} + assert_received {:mix_shell, :prompt, [message]} assert message =~ "Continue" assert_received {:mix_shell, :info, [message]} @@ -73,14 +73,14 @@ defmodule Mix.Tasks.Pleroma.UserTest do unsaved = build(:user) # prepare to answer no - send(self(), {:mix_shell_input, :yes?, false}) + send(self(), {:mix_shell_input, :prompt, "N"}) Mix.Tasks.Pleroma.User.run(["new", unsaved.nickname, unsaved.email]) assert_received {:mix_shell, :info, [message]} assert message =~ "user will be created" - assert_received {:mix_shell, :yes?, [message]} + assert_received {:mix_shell, :prompt, [message]} assert message =~ "Continue" assert_received {:mix_shell, :info, [message]} @@ -102,7 +102,7 @@ defmodule Mix.Tasks.Pleroma.UserTest do assert_received {:mix_shell, :info, [message]} assert message =~ " deleted" - assert %{deactivated: true} = User.get_by_nickname(user.nickname) + assert %{is_active: false} = User.get_by_nickname(user.nickname) assert called(Pleroma.Web.Federator.publish(:_)) end @@ -114,7 +114,7 @@ defmodule Mix.Tasks.Pleroma.UserTest do {:ok, post} = CommonAPI.post(user, %{status: "uguu"}) {:ok, post2} = CommonAPI.post(user2, %{status: "test"}) - obj = Object.normalize(post2) + obj = Object.normalize(post2, fetch: false) {:ok, like_object, meta} = Pleroma.Web.ActivityPub.Builder.like(user, obj) @@ -130,7 +130,7 @@ defmodule Mix.Tasks.Pleroma.UserTest do clear_config([:instance, :federating], true) - object = Object.normalize(post) + object = Object.normalize(post, fetch: false) Object.prune(object) with_mock Pleroma.Web.Federator, @@ -140,7 +140,7 @@ defmodule Mix.Tasks.Pleroma.UserTest do assert_received {:mix_shell, :info, [message]} assert message =~ " deleted" - assert %{deactivated: true} = User.get_by_nickname(user.nickname) + assert %{is_active: false} = User.get_by_nickname(user.nickname) assert called(Pleroma.Web.Federator.publish(:_)) refute Pleroma.Repo.get(Pleroma.Activity, like_activity.id) @@ -157,41 +157,8 @@ defmodule Mix.Tasks.Pleroma.UserTest do end end - describe "running toggle_activated" do - test "user is deactivated" do - user = insert(:user) - - Mix.Tasks.Pleroma.User.run(["toggle_activated", user.nickname]) - - assert_received {:mix_shell, :info, [message]} - assert message =~ " deactivated" - - user = User.get_cached_by_nickname(user.nickname) - assert user.deactivated - end - - test "user is activated" do - user = insert(:user, deactivated: true) - - Mix.Tasks.Pleroma.User.run(["toggle_activated", user.nickname]) - - assert_received {:mix_shell, :info, [message]} - assert message =~ " activated" - - user = User.get_cached_by_nickname(user.nickname) - refute user.deactivated - end - - test "no user to toggle" do - Mix.Tasks.Pleroma.User.run(["toggle_activated", "nonexistent"]) - - assert_received {:mix_shell, :error, [message]} - assert message =~ "No user" - end - end - describe "running deactivate" do - test "user is unsubscribed" do + test "active user is deactivated and unsubscribed" do followed = insert(:user) remote_followed = insert(:user, local: false) user = insert(:user) @@ -201,16 +168,26 @@ defmodule Mix.Tasks.Pleroma.UserTest do Mix.Tasks.Pleroma.User.run(["deactivate", user.nickname]) - assert_received {:mix_shell, :info, [message]} - assert message =~ "Deactivating" - # Note that the task has delay :timer.sleep(500) assert_received {:mix_shell, :info, [message]} - assert message =~ "Successfully unsubscribed" + + assert message == + "Successfully deactivated #{user.nickname} and unsubscribed all local followers" user = User.get_cached_by_nickname(user.nickname) assert Enum.empty?(Enum.filter(User.get_friends(user), & &1.local)) - assert user.deactivated + refute user.is_active + end + + test "user is deactivated" do + %{id: id, nickname: nickname} = insert(:user, is_active: false) + + assert :ok = Mix.Tasks.Pleroma.User.run(["deactivate", nickname]) + assert_received {:mix_shell, :info, [message]} + assert message == "User #{nickname} already deactivated" + + user = Repo.get(User, id) + refute user.is_active end test "no user to deactivate" do @@ -225,47 +202,69 @@ defmodule Mix.Tasks.Pleroma.UserTest do test "All statuses set" do user = insert(:user) - Mix.Tasks.Pleroma.User.run(["set", user.nickname, "--moderator", "--admin", "--locked"]) + Mix.Tasks.Pleroma.User.run([ + "set", + user.nickname, + "--admin", + "--confirmed", + "--locked", + "--moderator" + ]) + + assert_received {:mix_shell, :info, [message]} + assert message =~ ~r/Admin status .* true/ assert_received {:mix_shell, :info, [message]} - assert message =~ ~r/Moderator status .* true/ + assert message =~ ~r/Confirmation status.* true/ assert_received {:mix_shell, :info, [message]} assert message =~ ~r/Locked status .* true/ assert_received {:mix_shell, :info, [message]} - assert message =~ ~r/Admin status .* true/ + assert message =~ ~r/Moderator status .* true/ user = User.get_cached_by_nickname(user.nickname) assert user.is_moderator - assert user.locked + assert user.is_locked assert user.is_admin + assert user.is_confirmed end test "All statuses unset" do - user = insert(:user, locked: true, is_moderator: true, is_admin: true) + user = + insert(:user, + is_locked: true, + is_moderator: true, + is_admin: true, + is_confirmed: false + ) Mix.Tasks.Pleroma.User.run([ "set", user.nickname, - "--no-moderator", "--no-admin", - "--no-locked" + "--no-confirmed", + "--no-locked", + "--no-moderator" ]) assert_received {:mix_shell, :info, [message]} - assert message =~ ~r/Moderator status .* false/ + assert message =~ ~r/Admin status .* false/ + + assert_received {:mix_shell, :info, [message]} + assert message =~ ~r/Confirmation status.* false/ assert_received {:mix_shell, :info, [message]} assert message =~ ~r/Locked status .* false/ assert_received {:mix_shell, :info, [message]} - assert message =~ ~r/Admin status .* false/ + assert message =~ ~r/Moderator status .* false/ user = User.get_cached_by_nickname(user.nickname) refute user.is_moderator - refute user.locked + refute user.is_locked refute user.is_admin + refute user.is_confirmed end test "no user to set status" do @@ -414,13 +413,6 @@ defmodule Mix.Tasks.Pleroma.UserTest do assert_received {:mix_shell, :info, [message]} assert message =~ "Invite for token #{invite.token} was revoked." end - - test "it prints an error message when invite is not exist" do - Mix.Tasks.Pleroma.User.run(["revoke_invite", "foo"]) - - assert_received {:mix_shell, :error, [message]} - assert message =~ "No invite found" - end end describe "running delete_activities" do @@ -440,40 +432,71 @@ defmodule Mix.Tasks.Pleroma.UserTest do end end - describe "running toggle_confirmed" do + describe "running confirm" do test "user is confirmed" do - %{id: id, nickname: nickname} = insert(:user, confirmation_pending: false) + %{id: id, nickname: nickname} = insert(:user, is_confirmed: true) - assert :ok = Mix.Tasks.Pleroma.User.run(["toggle_confirmed", nickname]) + assert :ok = Mix.Tasks.Pleroma.User.run(["confirm", nickname]) assert_received {:mix_shell, :info, [message]} - assert message == "#{nickname} needs confirmation." + assert message == "#{nickname} doesn't need confirmation." user = Repo.get(User, id) - assert user.confirmation_pending - assert user.confirmation_token + assert user.is_confirmed + refute user.confirmation_token end test "user is not confirmed" do %{id: id, nickname: nickname} = - insert(:user, confirmation_pending: true, confirmation_token: "some token") + insert(:user, is_confirmed: false, confirmation_token: "some token") - assert :ok = Mix.Tasks.Pleroma.User.run(["toggle_confirmed", nickname]) + assert :ok = Mix.Tasks.Pleroma.User.run(["confirm", nickname]) assert_received {:mix_shell, :info, [message]} assert message == "#{nickname} doesn't need confirmation." user = Repo.get(User, id) - refute user.confirmation_pending + assert user.is_confirmed refute user.confirmation_token end test "it prints an error message when user is not exist" do - Mix.Tasks.Pleroma.User.run(["toggle_confirmed", "foo"]) + Mix.Tasks.Pleroma.User.run(["confirm", "foo"]) assert_received {:mix_shell, :error, [message]} assert message =~ "No local user" end end + describe "running activate" do + test "user is activated" do + %{id: id, nickname: nickname} = insert(:user, is_active: true) + + assert :ok = Mix.Tasks.Pleroma.User.run(["activate", nickname]) + assert_received {:mix_shell, :info, [message]} + assert message == "User #{nickname} already activated" + + user = Repo.get(User, id) + assert user.is_active + end + + test "user is not activated" do + %{id: id, nickname: nickname} = insert(:user, is_active: false) + + assert :ok = Mix.Tasks.Pleroma.User.run(["activate", nickname]) + assert_received {:mix_shell, :info, [message]} + assert message == "Successfully activated #{nickname}" + + user = Repo.get(User, id) + assert user.is_active + end + + test "no user to activate" do + Mix.Tasks.Pleroma.User.run(["activate", "foo"]) + + assert_received {:mix_shell, :error, [message]} + assert message =~ "No user" + end + end + describe "search" do test "it returns users matching" do user = insert(:user) @@ -481,7 +504,7 @@ defmodule Mix.Tasks.Pleroma.UserTest do moot = insert(:user, nickname: "moot") kawen = insert(:user, nickname: "kawen", name: "fediverse expert moon") - {:ok, user} = User.follow(user, moon) + {:ok, user, moon} = User.follow(user, moon) assert [moon.id, kawen.id] == User.Search.search("moon") |> Enum.map(& &1.id) @@ -554,4 +577,44 @@ defmodule Mix.Tasks.Pleroma.UserTest do assert message =~ "Could not change user tags" end end + + describe "bulk confirm and unconfirm" do + test "confirm all" do + user1 = insert(:user, is_confirmed: false) + user2 = insert(:user, is_confirmed: false) + + refute user1.is_confirmed + refute user2.is_confirmed + + Mix.Tasks.Pleroma.User.run(["confirm_all"]) + + user1 = User.get_cached_by_nickname(user1.nickname) + user2 = User.get_cached_by_nickname(user2.nickname) + + assert user1.is_confirmed + assert user2.is_confirmed + end + + test "unconfirm all" do + user1 = insert(:user, is_confirmed: true) + user2 = insert(:user, is_confirmed: true) + admin = insert(:user, is_admin: true, is_confirmed: true) + mod = insert(:user, is_moderator: true, is_confirmed: true) + + assert user1.is_confirmed + assert user2.is_confirmed + + Mix.Tasks.Pleroma.User.run(["unconfirm_all"]) + + user1 = User.get_cached_by_nickname(user1.nickname) + user2 = User.get_cached_by_nickname(user2.nickname) + admin = User.get_cached_by_nickname(admin.nickname) + mod = User.get_cached_by_nickname(mod.nickname) + + refute user1.is_confirmed + refute user2.is_confirmed + assert admin.is_confirmed + assert mod.is_confirmed + end + end end diff --git a/test/activity/ir/topics_test.exs b/test/pleroma/activity/ir/topics_test.exs index 14a6e6b71..9c8e5d932 100644 --- a/test/activity/ir/topics_test.exs +++ b/test/pleroma/activity/ir/topics_test.exs @@ -1,5 +1,9 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + defmodule Pleroma.Activity.Ir.TopicsTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true alias Pleroma.Activity alias Pleroma.Activity.Ir.Topics @@ -7,6 +11,8 @@ defmodule Pleroma.Activity.Ir.TopicsTest do require Pleroma.Constants + import Mock + describe "poll answer" do test "produce no topics" do activity = %Activity{object: %Object{data: %{"type" => "Answer"}}} @@ -73,14 +79,13 @@ defmodule Pleroma.Activity.Ir.TopicsTest do refute Enum.member?(topics, "public:local:media") end - test "converts tags to hash tags", %{activity: %{object: %{data: data} = object} = activity} do - tagged_data = Map.put(data, "tag", ["foo", "bar"]) - activity = %{activity | object: %{object | data: tagged_data}} - - topics = Topics.get_activity_topics(activity) + test "converts tags to hash tags", %{activity: activity} do + with_mock(Object, [:passthrough], hashtags: fn _ -> ["foo", "bar"] end) do + topics = Topics.get_activity_topics(activity) - assert Enum.member?(topics, "hashtag:foo") - assert Enum.member?(topics, "hashtag:bar") + assert Enum.member?(topics, "hashtag:foo") + assert Enum.member?(topics, "hashtag:bar") + end end test "only converts strings to hash tags", %{ @@ -93,6 +98,20 @@ defmodule Pleroma.Activity.Ir.TopicsTest do refute Enum.member?(topics, "hashtag:2") end + + test "non-local action produces public:remote topic", %{activity: activity} do + activity = %{activity | local: false, actor: "https://lain.com/users/lain"} + topics = Topics.get_activity_topics(activity) + + assert Enum.member?(topics, "public:remote:lain.com") + end + + test "local action doesn't produce public:remote topic", %{activity: activity} do + activity = %{activity | local: true, actor: "https://lain.com/users/lain"} + topics = Topics.get_activity_topics(activity) + + refute Enum.member?(topics, "public:remote:lain.com") + end end describe "public visibility create events with attachments" do @@ -124,6 +143,13 @@ defmodule Pleroma.Activity.Ir.TopicsTest do refute Enum.member?(topics, "public:local:media") end + + test "non-local action produces public:remote:media topic", %{activity: activity} do + activity = %{activity | local: false, actor: "https://lain.com/users/lain"} + topics = Topics.get_activity_topics(activity) + + assert Enum.member?(topics, "public:remote:media:lain.com") + end end describe "non-public visibility" do diff --git a/test/pleroma/activity/search_test.exs b/test/pleroma/activity/search_test.exs new file mode 100644 index 000000000..657fbc627 --- /dev/null +++ b/test/pleroma/activity/search_test.exs @@ -0,0 +1,45 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Activity.SearchTest do + alias Pleroma.Activity.Search + alias Pleroma.Web.CommonAPI + import Pleroma.Factory + + use Pleroma.DataCase, async: true + + test "it finds something" do + user = insert(:user) + {:ok, post} = CommonAPI.post(user, %{status: "it's wednesday my dudes"}) + + [result] = Search.search(nil, "wednesday") + + assert result.id == post.id + end + + test "using plainto_tsquery on postgres < 11" do + old_version = :persistent_term.get({Pleroma.Repo, :postgres_version}) + :persistent_term.put({Pleroma.Repo, :postgres_version}, 10.0) + on_exit(fn -> :persistent_term.put({Pleroma.Repo, :postgres_version}, old_version) end) + + user = insert(:user) + {:ok, post} = CommonAPI.post(user, %{status: "it's wednesday my dudes"}) + {:ok, _post2} = CommonAPI.post(user, %{status: "it's wednesday my bros"}) + + # plainto doesn't understand complex queries + assert [result] = Search.search(nil, "wednesday -dudes") + + assert result.id == post.id + end + + test "using websearch_to_tsquery" do + user = insert(:user) + {:ok, _post} = CommonAPI.post(user, %{status: "it's wednesday my dudes"}) + {:ok, other_post} = CommonAPI.post(user, %{status: "it's wednesday my bros"}) + + assert [result] = Search.search(nil, "wednesday -dudes") + + assert result.id == other_post.id + end +end diff --git a/test/activity_test.exs b/test/pleroma/activity_test.exs index 2a92327d1..4f9144f91 100644 --- a/test/activity_test.exs +++ b/test/pleroma/activity_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.ActivityTest do @@ -25,7 +25,7 @@ defmodule Pleroma.ActivityTest do test "returns activities by it's objects AP ids" do activity = insert(:note_activity) - object_data = Object.normalize(activity).data + object_data = Object.normalize(activity, fetch: false).data [found_activity] = Activity.get_all_create_by_object_ap_id(object_data["id"]) @@ -34,7 +34,7 @@ defmodule Pleroma.ActivityTest do test "returns the activity that created an object" do activity = insert(:note_activity) - object_data = Object.normalize(activity).data + object_data = Object.normalize(activity, fetch: false).data found_activity = Activity.get_create_by_object_ap_id(object_data["id"]) @@ -123,7 +123,8 @@ defmodule Pleroma.ActivityTest do "type" => "Note", "content" => "find me!", "id" => "http://mastodon.example.org/users/admin/objects/1", - "attributedTo" => "http://mastodon.example.org/users/admin" + "attributedTo" => "http://mastodon.example.org/users/admin", + "to" => ["https://www.w3.org/ns/activitystreams#Public"] }, "to" => ["https://www.w3.org/ns/activitystreams#Public"] } @@ -132,6 +133,7 @@ defmodule Pleroma.ActivityTest do {:ok, japanese_activity} = Pleroma.Web.CommonAPI.post(user, %{status: "更新情報"}) {:ok, job} = Pleroma.Web.Federator.incoming_ap_doc(params) {:ok, remote_activity} = ObanHelpers.perform(job) + remote_activity = Activity.get_by_id_with_object(remote_activity.id) %{ japanese_activity: japanese_activity, @@ -168,7 +170,7 @@ defmodule Pleroma.ActivityTest do test "find only local statuses for unauthenticated users when `limit_to_local_content` is `:all`", %{local_activity: local_activity} do - Pleroma.Config.put([:instance, :limit_to_local_content], :all) + clear_config([:instance, :limit_to_local_content], :all) assert [^local_activity] = Activity.search(nil, "find me") end @@ -177,7 +179,7 @@ defmodule Pleroma.ActivityTest do local_activity: local_activity, remote_activity: remote_activity } do - Pleroma.Config.put([:instance, :limit_to_local_content], false) + clear_config([:instance, :limit_to_local_content], false) activities = Enum.sort_by(Activity.search(nil, "find me"), & &1.id) @@ -185,15 +187,6 @@ defmodule Pleroma.ActivityTest do end end - test "add an activity with an expiration" do - activity = insert(:note_activity) - insert(:expiration_in_the_future, %{activity_id: activity.id}) - - Pleroma.ActivityExpiration - |> where([a], a.activity_id == ^activity.id) - |> Repo.one!() - end - test "all_by_ids_with_object/1" do %{id: id1} = insert(:note_activity) %{id: id2} = insert(:note_activity) @@ -206,6 +199,13 @@ defmodule Pleroma.ActivityTest do assert [%{id: ^id1, object: %Object{}}, %{id: ^id2, object: %Object{}}] = activities end + test "get_by_id_with_user_actor/1" do + user = insert(:user) + activity = insert(:note_activity, note: insert(:note, user: user)) + + assert Activity.get_by_id_with_user_actor(activity.id).user_actor == user + end + test "get_by_id_with_object/1" do %{id: id} = insert(:note_activity) @@ -240,4 +240,42 @@ defmodule Pleroma.ActivityTest do assert [%Activity{id: ^id1}, %Activity{id: ^id2}] = activities end + + test "get_by_object_ap_id_with_object/1" do + user = insert(:user) + another = insert(:user) + + {:ok, %{id: id, object: %{data: %{"id" => obj_id}}}} = + Pleroma.Web.CommonAPI.post(user, %{status: "cofe"}) + + Pleroma.Web.CommonAPI.favorite(another, id) + + assert obj_id + |> Pleroma.Activity.Queries.by_object_id() + |> Repo.aggregate(:count, :id) == 2 + + assert %{id: ^id} = Activity.get_by_object_ap_id_with_object(obj_id) + end + + test "add_by_params_query/3" do + user = insert(:user) + + note = insert(:note_activity, user: user) + + insert(:add_activity, user: user, note: note) + insert(:add_activity, user: user, note: note) + insert(:add_activity, user: user) + + assert Repo.aggregate(Activity, :count, :id) == 4 + + add_query = + Activity.add_by_params_query(note.data["object"], user.ap_id, user.featured_address) + + assert Repo.aggregate(add_query, :count, :id) == 2 + + Repo.delete_all(add_query) + assert Repo.aggregate(add_query, :count, :id) == 0 + + assert Repo.aggregate(Activity, :count, :id) == 2 + end end diff --git a/test/application_requirements_test.exs b/test/pleroma/application_requirements_test.exs index 21d24ddd0..a54c37968 100644 --- a/test/application_requirements_test.exs +++ b/test/pleroma/application_requirements_test.exs @@ -1,25 +1,47 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.ApplicationRequirementsTest do use Pleroma.DataCase + import ExUnit.CaptureLog import Mock + alias Pleroma.ApplicationRequirements alias Pleroma.Repo + describe "check_repo_pool_size!/1" do + test "raises if the pool size is unexpected" do + clear_config([Pleroma.Repo, :pool_size], 11) + clear_config([:dangerzone, :override_repo_pool_size], false) + + assert_raise Pleroma.ApplicationRequirements.VerifyError, + "Repo.pool_size different than recommended value.", + fn -> + capture_log(&Pleroma.ApplicationRequirements.verify!/0) + end + end + + test "doesn't raise if the pool size is unexpected but the respective flag is set" do + clear_config([Pleroma.Repo, :pool_size], 11) + clear_config([:dangerzone, :override_repo_pool_size], true) + + assert Pleroma.ApplicationRequirements.verify!() == :ok + end + end + describe "check_welcome_message_config!/1" do setup do: clear_config([:welcome]) setup do: clear_config([Pleroma.Emails.Mailer]) - test "raises if welcome email enabled but mail disabled" do - Pleroma.Config.put([:welcome, :email, :enabled], true) - Pleroma.Config.put([Pleroma.Emails.Mailer, :enabled], false) + test "warns if welcome email enabled but mail disabled" do + clear_config([:welcome, :email, :enabled], true) + clear_config([Pleroma.Emails.Mailer, :enabled], false) - assert_raise Pleroma.ApplicationRequirements.VerifyError, "The mail disabled.", fn -> - capture_log(&Pleroma.ApplicationRequirements.verify!/0) - end + assert capture_log(fn -> + assert Pleroma.ApplicationRequirements.verify!() == :ok + end) =~ "Welcome emails will NOT be sent" end end @@ -35,26 +57,24 @@ defmodule Pleroma.ApplicationRequirementsTest do setup do: clear_config([:instance, :account_activation_required]) - test "raises if account confirmation is required but mailer isn't enable" do - Pleroma.Config.put([:instance, :account_activation_required], true) - Pleroma.Config.put([Pleroma.Emails.Mailer, :enabled], false) + test "warns if account confirmation is required but mailer isn't enabled" do + clear_config([:instance, :account_activation_required], true) + clear_config([Pleroma.Emails.Mailer, :enabled], false) - assert_raise Pleroma.ApplicationRequirements.VerifyError, - "Account activation enabled, but Mailer is disabled. Cannot send confirmation emails.", - fn -> - capture_log(&Pleroma.ApplicationRequirements.verify!/0) - end + assert capture_log(fn -> + assert Pleroma.ApplicationRequirements.verify!() == :ok + end) =~ "Users will NOT be able to confirm their accounts" end test "doesn't do anything if account confirmation is disabled" do - Pleroma.Config.put([:instance, :account_activation_required], false) - Pleroma.Config.put([Pleroma.Emails.Mailer, :enabled], false) + clear_config([:instance, :account_activation_required], false) + clear_config([Pleroma.Emails.Mailer, :enabled], false) assert Pleroma.ApplicationRequirements.verify!() == :ok end test "doesn't do anything if account confirmation is required and mailer is enabled" do - Pleroma.Config.put([:instance, :account_activation_required], true) - Pleroma.Config.put([Pleroma.Emails.Mailer, :enabled], true) + clear_config([:instance, :account_activation_required], true) + clear_config([Pleroma.Emails.Mailer, :enabled], true) assert Pleroma.ApplicationRequirements.verify!() == :ok end end @@ -70,42 +90,42 @@ defmodule Pleroma.ApplicationRequirementsTest do setup do: clear_config([:database, :rum_enabled]) test "raises if rum is enabled and detects unapplied rum migrations" do - Pleroma.Config.put([:database, :rum_enabled], true) + clear_config([:database, :rum_enabled], true) with_mocks([{Repo, [:passthrough], [exists?: fn _, _ -> false end]}]) do - assert_raise Pleroma.ApplicationRequirements.VerifyError, + assert_raise ApplicationRequirements.VerifyError, "Unapplied RUM Migrations detected", fn -> - capture_log(&Pleroma.ApplicationRequirements.verify!/0) + capture_log(&ApplicationRequirements.verify!/0) end end end test "raises if rum is disabled and detects rum migrations" do - Pleroma.Config.put([:database, :rum_enabled], false) + clear_config([:database, :rum_enabled], false) with_mocks([{Repo, [:passthrough], [exists?: fn _, _ -> true end]}]) do - assert_raise Pleroma.ApplicationRequirements.VerifyError, + assert_raise ApplicationRequirements.VerifyError, "RUM Migrations detected", fn -> - capture_log(&Pleroma.ApplicationRequirements.verify!/0) + capture_log(&ApplicationRequirements.verify!/0) end end end test "doesn't do anything if rum enabled and applied migrations" do - Pleroma.Config.put([:database, :rum_enabled], true) + clear_config([:database, :rum_enabled], true) with_mocks([{Repo, [:passthrough], [exists?: fn _, _ -> true end]}]) do - assert Pleroma.ApplicationRequirements.verify!() == :ok + assert ApplicationRequirements.verify!() == :ok end end test "doesn't do anything if rum disabled" do - Pleroma.Config.put([:database, :rum_enabled], false) + clear_config([:database, :rum_enabled], false) with_mocks([{Repo, [:passthrough], [exists?: fn _, _ -> false end]}]) do - assert Pleroma.ApplicationRequirements.verify!() == :ok + assert ApplicationRequirements.verify!() == :ok end end end @@ -130,17 +150,17 @@ defmodule Pleroma.ApplicationRequirementsTest do setup do: clear_config([:i_am_aware_this_may_cause_data_loss, :disable_migration_check]) test "raises if it detects unapplied migrations" do - assert_raise Pleroma.ApplicationRequirements.VerifyError, + assert_raise ApplicationRequirements.VerifyError, "Unapplied Migrations detected", fn -> - capture_log(&Pleroma.ApplicationRequirements.verify!/0) + capture_log(&ApplicationRequirements.verify!/0) end end test "doesn't do anything if disabled" do - Pleroma.Config.put([:i_am_aware_this_may_cause_data_loss, :disable_migration_check], true) + clear_config([:i_am_aware_this_may_cause_data_loss, :disable_migration_check], true) - assert :ok == Pleroma.ApplicationRequirements.verify!() + assert :ok == ApplicationRequirements.verify!() end end end diff --git a/test/bbs/handler_test.exs b/test/pleroma/bbs/handler_test.exs index eb716486e..3990f8286 100644 --- a/test/bbs/handler_test.exs +++ b/test/pleroma/bbs/handler_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.BBS.HandlerTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true alias Pleroma.Activity alias Pleroma.BBS.Handler alias Pleroma.Object @@ -19,7 +19,7 @@ defmodule Pleroma.BBS.HandlerTest do user = insert(:user) followed = insert(:user) - {:ok, user} = User.follow(user, followed) + {:ok, user, followed} = User.follow(user, followed) {:ok, _first} = CommonAPI.post(user, %{status: "hey"}) {:ok, _second} = CommonAPI.post(followed, %{status: "hello"}) @@ -54,7 +54,7 @@ defmodule Pleroma.BBS.HandlerTest do ) assert activity.actor == user.ap_id - object = Object.normalize(activity) + object = Object.normalize(activity, fetch: false) assert object.data["content"] == "this is a test post" end @@ -63,7 +63,7 @@ defmodule Pleroma.BBS.HandlerTest do another_user = insert(:user) {:ok, activity} = CommonAPI.post(another_user, %{status: "this is a test post"}) - activity_object = Object.normalize(activity) + activity_object = Object.normalize(activity, fetch: false) output = capture_io(fn -> @@ -82,7 +82,7 @@ defmodule Pleroma.BBS.HandlerTest do assert reply.actor == user.ap_id - reply_object_data = Object.normalize(reply).data + reply_object_data = Object.normalize(reply, fetch: false).data assert reply_object_data["content"] == "this is a reply" assert reply_object_data["inReplyTo"] == activity_object.data["id"] end diff --git a/test/bookmark_test.exs b/test/pleroma/bookmark_test.exs index 2726fe7cd..9f64a01c2 100644 --- a/test/bookmark_test.exs +++ b/test/pleroma/bookmark_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.BookmarkTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true import Pleroma.Factory alias Pleroma.Bookmark alias Pleroma.Web.CommonAPI diff --git a/test/captcha_test.exs b/test/pleroma/captcha_test.exs index 1b9f4a12f..fcb585112 100644 --- a/test/captcha_test.exs +++ b/test/pleroma/captcha_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.CaptchaTest do @@ -69,7 +69,7 @@ defmodule Pleroma.CaptchaTest do describe "Captcha Wrapper" do test "validate" do - Pleroma.Config.put([Pleroma.Captcha, :enabled], true) + clear_config([Pleroma.Captcha, :enabled], true) new = Captcha.new() @@ -80,11 +80,10 @@ defmodule Pleroma.CaptchaTest do assert is_binary(answer) assert :ok = Captcha.validate(token, "63615261b77f5354fb8c4e4986477555", answer) - Cachex.del(:used_captcha_cache, token) end test "doesn't validate invalid answer" do - Pleroma.Config.put([Pleroma.Captcha, :enabled], true) + clear_config([Pleroma.Captcha, :enabled], true) new = Captcha.new() @@ -100,7 +99,7 @@ defmodule Pleroma.CaptchaTest do end test "nil answer_data" do - Pleroma.Config.put([Pleroma.Captcha, :enabled], true) + clear_config([Pleroma.Captcha, :enabled], true) new = Captcha.new() diff --git a/test/chat/message_reference_test.exs b/test/pleroma/chat/message_reference_test.exs index aaa7c1ad4..c8db3b450 100644 --- a/test/chat/message_reference_test.exs +++ b/test/pleroma/chat/message_reference_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Chat.MessageReferenceTest do diff --git a/test/chat_test.exs b/test/pleroma/chat_test.exs index 9e8a9ebf0..a5fd1e02e 100644 --- a/test/chat_test.exs +++ b/test/pleroma/chat_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.ChatTest do @@ -73,7 +73,8 @@ defmodule Pleroma.ChatTest do other_user = insert(:user) {:ok, chat} = Chat.bump_or_create(user.id, other_user.ap_id) - :timer.sleep(1500) + {:ok, chat} = time_travel(chat, -2) + {:ok, chat_two} = Chat.bump_or_create(user.id, other_user.ap_id) assert chat.id == chat_two.id diff --git a/test/pleroma/config/deprecation_warnings_test.exs b/test/pleroma/config/deprecation_warnings_test.exs new file mode 100644 index 000000000..c5e2b20f4 --- /dev/null +++ b/test/pleroma/config/deprecation_warnings_test.exs @@ -0,0 +1,336 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Config.DeprecationWarningsTest do + use ExUnit.Case + use Pleroma.Tests.Helpers + + import ExUnit.CaptureLog + + alias Pleroma.Config + alias Pleroma.Config.DeprecationWarnings + + describe "simple policy tuples" do + test "gives warning when there are still strings" do + clear_config([:mrf_simple], + media_removal: ["some.removal"], + media_nsfw: ["some.nsfw"], + federated_timeline_removal: ["some.tl.removal"], + report_removal: ["some.report.removal"], + reject: ["some.reject"], + followers_only: ["some.followers.only"], + accept: ["some.accept"], + avatar_removal: ["some.avatar.removal"], + banner_removal: ["some.banner.removal"], + reject_deletes: ["some.reject.deletes"] + ) + + assert capture_log(fn -> DeprecationWarnings.check_simple_policy_tuples() end) =~ + """ + !!!DEPRECATION WARNING!!! + Your config is using strings in the SimplePolicy configuration instead of tuples. They should work for now, but you are advised to change to the new configuration to prevent possible issues later: + + ``` + config :pleroma, :mrf_simple, + media_removal: ["instance.tld"], + media_nsfw: ["instance.tld"], + federated_timeline_removal: ["instance.tld"], + report_removal: ["instance.tld"], + reject: ["instance.tld"], + followers_only: ["instance.tld"], + accept: ["instance.tld"], + avatar_removal: ["instance.tld"], + banner_removal: ["instance.tld"], + reject_deletes: ["instance.tld"] + ``` + + Is now + + + ``` + config :pleroma, :mrf_simple, + media_removal: [{"instance.tld", "Reason for media removal"}], + media_nsfw: [{"instance.tld", "Reason for media nsfw"}], + federated_timeline_removal: [{"instance.tld", "Reason for federated timeline removal"}], + report_removal: [{"instance.tld", "Reason for report removal"}], + reject: [{"instance.tld", "Reason for reject"}], + followers_only: [{"instance.tld", "Reason for followers only"}], + accept: [{"instance.tld", "Reason for accept"}], + avatar_removal: [{"instance.tld", "Reason for avatar removal"}], + banner_removal: [{"instance.tld", "Reason for banner removal"}], + reject_deletes: [{"instance.tld", "Reason for reject deletes"}] + ``` + """ + end + + test "transforms config to tuples" do + clear_config([:mrf_simple], + media_removal: ["some.removal", {"some.other.instance", "Some reason"}] + ) + + expected_config = [ + {:media_removal, [{"some.removal", ""}, {"some.other.instance", "Some reason"}]} + ] + + capture_log(fn -> DeprecationWarnings.warn() end) + + assert Config.get([:mrf_simple]) == expected_config + end + + test "doesn't give a warning with correct config" do + clear_config([:mrf_simple], + media_removal: [{"some.removal", ""}, {"some.other.instance", "Some reason"}] + ) + + assert capture_log(fn -> DeprecationWarnings.check_simple_policy_tuples() end) == "" + end + end + + describe "quarantined_instances tuples" do + test "gives warning when there are still strings" do + clear_config([:instance, :quarantined_instances], [ + {"domain.com", "some reason"}, + "somedomain.tld" + ]) + + assert capture_log(fn -> DeprecationWarnings.check_quarantined_instances_tuples() end) =~ + """ + !!!DEPRECATION WARNING!!! + Your config is using strings in the quarantined_instances configuration instead of tuples. They should work for now, but you are advised to change to the new configuration to prevent possible issues later: + + ``` + config :pleroma, :instance, + quarantined_instances: ["instance.tld"] + ``` + + Is now + + + ``` + config :pleroma, :instance, + quarantined_instances: [{"instance.tld", "Reason for quarantine"}] + ``` + """ + end + + test "transforms config to tuples" do + clear_config([:instance, :quarantined_instances], [ + {"domain.com", "some reason"}, + "some.tld" + ]) + + expected_config = [{"domain.com", "some reason"}, {"some.tld", ""}] + + capture_log(fn -> DeprecationWarnings.warn() end) + + assert Config.get([:instance, :quarantined_instances]) == expected_config + end + + test "doesn't give a warning with correct config" do + clear_config([:instance, :quarantined_instances], [ + {"domain.com", "some reason"}, + {"some.tld", ""} + ]) + + assert capture_log(fn -> DeprecationWarnings.check_quarantined_instances_tuples() end) == "" + end + end + + describe "transparency_exclusions tuples" do + test "gives warning when there are still strings" do + clear_config([:mrf, :transparency_exclusions], [ + {"domain.com", "some reason"}, + "somedomain.tld" + ]) + + assert capture_log(fn -> DeprecationWarnings.check_transparency_exclusions_tuples() end) =~ + """ + !!!DEPRECATION WARNING!!! + Your config is using strings in the transparency_exclusions configuration instead of tuples. They should work for now, but you are advised to change to the new configuration to prevent possible issues later: + + ``` + config :pleroma, :mrf, + transparency_exclusions: ["instance.tld"] + ``` + + Is now + + + ``` + config :pleroma, :mrf, + transparency_exclusions: [{"instance.tld", "Reason to exlude transparency"}] + ``` + """ + end + + test "transforms config to tuples" do + clear_config([:mrf, :transparency_exclusions], [ + {"domain.com", "some reason"}, + "some.tld" + ]) + + expected_config = [{"domain.com", "some reason"}, {"some.tld", ""}] + + capture_log(fn -> DeprecationWarnings.warn() end) + + assert Config.get([:mrf, :transparency_exclusions]) == expected_config + end + + test "doesn't give a warning with correct config" do + clear_config([:mrf, :transparency_exclusions], [ + {"domain.com", "some reason"}, + {"some.tld", ""} + ]) + + assert capture_log(fn -> DeprecationWarnings.check_transparency_exclusions_tuples() end) == + "" + end + end + + test "check_old_mrf_config/0" do + clear_config([:instance, :rewrite_policy], []) + clear_config([:instance, :mrf_transparency], true) + clear_config([:instance, :mrf_transparency_exclusions], []) + + assert capture_log(fn -> DeprecationWarnings.check_old_mrf_config() end) =~ + """ + !!!DEPRECATION WARNING!!! + Your config is using old namespaces for MRF configuration. They should work for now, but you are advised to change to new namespaces to prevent possible issues later: + + * `config :pleroma, :instance, rewrite_policy` is now `config :pleroma, :mrf, policies` + * `config :pleroma, :instance, mrf_transparency` is now `config :pleroma, :mrf, transparency` + * `config :pleroma, :instance, mrf_transparency_exclusions` is now `config :pleroma, :mrf, transparency_exclusions` + """ + end + + test "move_namespace_and_warn/2" do + old_group1 = [:group, :key] + old_group2 = [:group, :key2] + old_group3 = [:group, :key3] + + new_group1 = [:another_group, :key4] + new_group2 = [:another_group, :key5] + new_group3 = [:another_group, :key6] + + clear_config(old_group1, 1) + clear_config(old_group2, 2) + clear_config(old_group3, 3) + + clear_config(new_group1) + clear_config(new_group2) + clear_config(new_group3) + + config_map = [ + {old_group1, new_group1, "\n error :key"}, + {old_group2, new_group2, "\n error :key2"}, + {old_group3, new_group3, "\n error :key3"} + ] + + assert capture_log(fn -> + DeprecationWarnings.move_namespace_and_warn( + config_map, + "Warning preface" + ) + end) =~ "Warning preface\n error :key\n error :key2\n error :key3" + + assert Config.get(new_group1) == 1 + assert Config.get(new_group2) == 2 + assert Config.get(new_group3) == 3 + end + + test "check_media_proxy_whitelist_config/0" do + clear_config([:media_proxy, :whitelist], ["https://example.com", "example2.com"]) + + assert capture_log(fn -> + DeprecationWarnings.check_media_proxy_whitelist_config() + end) =~ "Your config is using old format (only domain) for MediaProxy whitelist option" + end + + test "check_welcome_message_config/0" do + clear_config([:instance, :welcome_user_nickname], "LainChan") + + assert capture_log(fn -> + DeprecationWarnings.check_welcome_message_config() + end) =~ "Your config is using the old namespace for Welcome messages configuration." + end + + test "check_hellthread_threshold/0" do + clear_config([:mrf_hellthread, :threshold], 16) + + assert capture_log(fn -> + DeprecationWarnings.check_hellthread_threshold() + end) =~ "You are using the old configuration mechanism for the hellthread filter." + end + + test "check_activity_expiration_config/0" do + clear_config([Pleroma.ActivityExpiration], enabled: true) + + assert capture_log(fn -> + DeprecationWarnings.check_activity_expiration_config() + end) =~ "Your config is using old namespace for activity expiration configuration." + end + + test "check_uploders_s3_public_endpoint/0" do + clear_config([Pleroma.Uploaders.S3], public_endpoint: "https://fake.amazonaws.com/bucket/") + + assert capture_log(fn -> + DeprecationWarnings.check_uploders_s3_public_endpoint() + end) =~ + "Your config is using the old setting for controlling the URL of media uploaded to your S3 bucket." + end + + describe "check_gun_pool_options/0" do + test "await_up_timeout" do + config = Config.get(:connections_pool) + clear_config(:connections_pool, Keyword.put(config, :await_up_timeout, 5_000)) + + assert capture_log(fn -> + DeprecationWarnings.check_gun_pool_options() + end) =~ + "Your config is using old setting `config :pleroma, :connections_pool, await_up_timeout`." + end + + test "pool timeout" do + old_config = [ + federation: [ + size: 50, + max_waiting: 10, + timeout: 10_000 + ], + media: [ + size: 50, + max_waiting: 10, + timeout: 10_000 + ], + upload: [ + size: 25, + max_waiting: 5, + timeout: 15_000 + ], + default: [ + size: 10, + max_waiting: 2, + timeout: 5_000 + ] + ] + + clear_config(:pools, old_config) + + assert capture_log(fn -> + DeprecationWarnings.check_gun_pool_options() + end) =~ + "Your config is using old setting name `timeout` instead of `recv_timeout` in pool settings" + end + end + + test "check_old_chat_shoutbox/0" do + clear_config([:instance, :chat_limit], 1_000) + clear_config([:chat, :enabled], true) + + assert capture_log(fn -> + DeprecationWarnings.check_old_chat_shoutbox() + end) =~ + "Your config is using the old namespace for the Shoutbox configuration." + end +end diff --git a/test/config/holder_test.exs b/test/pleroma/config/holder_test.exs index abcaa27dd..ca4c38995 100644 --- a/test/config/holder_test.exs +++ b/test/pleroma/config/holder_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Config.HolderTest do diff --git a/test/config/loader_test.exs b/test/pleroma/config/loader_test.exs index 607572f4e..b34fd70da 100644 --- a/test/config/loader_test.exs +++ b/test/pleroma/config/loader_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Config.LoaderTest do diff --git a/test/pleroma/config/release_runtime_provider_test.exs b/test/pleroma/config/release_runtime_provider_test.exs new file mode 100644 index 000000000..6578d3268 --- /dev/null +++ b/test/pleroma/config/release_runtime_provider_test.exs @@ -0,0 +1,45 @@ +defmodule Pleroma.Config.ReleaseRuntimeProviderTest do + use ExUnit.Case, async: true + + alias Pleroma.Config.ReleaseRuntimeProvider + + describe "load/2" do + test "loads release defaults config and warns about non-existent runtime config" do + ExUnit.CaptureIO.capture_io(fn -> + merged = ReleaseRuntimeProvider.load([], []) + assert merged == Pleroma.Config.Holder.release_defaults() + end) =~ + "!!! Config path is not declared! Please ensure it exists and that PLEROMA_CONFIG_PATH is unset or points to an existing file" + end + + test "merged runtime config" do + merged = + ReleaseRuntimeProvider.load([], config_path: "test/fixtures/config/temp.secret.exs") + + assert merged[:pleroma][:first_setting] == [key: "value", key2: [Pleroma.Repo]] + assert merged[:pleroma][:second_setting] == [key: "value2", key2: ["Activity"]] + end + + test "merged exported config" do + ExUnit.CaptureIO.capture_io(fn -> + merged = + ReleaseRuntimeProvider.load([], + exported_config_path: "test/fixtures/config/temp.exported_from_db.secret.exs" + ) + + assert merged[:pleroma][:exported_config_merged] + end) =~ + "!!! Config path is not declared! Please ensure it exists and that PLEROMA_CONFIG_PATH is unset or points to an existing file" + end + + test "runtime config is merged with exported config" do + merged = + ReleaseRuntimeProvider.load([], + config_path: "test/fixtures/config/temp.secret.exs", + exported_config_path: "test/fixtures/config/temp.exported_from_db.secret.exs" + ) + + assert merged[:pleroma][:first_setting] == [key2: [Pleroma.Repo], key: "new value"] + end + end +end diff --git a/test/config/transfer_task_test.exs b/test/pleroma/config/transfer_task_test.exs index f53829e09..9e3f11f1a 100644 --- a/test/config/transfer_task_test.exs +++ b/test/pleroma/config/transfer_task_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Config.TransferTaskTest do @@ -82,6 +82,7 @@ defmodule Pleroma.Config.TransferTaskTest do on_exit(fn -> Restarter.Pleroma.refresh() end) end + @tag :erratic test "don't restart if no reboot time settings were changed" do clear_config(:emoji) insert(:config, key: :emoji, value: [groups: [a: 1, b: 2]]) @@ -92,23 +93,26 @@ defmodule Pleroma.Config.TransferTaskTest do ) end + @tag :erratic test "on reboot time key" do - clear_config(:chat) - insert(:config, key: :chat, value: [enabled: false]) + clear_config(:shout) + insert(:config, key: :shout, value: [enabled: false]) assert capture_log(fn -> TransferTask.start_link([]) end) =~ "pleroma restarted" end + @tag :erratic test "on reboot time subkey" do clear_config(Pleroma.Captcha) insert(:config, key: Pleroma.Captcha, value: [seconds_valid: 60]) assert capture_log(fn -> TransferTask.start_link([]) end) =~ "pleroma restarted" end + @tag :erratic test "don't restart pleroma on reboot time key and subkey if there is false flag" do - clear_config(:chat) + clear_config(:shout) clear_config(Pleroma.Captcha) - insert(:config, key: :chat, value: [enabled: false]) + insert(:config, key: :shout, value: [enabled: false]) insert(:config, key: Pleroma.Captcha, value: [seconds_valid: 60]) refute String.contains?( diff --git a/test/config/config_db_test.exs b/test/pleroma/config_db_test.exs index 3895e2cda..d42123fb4 100644 --- a/test/config/config_db_test.exs +++ b/test/pleroma/config_db_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.ConfigDBTest do diff --git a/test/config_test.exs b/test/pleroma/config_test.exs index 1556e4237..3158a2ec8 100644 --- a/test/config_test.exs +++ b/test/pleroma/config_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.ConfigTest do - use ExUnit.Case + use Pleroma.DataCase test "get/1 with an atom" do assert Pleroma.Config.get(:instance) == Application.get_env(:pleroma, :instance) @@ -30,9 +30,9 @@ defmodule Pleroma.ConfigTest do describe "nil values" do setup do - Pleroma.Config.put(:lorem, nil) - Pleroma.Config.put(:ipsum, %{dolor: [sit: nil]}) - Pleroma.Config.put(:dolor, sit: %{amet: nil}) + clear_config(:lorem, nil) + clear_config(:ipsum, %{dolor: [sit: nil]}) + clear_config(:dolor, sit: %{amet: nil}) on_exit(fn -> Enum.each(~w(lorem ipsum dolor)a, &Pleroma.Config.delete/1) end) end @@ -57,9 +57,9 @@ defmodule Pleroma.ConfigTest do end test "get/1 when value is false" do - Pleroma.Config.put([:instance, :false_test], false) - Pleroma.Config.put([:instance, :nested], []) - Pleroma.Config.put([:instance, :nested, :false_test], false) + clear_config([:instance, :false_test], false) + clear_config([:instance, :nested], []) + clear_config([:instance, :nested, :false_test], false) assert Pleroma.Config.get([:instance, :false_test]) == false assert Pleroma.Config.get([:instance, :nested, :false_test]) == false @@ -81,40 +81,40 @@ defmodule Pleroma.ConfigTest do end test "get!/1 when value is false" do - Pleroma.Config.put([:instance, :false_test], false) - Pleroma.Config.put([:instance, :nested], []) - Pleroma.Config.put([:instance, :nested, :false_test], false) + clear_config([:instance, :false_test], false) + clear_config([:instance, :nested], []) + clear_config([:instance, :nested, :false_test], false) assert Pleroma.Config.get!([:instance, :false_test]) == false assert Pleroma.Config.get!([:instance, :nested, :false_test]) == false end test "put/2 with a key" do - Pleroma.Config.put(:config_test, true) + clear_config(:config_test, true) assert Pleroma.Config.get(:config_test) == true end test "put/2 with a list of keys" do - Pleroma.Config.put([:instance, :config_test], true) - Pleroma.Config.put([:instance, :config_nested_test], []) - Pleroma.Config.put([:instance, :config_nested_test, :x], true) + clear_config([:instance, :config_test], true) + clear_config([:instance, :config_nested_test], []) + clear_config([:instance, :config_nested_test, :x], true) assert Pleroma.Config.get([:instance, :config_test]) == true assert Pleroma.Config.get([:instance, :config_nested_test, :x]) == true end test "delete/1 with a key" do - Pleroma.Config.put([:delete_me], :delete_me) + clear_config([:delete_me], :delete_me) Pleroma.Config.delete([:delete_me]) assert Pleroma.Config.get([:delete_me]) == nil end test "delete/2 with a list of keys" do - Pleroma.Config.put([:delete_me], hello: "world", world: "Hello") + clear_config([:delete_me], hello: "world", world: "Hello") Pleroma.Config.delete([:delete_me, :world]) assert Pleroma.Config.get([:delete_me]) == [hello: "world"] - Pleroma.Config.put([:delete_me, :delete_me], hello: "world", world: "Hello") + clear_config([:delete_me, :delete_me], hello: "world", world: "Hello") Pleroma.Config.delete([:delete_me, :delete_me, :world]) assert Pleroma.Config.get([:delete_me, :delete_me]) == [hello: "world"] @@ -123,8 +123,8 @@ defmodule Pleroma.ConfigTest do end test "fetch/1" do - Pleroma.Config.put([:lorem], :ipsum) - Pleroma.Config.put([:ipsum], dolor: :sit) + clear_config([:lorem], :ipsum) + clear_config([:ipsum], dolor: :sit) assert Pleroma.Config.fetch([:lorem]) == {:ok, :ipsum} assert Pleroma.Config.fetch(:lorem) == {:ok, :ipsum} diff --git a/test/conversation/participation_test.exs b/test/pleroma/conversation/participation_test.exs index 59a1b6492..a25e17c95 100644 --- a/test/conversation/participation_test.exs +++ b/test/pleroma/conversation/participation_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Conversation.ParticipationTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true import Pleroma.Factory alias Pleroma.Conversation alias Pleroma.Conversation.Participation @@ -37,9 +37,8 @@ defmodule Pleroma.Conversation.ParticipationTest do [%{read: true}] = Participation.for_user(user) [%{read: false} = participation] = Participation.for_user(other_user) - - assert User.get_cached_by_id(user.id).unread_conversation_count == 0 - assert User.get_cached_by_id(other_user.id).unread_conversation_count == 1 + assert Participation.unread_count(user) == 0 + assert Participation.unread_count(other_user) == 1 {:ok, _} = CommonAPI.post(other_user, %{ @@ -54,8 +53,8 @@ defmodule Pleroma.Conversation.ParticipationTest do [%{read: false}] = Participation.for_user(user) [%{read: true}] = Participation.for_user(other_user) - assert User.get_cached_by_id(user.id).unread_conversation_count == 1 - assert User.get_cached_by_id(other_user.id).unread_conversation_count == 0 + assert Participation.unread_count(user) == 1 + assert Participation.unread_count(other_user) == 0 end test "for a new conversation, it sets the recipents of the participation" do @@ -97,12 +96,11 @@ defmodule Pleroma.Conversation.ParticipationTest do {:ok, %Participation{} = participation} = Participation.create_for_user_and_conversation(user, conversation) + {:ok, participation} = time_travel(participation, -2) + assert participation.user_id == user.id assert participation.conversation_id == conversation.id - # Needed because updated_at is accurate down to a second - :timer.sleep(1000) - # Creating again returns the same participation {:ok, %Participation{} = participation_two} = Participation.create_for_user_and_conversation(user, conversation) @@ -177,8 +175,8 @@ defmodule Pleroma.Conversation.ParticipationTest do assert [participation_one, participation_two] = Participation.for_user(user) - object2 = Pleroma.Object.normalize(activity_two) - object3 = Pleroma.Object.normalize(activity_three) + object2 = Pleroma.Object.normalize(activity_two, fetch: false) + object3 = Pleroma.Object.normalize(activity_three, fetch: false) user = Repo.get(Pleroma.User, user.id) @@ -264,7 +262,7 @@ defmodule Pleroma.Conversation.ParticipationTest do assert [%{read: false}, %{read: false}, %{read: false}, %{read: false}] = Participation.for_user(blocker) - assert User.get_cached_by_id(blocker.id).unread_conversation_count == 4 + assert Participation.unread_count(blocker) == 4 {:ok, _user_relationship} = User.block(blocker, blocked) @@ -272,15 +270,15 @@ defmodule Pleroma.Conversation.ParticipationTest do assert [%{read: true}, %{read: true}, %{read: true}, %{read: false}] = Participation.for_user(blocker) - assert User.get_cached_by_id(blocker.id).unread_conversation_count == 1 + assert Participation.unread_count(blocker) == 1 # The conversation is not marked as read for the blocked user assert [_, _, %{read: false}] = Participation.for_user(blocked) - assert User.get_cached_by_id(blocked.id).unread_conversation_count == 1 + assert Participation.unread_count(blocker) == 1 # The conversation is not marked as read for the third user assert [%{read: false}, _, _] = Participation.for_user(third_user) - assert User.get_cached_by_id(third_user.id).unread_conversation_count == 1 + assert Participation.unread_count(third_user) == 1 end test "the new conversation with the blocked user is not marked as unread " do @@ -298,7 +296,7 @@ defmodule Pleroma.Conversation.ParticipationTest do }) assert [%{read: true}] = Participation.for_user(blocker) - assert User.get_cached_by_id(blocker.id).unread_conversation_count == 0 + assert Participation.unread_count(blocker) == 0 # When the blocked user is a recipient {:ok, _direct2} = @@ -308,10 +306,10 @@ defmodule Pleroma.Conversation.ParticipationTest do }) assert [%{read: true}, %{read: true}] = Participation.for_user(blocker) - assert User.get_cached_by_id(blocker.id).unread_conversation_count == 0 + assert Participation.unread_count(blocker) == 0 assert [%{read: false}, _] = Participation.for_user(blocked) - assert User.get_cached_by_id(blocked.id).unread_conversation_count == 1 + assert Participation.unread_count(blocked) == 1 end test "the conversation with the blocked user is not marked as unread on a reply" do @@ -327,8 +325,8 @@ defmodule Pleroma.Conversation.ParticipationTest do {:ok, _user_relationship} = User.block(blocker, blocked) assert [%{read: true}] = Participation.for_user(blocker) - assert User.get_cached_by_id(blocker.id).unread_conversation_count == 0 + assert Participation.unread_count(blocker) == 0 assert [blocked_participation] = Participation.for_user(blocked) # When it's a reply from the blocked user @@ -340,8 +338,8 @@ defmodule Pleroma.Conversation.ParticipationTest do }) assert [%{read: true}] = Participation.for_user(blocker) - assert User.get_cached_by_id(blocker.id).unread_conversation_count == 0 + assert Participation.unread_count(blocker) == 0 assert [third_user_participation] = Participation.for_user(third_user) # When it's a reply from the third user @@ -353,11 +351,24 @@ defmodule Pleroma.Conversation.ParticipationTest do }) assert [%{read: true}] = Participation.for_user(blocker) - assert User.get_cached_by_id(blocker.id).unread_conversation_count == 0 + assert Participation.unread_count(blocker) == 0 # Marked as unread for the blocked user assert [%{read: false}] = Participation.for_user(blocked) - assert User.get_cached_by_id(blocked.id).unread_conversation_count == 1 + + assert Participation.unread_count(blocked) == 1 end end + + test "deletes a conversation" do + user = insert(:user) + other_user = insert(:user) + + {:ok, _activity} = + CommonAPI.post(user, %{status: "Hey @#{other_user.nickname}.", visibility: "direct"}) + + assert [participation] = Participation.for_user(other_user) + assert {:ok, _} = Participation.delete(participation) + assert [] == Participation.for_user(other_user) + end end diff --git a/test/conversation_test.exs b/test/pleroma/conversation_test.exs index 359aa6840..1a947606d 100644 --- a/test/conversation_test.exs +++ b/test/pleroma/conversation_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.ConversationTest do @@ -48,7 +48,7 @@ defmodule Pleroma.ConversationTest do user = insert(:user) {:ok, activity} = CommonAPI.post(user, %{status: "Hey"}) - object = Pleroma.Object.normalize(activity) + object = Pleroma.Object.normalize(activity, fetch: false) context = object.data["context"] conversation = Conversation.get_for_ap_id(context) @@ -64,7 +64,7 @@ defmodule Pleroma.ConversationTest do {:ok, activity} = CommonAPI.post(har, %{status: "Hey @#{jafnhar.nickname}", visibility: "direct"}) - object = Pleroma.Object.normalize(activity) + object = Pleroma.Object.normalize(activity, fetch: false) context = object.data["context"] conversation = @@ -86,7 +86,7 @@ defmodule Pleroma.ConversationTest do in_reply_to_status_id: activity.id }) - object = Pleroma.Object.normalize(activity) + object = Pleroma.Object.normalize(activity, fetch: false) context = object.data["context"] conversation_two = @@ -110,7 +110,7 @@ defmodule Pleroma.ConversationTest do in_reply_to_status_id: activity.id }) - object = Pleroma.Object.normalize(activity) + object = Pleroma.Object.normalize(activity, fetch: false) context = object.data["context"] conversation_three = diff --git a/test/docs/generator_test.exs b/test/pleroma/docs/generator_test.exs index b32918a69..8574c1d5e 100644 --- a/test/docs/generator_test.exs +++ b/test/pleroma/docs/generator_test.exs @@ -1,3 +1,7 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + defmodule Pleroma.Docs.GeneratorTest do use ExUnit.Case, async: true alias Pleroma.Docs.Generator @@ -19,7 +23,7 @@ defmodule Pleroma.Docs.GeneratorTest do key: :filters, type: {:list, :module}, description: "", - suggestions: {:list_behaviour_implementations, Pleroma.Web.ActivityPub.MRF} + suggestions: {:list_behaviour_implementations, Pleroma.Web.ActivityPub.MRF.Policy} }, %{ key: Pleroma.Upload, diff --git a/test/web/activity_pub/object_validators/types/date_time_test.exs b/test/pleroma/ecto_type/activity_pub/object_validators/date_time_test.exs index 43be8e936..259fd6a5f 100644 --- a/test/web/activity_pub/object_validators/types/date_time_test.exs +++ b/test/pleroma/ecto_type/activity_pub/object_validators/date_time_test.exs @@ -1,6 +1,10 @@ -defmodule Pleroma.Web.ActivityPub.ObjectValidators.Types.DateTimeTest do +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.DateTimeTest do alias Pleroma.EctoType.ActivityPub.ObjectValidators.DateTime - use Pleroma.DataCase + use Pleroma.DataCase, async: true test "it validates an xsd:Datetime" do valid_strings = [ diff --git a/test/web/activity_pub/object_validators/types/object_id_test.exs b/test/pleroma/ecto_type/activity_pub/object_validators/object_id_test.exs index e0ab76379..1a4c2dfcb 100644 --- a/test/web/activity_pub/object_validators/types/object_id_test.exs +++ b/test/pleroma/ecto_type/activity_pub/object_validators/object_id_test.exs @@ -1,10 +1,10 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.Web.ObjectValidators.Types.ObjectIDTest do +defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.ObjectIDTest do alias Pleroma.EctoType.ActivityPub.ObjectValidators.ObjectID - use Pleroma.DataCase + use Pleroma.DataCase, async: true @uris [ "http://lain.com/users/lain", diff --git a/test/web/activity_pub/object_validators/types/recipients_test.exs b/test/pleroma/ecto_type/activity_pub/object_validators/recipients_test.exs index 053916bdd..4cdafa898 100644 --- a/test/web/activity_pub/object_validators/types/recipients_test.exs +++ b/test/pleroma/ecto_type/activity_pub/object_validators/recipients_test.exs @@ -1,11 +1,15 @@ -defmodule Pleroma.Web.ObjectValidators.Types.RecipientsTest do +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.RecipientsTest do alias Pleroma.EctoType.ActivityPub.ObjectValidators.Recipients - use Pleroma.DataCase + use Pleroma.DataCase, async: true - test "it asserts that all elements of the list are object ids" do + test "it only keeps elements that are valid object ids" do list = ["https://lain.com/users/lain", "invalid"] - assert :error == Recipients.cast(list) + assert {:ok, ["https://lain.com/users/lain"]} == Recipients.cast(list) end test "it works with a list" do diff --git a/test/web/activity_pub/object_validators/types/safe_text_test.exs b/test/pleroma/ecto_type/activity_pub/object_validators/safe_text_test.exs index 9c08606f6..7002eca30 100644 --- a/test/web/activity_pub/object_validators/types/safe_text_test.exs +++ b/test/pleroma/ecto_type/activity_pub/object_validators/safe_text_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.Web.ActivityPub.ObjectValidators.Types.SafeTextTest do - use Pleroma.DataCase +defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.SafeTextTest do + use Pleroma.DataCase, async: true alias Pleroma.EctoType.ActivityPub.ObjectValidators.SafeText diff --git a/test/emails/admin_email_test.exs b/test/pleroma/emails/admin_email_test.exs index e24231e27..e65752c23 100644 --- a/test/emails/admin_email_test.exs +++ b/test/pleroma/emails/admin_email_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Emails.AdminEmailTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true import Pleroma.Factory alias Pleroma.Emails.AdminEmail @@ -19,19 +19,15 @@ defmodule Pleroma.Emails.AdminEmailTest do AdminEmail.report(to_user, reporter, account, [%{name: "Test", id: "12"}], "Test comment") status_url = Helpers.o_status_url(Pleroma.Web.Endpoint, :notice, "12") - reporter_url = Helpers.user_feed_url(Pleroma.Web.Endpoint, :feed_redirect, reporter.id) - account_url = Helpers.user_feed_url(Pleroma.Web.Endpoint, :feed_redirect, account.id) + reporter_url = reporter.ap_id + account_url = account.ap_id assert res.to == [{to_user.name, to_user.email}] assert res.from == {config[:name], config[:notify_email]} assert res.subject == "#{config[:name]} Report" assert res.html_body == - "<p>Reported by: <a href=\"#{reporter_url}\">#{reporter.nickname}</a></p>\n<p>Reported Account: <a href=\"#{ - account_url - }\">#{account.nickname}</a></p>\n<p>Comment: Test comment\n<p> Statuses:\n <ul>\n <li><a href=\"#{ - status_url - }\">#{status_url}</li>\n </ul>\n</p>\n\n<p>\n<a href=\"http://localhost:4001/pleroma/admin/#/reports/index\">View Reports in AdminFE</a>\n" + "<p>Reported by: <a href=\"#{reporter_url}\">#{reporter.nickname}</a></p>\n<p>Reported Account: <a href=\"#{account_url}\">#{account.nickname}</a></p>\n<p>Comment: Test comment\n<p> Statuses:\n <ul>\n <li><a href=\"#{status_url}\">#{status_url}</li>\n </ul>\n</p>\n\n<p>\n<a href=\"http://localhost:4001/pleroma/admin/#/reports/index\">View Reports in AdminFE</a>\n" end test "it works when the reporter is a remote user without email" do @@ -54,7 +50,7 @@ defmodule Pleroma.Emails.AdminEmailTest do res = AdminEmail.new_unapproved_registration(to_user, account) - account_url = Helpers.user_feed_url(Pleroma.Web.Endpoint, :feed_redirect, account.id) + account_url = account.ap_id assert res.to == [{to_user.name, to_user.email}] assert res.from == {config[:name], config[:notify_email]} @@ -63,7 +59,7 @@ defmodule Pleroma.Emails.AdminEmailTest do assert res.html_body == """ <p>New account for review: <a href="#{account_url}">@#{account.nickname}</a></p> <blockquote>Plz let me in</blockquote> - <a href="http://localhost:4001/pleroma/admin">Visit AdminFE</a> + <a href="http://localhost:4001/pleroma/admin/#/users/#{account.id}/">Visit AdminFE</a> """ end end diff --git a/test/emails/mailer_test.exs b/test/pleroma/emails/mailer_test.exs index 9e232d2a0..a8e1553e5 100644 --- a/test/emails/mailer_test.exs +++ b/test/pleroma/emails/mailer_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Emails.MailerTest do diff --git a/test/emails/user_email_test.exs b/test/pleroma/emails/user_email_test.exs index a75623bb4..21fd06ea6 100644 --- a/test/emails/user_email_test.exs +++ b/test/pleroma/emails/user_email_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Emails.UserEmailTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true alias Pleroma.Emails.UserEmail alias Pleroma.Web.Endpoint @@ -45,4 +45,15 @@ defmodule Pleroma.Emails.UserEmailTest do assert email.html_body =~ Router.Helpers.confirm_email_url(Endpoint, :confirm_email, user.id, "conf-token") end + + test "build approval pending email" do + config = Pleroma.Config.get(:instance) + user = insert(:user) + email = UserEmail.approval_pending_email(user) + + assert email.from == {config[:name], config[:notify_email]} + assert email.to == [{user.name, user.email}] + assert email.subject == "Your account is awaiting approval" + assert email.html_body =~ "Awaiting Approval" + end end diff --git a/test/emoji/formatter_test.exs b/test/pleroma/emoji/formatter_test.exs index 12af6cd8b..3942f609f 100644 --- a/test/emoji/formatter_test.exs +++ b/test/pleroma/emoji/formatter_test.exs @@ -1,10 +1,10 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Emoji.FormatterTest do alias Pleroma.Emoji.Formatter - use Pleroma.DataCase + use Pleroma.DataCase, async: true describe "emojify" do test "it adds cool emoji" do diff --git a/test/emoji/loader_test.exs b/test/pleroma/emoji/loader_test.exs index 804039e7e..de89e3bc4 100644 --- a/test/emoji/loader_test.exs +++ b/test/pleroma/emoji/loader_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Emoji.LoaderTest do diff --git a/test/pleroma/emoji/pack_test.exs b/test/pleroma/emoji/pack_test.exs new file mode 100644 index 000000000..ac7535412 --- /dev/null +++ b/test/pleroma/emoji/pack_test.exs @@ -0,0 +1,93 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Emoji.PackTest do + use Pleroma.DataCase + alias Pleroma.Emoji.Pack + + @emoji_path Path.join( + Pleroma.Config.get!([:instance, :static_dir]), + "emoji" + ) + + setup do + pack_path = Path.join(@emoji_path, "dump_pack") + File.mkdir(pack_path) + + File.write!(Path.join(pack_path, "pack.json"), """ + { + "files": { }, + "pack": { + "description": "Dump pack", "homepage": "https://pleroma.social", + "license": "Test license", "share-files": true + }} + """) + + {:ok, pack} = Pleroma.Emoji.Pack.load_pack("dump_pack") + + on_exit(fn -> + File.rm_rf!(pack_path) + end) + + {:ok, pack: pack} + end + + describe "add_file/4" do + test "add emojies from zip file", %{pack: pack} do + file = %Plug.Upload{ + content_type: "application/zip", + filename: "emojis.zip", + path: Path.absname("test/fixtures/emojis.zip") + } + + {:ok, updated_pack} = Pack.add_file(pack, nil, nil, file) + + assert updated_pack.files == %{ + "a_trusted_friend-128" => "128px/a_trusted_friend-128.png", + "auroraborealis" => "auroraborealis.png", + "baby_in_a_box" => "1000px/baby_in_a_box.png", + "bear" => "1000px/bear.png", + "bear-128" => "128px/bear-128.png" + } + + assert updated_pack.files_count == 5 + end + end + + test "returns error when zip file is bad", %{pack: pack} do + file = %Plug.Upload{ + content_type: "application/zip", + filename: "emojis.zip", + path: Path.absname("test/instance_static/emoji/test_pack/blank.png") + } + + assert Pack.add_file(pack, nil, nil, file) == {:error, :einval} + end + + test "returns pack when zip file is empty", %{pack: pack} do + file = %Plug.Upload{ + content_type: "application/zip", + filename: "emojis.zip", + path: Path.absname("test/fixtures/empty.zip") + } + + {:ok, updated_pack} = Pack.add_file(pack, nil, nil, file) + assert updated_pack == pack + end + + test "add emoji file", %{pack: pack} do + file = %Plug.Upload{ + filename: "blank.png", + path: "#{@emoji_path}/test_pack/blank.png" + } + + {:ok, updated_pack} = Pack.add_file(pack, "test_blank", "test_blank.png", file) + + assert updated_pack.files == %{ + "test_blank" => "test_blank.png" + } + + assert updated_pack.files_count == 1 + end +end diff --git a/test/emoji_test.exs b/test/pleroma/emoji_test.exs index b36047578..027a8132f 100644 --- a/test/emoji_test.exs +++ b/test/pleroma/emoji_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.EmojiTest do @@ -9,8 +9,22 @@ defmodule Pleroma.EmojiTest do describe "is_unicode_emoji?/1" do test "tells if a string is an unicode emoji" do refute Emoji.is_unicode_emoji?("X") - assert Emoji.is_unicode_emoji?("☂") + refute Emoji.is_unicode_emoji?("ね") + + # Only accept fully-qualified (RGI) emoji + # See http://www.unicode.org/reports/tr51/ + refute Emoji.is_unicode_emoji?("❤") + refute Emoji.is_unicode_emoji?("☂") + assert Emoji.is_unicode_emoji?("🥺") + assert Emoji.is_unicode_emoji?("🤰") + assert Emoji.is_unicode_emoji?("❤️") + assert Emoji.is_unicode_emoji?("🏳️⚧️") + + # Additionally, we accept regional indicators. + assert Emoji.is_unicode_emoji?("🇵") + assert Emoji.is_unicode_emoji?("🇴") + assert Emoji.is_unicode_emoji?("🇬") end end diff --git a/test/pleroma/filter_test.exs b/test/pleroma/filter_test.exs new file mode 100644 index 000000000..19ad6b8c0 --- /dev/null +++ b/test/pleroma/filter_test.exs @@ -0,0 +1,193 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.FilterTest do + use Pleroma.DataCase, async: true + + import Pleroma.Factory + + alias Oban.Job + alias Pleroma.Filter + + setup do + [user: insert(:user)] + end + + describe "creating filters" do + test "creation validation error", %{user: user} do + attrs = %{ + user_id: user.id, + expires_in: 60 + } + + {:error, _} = Filter.create(attrs) + + assert Repo.all(Job) == [] + end + + test "use passed expires_at instead expires_in", %{user: user} do + now = NaiveDateTime.utc_now() + + attrs = %{ + user_id: user.id, + expires_at: now, + phrase: "knights", + context: ["home"], + expires_in: 600 + } + + {:ok, %Filter{} = filter} = Filter.create(attrs) + + result = Filter.get(filter.filter_id, user) + assert result.expires_at == NaiveDateTime.truncate(now, :second) + + [job] = Repo.all(Job) + + assert DateTime.truncate(job.scheduled_at, :second) == + now |> NaiveDateTime.truncate(:second) |> DateTime.from_naive!("Etc/UTC") + end + + test "creating one filter", %{user: user} do + attrs = %{ + user_id: user.id, + filter_id: 42, + phrase: "knights", + context: ["home"] + } + + {:ok, %Filter{} = filter} = Filter.create(attrs) + result = Filter.get(filter.filter_id, user) + assert attrs.phrase == result.phrase + end + + test "creating with expired_at", %{user: user} do + attrs = %{ + user_id: user.id, + filter_id: 42, + phrase: "knights", + context: ["home"], + expires_in: 60 + } + + {:ok, %Filter{} = filter} = Filter.create(attrs) + result = Filter.get(filter.filter_id, user) + assert attrs.phrase == result.phrase + + assert [_] = Repo.all(Job) + end + + test "creating one filter without a pre-defined filter_id", %{user: user} do + attrs = %{ + user_id: user.id, + phrase: "knights", + context: ["home"] + } + + {:ok, %Filter{} = filter} = Filter.create(attrs) + # Should start at 1 + assert filter.filter_id == 1 + end + + test "creating additional filters uses previous highest filter_id + 1", %{user: user} do + filter1 = insert(:filter, user: user) + + attrs = %{ + user_id: user.id, + # No filter_id + phrase: "who", + context: ["home"] + } + + {:ok, %Filter{} = filter2} = Filter.create(attrs) + assert filter2.filter_id == filter1.filter_id + 1 + end + + test "filter_id is unique per user", %{user: user_one} do + user_two = insert(:user) + + attrs1 = %{ + user_id: user_one.id, + phrase: "knights", + context: ["home"] + } + + {:ok, %Filter{} = filter_one} = Filter.create(attrs1) + + attrs2 = %{ + user_id: user_two.id, + phrase: "who", + context: ["home"] + } + + {:ok, %Filter{} = filter_two} = Filter.create(attrs2) + + assert filter_one.filter_id == 1 + assert filter_two.filter_id == 1 + + result_one = Filter.get(filter_one.filter_id, user_one) + assert result_one.phrase == filter_one.phrase + + result_two = Filter.get(filter_two.filter_id, user_two) + assert result_two.phrase == filter_two.phrase + end + end + + test "deleting a filter", %{user: user} do + filter = insert(:filter, user: user) + + assert Repo.get(Filter, filter.id) + {:ok, filter} = Filter.delete(filter) + refute Repo.get(Filter, filter.id) + end + + test "deleting a filter with expires_at is removing Oban job too", %{user: user} do + attrs = %{ + user_id: user.id, + phrase: "cofe", + context: ["home"], + expires_in: 600 + } + + {:ok, filter} = Filter.create(attrs) + assert %Job{id: job_id} = Pleroma.Workers.PurgeExpiredFilter.get_expiration(filter.id) + {:ok, _} = Filter.delete(filter) + + assert Repo.get(Job, job_id) == nil + end + + test "getting all filters by an user", %{user: user} do + filter1 = insert(:filter, user: user) + filter2 = insert(:filter, user: user) + + filter_ids = user |> Filter.get_filters() |> collect_ids() + + assert filter1.id in filter_ids + assert filter2.id in filter_ids + end + + test "updating a filter", %{user: user} do + filter = insert(:filter, user: user) + + changes = %{ + phrase: "who", + context: ["home", "timeline"] + } + + {:ok, updated_filter} = Filter.update(filter, changes) + + assert filter != updated_filter + assert updated_filter.phrase == changes.phrase + assert updated_filter.context == changes.context + end + + test "updating with error", %{user: user} do + filter = insert(:filter, user: user) + + changes = %{ + phrase: nil + } + + {:error, _} = Filter.update(filter, changes) + end +end diff --git a/test/following_relationship_test.exs b/test/pleroma/following_relationship_test.exs index 17a468abb..37452996b 100644 --- a/test/following_relationship_test.exs +++ b/test/pleroma/following_relationship_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.FollowingRelationshipTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true alias Pleroma.FollowingRelationship alias Pleroma.Web.ActivityPub.InternalFetchActor diff --git a/test/formatter_test.exs b/test/pleroma/formatter_test.exs index f066bd50a..b0f9f41b1 100644 --- a/test/formatter_test.exs +++ b/test/pleroma/formatter_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.FormatterTest do @@ -151,13 +151,7 @@ defmodule Pleroma.FormatterTest do assert length(mentions) == 3 expected_text = - ~s(<span class="h-card"><a class="u-url mention" data-user="#{gsimg.id}" href="#{ - gsimg.ap_id - }" rel="ugc">@<span>gsimg</span></a></span> According to <span class="h-card"><a class="u-url mention" data-user="#{ - archaeme.id - }" href="#{"https://archeme/@archa_eme_"}" rel="ugc">@<span>archa_eme_</span></a></span>, that is @daggsy. Also hello <span class="h-card"><a class="u-url mention" data-user="#{ - archaeme_remote.id - }" href="#{archaeme_remote.ap_id}" rel="ugc">@<span>archaeme</span></a></span>) + ~s(<span class="h-card"><a class="u-url mention" data-user="#{gsimg.id}" href="#{gsimg.ap_id}" rel="ugc">@<span>gsimg</span></a></span> According to <span class="h-card"><a class="u-url mention" data-user="#{archaeme.id}" href="#{"https://archeme/@archa_eme_"}" rel="ugc">@<span>archa_eme_</span></a></span>, that is @daggsy. Also hello <span class="h-card"><a class="u-url mention" data-user="#{archaeme_remote.id}" href="#{archaeme_remote.ap_id}" rel="ugc">@<span>archaeme</span></a></span>) assert expected_text == text end @@ -172,9 +166,7 @@ defmodule Pleroma.FormatterTest do assert length(mentions) == 1 expected_text = - ~s(<span class="h-card"><a class="u-url mention" data-user="#{mike.id}" href="#{ - mike.ap_id - }" rel="ugc">@<span>mike</span></a></span> test) + ~s(<span class="h-card"><a class="u-url mention" data-user="#{mike.id}" href="#{mike.ap_id}" rel="ugc">@<span>mike</span></a></span> test) assert expected_text == text end @@ -210,13 +202,7 @@ defmodule Pleroma.FormatterTest do assert mentions == [{"@#{user.nickname}", user}, {"@#{other_user.nickname}", other_user}] assert expected_text == - ~s(<span class="h-card"><a class="u-url mention" data-user="#{user.id}" href="#{ - user.ap_id - }" rel="ugc">@<span>#{user.nickname}</span></a></span> <span class="h-card"><a class="u-url mention" data-user="#{ - other_user.id - }" href="#{other_user.ap_id}" rel="ugc">@<span>#{other_user.nickname}</span></a></span> hey dudes i hate <span class="h-card"><a class="u-url mention" data-user="#{ - third_user.id - }" href="#{third_user.ap_id}" rel="ugc">@<span>#{third_user.nickname}</span></a></span>) + ~s(<span class="h-card"><a class="u-url mention" data-user="#{user.id}" href="#{user.ap_id}" rel="ugc">@<span>#{user.nickname}</span></a></span> <span class="h-card"><a class="u-url mention" data-user="#{other_user.id}" href="#{other_user.ap_id}" rel="ugc">@<span>#{other_user.nickname}</span></a></span> hey dudes i hate <span class="h-card"><a class="u-url mention" data-user="#{third_user.id}" href="#{third_user.ap_id}" rel="ugc">@<span>#{third_user.nickname}</span></a></span>) end test "given the 'safe_mention' option, it will still work without any mention" do @@ -241,16 +227,14 @@ defmodule Pleroma.FormatterTest do "@@gsimg According to @archaeme, that is @daggsy. Also hello @archaeme@archae.me and @o and @@@jimm" o = insert(:user, %{nickname: "o"}) - jimm = insert(:user, %{nickname: "jimm"}) - gsimg = insert(:user, %{nickname: "gsimg"}) + _jimm = insert(:user, %{nickname: "jimm"}) + _gsimg = insert(:user, %{nickname: "gsimg"}) archaeme = insert(:user, %{nickname: "archaeme"}) archaeme_remote = insert(:user, %{nickname: "archaeme@archae.me"}) expected_mentions = [ {"@archaeme", archaeme}, {"@archaeme@archae.me", archaeme_remote}, - {"@gsimg", gsimg}, - {"@jimm", jimm}, {"@o", o} ] diff --git a/test/pleroma/frontend_test.exs b/test/pleroma/frontend_test.exs new file mode 100644 index 000000000..1b50a031d --- /dev/null +++ b/test/pleroma/frontend_test.exs @@ -0,0 +1,72 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.FrontendTest do + use Pleroma.DataCase + alias Pleroma.Frontend + + @dir "test/frontend_static_test" + + setup do + File.mkdir_p!(@dir) + clear_config([:instance, :static_dir], @dir) + + on_exit(fn -> + File.rm_rf(@dir) + end) + end + + test "it downloads and unzips a known frontend" do + clear_config([:frontends, :available], %{ + "pleroma" => %{ + "ref" => "fantasy", + "name" => "pleroma", + "build_url" => "http://gensokyo.2hu/builds/${ref}" + } + }) + + Tesla.Mock.mock(fn %{url: "http://gensokyo.2hu/builds/fantasy"} -> + %Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/frontend_dist.zip")} + end) + + Frontend.install("pleroma") + + assert File.exists?(Path.join([@dir, "frontends", "pleroma", "fantasy", "test.txt"])) + end + + test "it also works given a file" do + clear_config([:frontends, :available], %{ + "pleroma" => %{ + "ref" => "fantasy", + "name" => "pleroma", + "build_dir" => "" + } + }) + + folder = Path.join([@dir, "frontends", "pleroma", "fantasy"]) + previously_existing = Path.join([folder, "temp"]) + File.mkdir_p!(folder) + File.write!(previously_existing, "yey") + assert File.exists?(previously_existing) + + Frontend.install("pleroma", file: "test/fixtures/tesla_mock/frontend.zip") + + assert File.exists?(Path.join([folder, "test.txt"])) + refute File.exists?(previously_existing) + end + + test "it downloads and unzips unknown frontends" do + Tesla.Mock.mock(fn %{url: "http://gensokyo.2hu/madeup.zip"} -> + %Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/frontend.zip")} + end) + + Frontend.install("unknown", + ref: "baka", + build_url: "http://gensokyo.2hu/madeup.zip", + build_dir: "" + ) + + assert File.exists?(Path.join([@dir, "frontends", "unknown", "baka", "test.txt"])) + end +end diff --git a/test/gun/conneciton_pool_test.exs b/test/pleroma/gun/connection_pool_test.exs index aea908fac..51637f541 100644 --- a/test/gun/conneciton_pool_test.exs +++ b/test/pleroma/gun/connection_pool_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Gun.ConnectionPoolTest do @@ -7,7 +7,6 @@ defmodule Pleroma.Gun.ConnectionPoolTest do import Mox import ExUnit.CaptureLog - alias Pleroma.Config alias Pleroma.Gun.ConnectionPool defp gun_mock(_) do @@ -19,7 +18,6 @@ defmodule Pleroma.Gun.ConnectionPoolTest do :ok end - setup :set_mox_from_context setup :gun_mock test "gives the same connection to 2 concurrent requests" do @@ -48,9 +46,10 @@ defmodule Pleroma.Gun.ConnectionPoolTest do end end + @tag :erratic test "connection limit is respected with concurrent requests" do clear_config([:connections_pool, :max_connections]) do - Config.put([:connections_pool, :max_connections], 1) + clear_config([:connections_pool, :max_connections], 1) # The supervisor needs a reboot to apply the new config setting Process.exit(Process.whereis(Pleroma.Gun.ConnectionPool.WorkerSupervisor), :kill) diff --git a/test/pleroma/hashtag_test.exs b/test/pleroma/hashtag_test.exs new file mode 100644 index 000000000..0264dea0b --- /dev/null +++ b/test/pleroma/hashtag_test.exs @@ -0,0 +1,17 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.HashtagTest do + use Pleroma.DataCase + + alias Pleroma.Hashtag + + describe "changeset validations" do + test "ensure non-blank :name" do + changeset = Hashtag.changeset(%Hashtag{}, %{name: ""}) + + assert {:name, {"can't be blank", [validation: :required]}} in changeset.errors + end + end +end diff --git a/test/healthcheck_test.exs b/test/pleroma/healthcheck_test.exs index e341e6983..469e5b397 100644 --- a/test/healthcheck_test.exs +++ b/test/pleroma/healthcheck_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.HealthcheckTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true alias Pleroma.Healthcheck test "system_info/0" do diff --git a/test/html_test.exs b/test/pleroma/html_test.exs index 7d3756884..fe1a1ed57 100644 --- a/test/html_test.exs +++ b/test/pleroma/html_test.exs @@ -1,12 +1,12 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.HTMLTest do alias Pleroma.HTML alias Pleroma.Object alias Pleroma.Web.CommonAPI - use Pleroma.DataCase + use Pleroma.DataCase, async: true import Pleroma.Factory @@ -175,7 +175,7 @@ defmodule Pleroma.HTMLTest do "I think I just found the best github repo https://github.com/komeiji-satori/Dress" }) - object = Object.normalize(activity) + object = Object.normalize(activity, fetch: false) {:ok, url} = HTML.extract_first_external_url_from_object(object) assert url == "https://github.com/komeiji-satori/Dress" end @@ -190,7 +190,7 @@ defmodule Pleroma.HTMLTest do "@#{other_user.nickname} install misskey! https://github.com/syuilo/misskey/blob/develop/docs/setup.en.md" }) - object = Object.normalize(activity) + object = Object.normalize(activity, fetch: false) {:ok, url} = HTML.extract_first_external_url_from_object(object) assert url == "https://github.com/syuilo/misskey/blob/develop/docs/setup.en.md" @@ -206,7 +206,7 @@ defmodule Pleroma.HTMLTest do status: "#cofe https://www.pixiv.net/member_illust.php?mode=medium&illust_id=72255140" }) - object = Object.normalize(activity) + object = Object.normalize(activity, fetch: false) {:ok, url} = HTML.extract_first_external_url_from_object(object) assert url == "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=72255140" @@ -222,7 +222,7 @@ defmodule Pleroma.HTMLTest do content_type: "text/html" }) - object = Object.normalize(activity) + object = Object.normalize(activity, fetch: false) {:ok, url} = HTML.extract_first_external_url_from_object(object) assert url == "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=72255140" @@ -233,7 +233,7 @@ defmodule Pleroma.HTMLTest do {:ok, activity} = CommonAPI.post(user, %{status: "\"http://cofe.com/?boomer=ok&foo=bar\""}) - object = Object.normalize(activity) + object = Object.normalize(activity, fetch: false) assert {:ok, nil} = HTML.extract_first_external_url_from_object(object) end @@ -247,7 +247,7 @@ defmodule Pleroma.HTMLTest do "<a href=\"https://pleroma.gov/media/d24caa3a498e21e0298377a9ca0149a4f4f8b767178aacf837542282e2d94fb1.png?name=image.png\" class=\"attachment\">image.png</a>" }) - object = Object.normalize(activity) + object = Object.normalize(activity, fetch: false) assert {:ok, nil} = HTML.extract_first_external_url_from_object(object) end diff --git a/test/http/adapter_helper/gun_test.exs b/test/pleroma/http/adapter_helper/gun_test.exs index 80589c73d..cfb68557d 100644 --- a/test/http/adapter_helper/gun_test.exs +++ b/test/pleroma/http/adapter_helper/gun_test.exs @@ -1,14 +1,13 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.HTTP.AdapterHelper.GunTest do - use ExUnit.Case, async: true + use ExUnit.Case use Pleroma.Tests.Helpers import Mox - alias Pleroma.Config alias Pleroma.HTTP.AdapterHelper.Gun setup :verify_on_exit! @@ -52,9 +51,7 @@ defmodule Pleroma.HTTP.AdapterHelper.GunTest do end test "parses string proxy host & port" do - proxy = Config.get([:http, :proxy_url]) - Config.put([:http, :proxy_url], "localhost:8123") - on_exit(fn -> Config.put([:http, :proxy_url], proxy) end) + clear_config([:http, :proxy_url], "localhost:8123") uri = URI.parse("https://some-domain.com") opts = Gun.options([receive_conn: false], uri) @@ -62,9 +59,7 @@ defmodule Pleroma.HTTP.AdapterHelper.GunTest do end test "parses tuple proxy scheme host and port" do - proxy = Config.get([:http, :proxy_url]) - Config.put([:http, :proxy_url], {:socks, 'localhost', 1234}) - on_exit(fn -> Config.put([:http, :proxy_url], proxy) end) + clear_config([:http, :proxy_url], {:socks, 'localhost', 1234}) uri = URI.parse("https://some-domain.com") opts = Gun.options([receive_conn: false], uri) @@ -72,9 +67,7 @@ defmodule Pleroma.HTTP.AdapterHelper.GunTest do end test "passed opts have more weight than defaults" do - proxy = Config.get([:http, :proxy_url]) - Config.put([:http, :proxy_url], {:socks5, 'localhost', 1234}) - on_exit(fn -> Config.put([:http, :proxy_url], proxy) end) + clear_config([:http, :proxy_url], {:socks5, 'localhost', 1234}) uri = URI.parse("https://some-domain.com") opts = Gun.options([receive_conn: false, proxy: {'example.com', 4321}], uri) diff --git a/test/http/adapter_helper/hackney_test.exs b/test/pleroma/http/adapter_helper/hackney_test.exs index f2361ff0b..85150a65c 100644 --- a/test/http/adapter_helper/hackney_test.exs +++ b/test/pleroma/http/adapter_helper/hackney_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.HTTP.AdapterHelper.HackneyTest do diff --git a/test/http/adapter_helper_test.exs b/test/pleroma/http/adapter_helper_test.exs index 24d501ad5..3c8c89164 100644 --- a/test/http/adapter_helper_test.exs +++ b/test/pleroma/http/adapter_helper_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.HTTP.AdapterHelperTest do diff --git a/test/http/ex_aws_test.exs b/test/pleroma/http/ex_aws_test.exs index d0b00ca26..4cbc440bd 100644 --- a/test/http/ex_aws_test.exs +++ b/test/pleroma/http/ex_aws_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.HTTP.ExAwsTest do diff --git a/test/http/request_builder_test.exs b/test/pleroma/http/request_builder_test.exs index fab909905..433beaac1 100644 --- a/test/http/request_builder_test.exs +++ b/test/pleroma/http/request_builder_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.HTTP.RequestBuilderTest do @@ -34,24 +34,32 @@ defmodule Pleroma.HTTP.RequestBuilderTest do describe "add_param/4" do test "add file parameter" do - %Request{ - body: %Tesla.Multipart{ - boundary: _, - content_type_params: [], - parts: [ - %Tesla.Multipart.Part{ - body: %File.Stream{ - line_or_bytes: 2048, - modes: [:raw, :read_ahead, :read, :binary], - path: "some-path/filename.png", - raw: true - }, - dispositions: [name: "filename.png", filename: "filename.png"], - headers: [] - } - ] - } - } = RequestBuilder.add_param(%Request{}, :file, "filename.png", "some-path/filename.png") + assert match?( + %Request{ + body: %Tesla.Multipart{ + boundary: _, + content_type_params: [], + parts: [ + %Tesla.Multipart.Part{ + body: %File.Stream{ + line_or_bytes: 2048, + modes: [:raw, :read_ahead, :binary], + path: "some-path/filename.png", + raw: true + }, + dispositions: [name: "filename.png", filename: "filename.png"], + headers: [] + } + ] + } + }, + RequestBuilder.add_param( + %Request{}, + :file, + "filename.png", + "some-path/filename.png" + ) + ) end test "add key to body" do diff --git a/test/http/tzdata_test.exs b/test/pleroma/http/tzdata_test.exs index 3e605d33b..1161bfaef 100644 --- a/test/http/tzdata_test.exs +++ b/test/pleroma/http/tzdata_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.HTTP.TzdataTest do diff --git a/test/http_test.exs b/test/pleroma/http_test.exs index d394bb942..e6a6d31b3 100644 --- a/test/http_test.exs +++ b/test/pleroma/http_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.HTTPTest do diff --git a/test/web/instances/instance_test.exs b/test/pleroma/instances/instance_test.exs index dc6ace843..e49922724 100644 --- a/test/web/instances/instance_test.exs +++ b/test/pleroma/instances/instance_test.exs @@ -1,10 +1,13 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Instances.InstanceTest do + alias Pleroma.Instances alias Pleroma.Instances.Instance alias Pleroma.Repo + alias Pleroma.Tests.ObanHelpers + alias Pleroma.Web.CommonAPI use Pleroma.DataCase @@ -99,35 +102,91 @@ defmodule Pleroma.Instances.InstanceTest do end end - test "Scrapes favicon URLs" do - Tesla.Mock.mock(fn %{url: "https://favicon.example.org/"} -> - %Tesla.Env{ - status: 200, - body: ~s[<html><head><link rel="icon" href="/favicon.png"></head></html>] - } - end) + describe "get_or_update_favicon/1" do + test "Scrapes favicon URLs" do + Tesla.Mock.mock(fn %{url: "https://favicon.example.org/"} -> + %Tesla.Env{ + status: 200, + body: ~s[<html><head><link rel="icon" href="/favicon.png"></head></html>] + } + end) + + assert "https://favicon.example.org/favicon.png" == + Instance.get_or_update_favicon(URI.parse("https://favicon.example.org/")) + end + + test "Returns nil on too long favicon URLs" do + long_favicon_url = + "https://Lorem.ipsum.dolor.sit.amet/consecteturadipiscingelit/Praesentpharetrapurusutaliquamtempus/Mauriseulaoreetarcu/atfacilisisorci/Nullamporttitor/nequesedfeugiatmollis/dolormagnaefficiturlorem/nonpretiumsapienorcieurisus/Nullamveleratsem/Maecenassedaccumsanexnam/favicon.png" + + Tesla.Mock.mock(fn %{url: "https://long-favicon.example.org/"} -> + %Tesla.Env{ + status: 200, + body: + ~s[<html><head><link rel="icon" href="] <> long_favicon_url <> ~s["></head></html>] + } + end) + + assert capture_log(fn -> + assert nil == + Instance.get_or_update_favicon( + URI.parse("https://long-favicon.example.org/") + ) + end) =~ + "Instance.get_or_update_favicon(\"long-favicon.example.org\") error: %Postgrex.Error{" + end - assert "https://favicon.example.org/favicon.png" == - Instance.get_or_update_favicon(URI.parse("https://favicon.example.org/")) + test "Handles not getting a favicon URL properly" do + Tesla.Mock.mock(fn %{url: "https://no-favicon.example.org/"} -> + %Tesla.Env{ + status: 200, + body: ~s[<html><head><h1>I wil look down and whisper "GNO.."</h1></head></html>] + } + end) + + refute capture_log(fn -> + assert nil == + Instance.get_or_update_favicon( + URI.parse("https://no-favicon.example.org/") + ) + end) =~ "Instance.scrape_favicon(\"https://no-favicon.example.org/\") error: " + end + + test "Doesn't scrapes unreachable instances" do + instance = insert(:instance, unreachable_since: Instances.reachability_datetime_threshold()) + url = "https://" <> instance.host + + assert capture_log(fn -> assert nil == Instance.get_or_update_favicon(URI.parse(url)) end) =~ + "Instance.scrape_favicon(\"#{url}\") ignored unreachable host" + end end - test "Returns nil on too long favicon URLs" do - long_favicon_url = - "https://Lorem.ipsum.dolor.sit.amet/consecteturadipiscingelit/Praesentpharetrapurusutaliquamtempus/Mauriseulaoreetarcu/atfacilisisorci/Nullamporttitor/nequesedfeugiatmollis/dolormagnaefficiturlorem/nonpretiumsapienorcieurisus/Nullamveleratsem/Maecenassedaccumsanexnam/favicon.png" - - Tesla.Mock.mock(fn %{url: "https://long-favicon.example.org/"} -> - %Tesla.Env{ - status: 200, - body: ~s[<html><head><link rel="icon" href="] <> long_favicon_url <> ~s["></head></html>] - } - end) - - assert capture_log(fn -> - assert nil == - Instance.get_or_update_favicon( - URI.parse("https://long-favicon.example.org/") - ) - end) =~ - "Instance.get_or_update_favicon(\"long-favicon.example.org\") error: %Postgrex.Error{" + test "delete_users_and_activities/1 deletes remote instance users and activities" do + [mario, luigi, _peach, wario] = + users = [ + insert(:user, nickname: "mario@mushroom.kingdom", name: "Mario"), + insert(:user, nickname: "luigi@mushroom.kingdom", name: "Luigi"), + insert(:user, nickname: "peach@mushroom.kingdom", name: "Peach"), + insert(:user, nickname: "wario@greedville.biz", name: "Wario") + ] + + {:ok, post1} = CommonAPI.post(mario, %{status: "letsa go!"}) + {:ok, post2} = CommonAPI.post(luigi, %{status: "itsa me... luigi"}) + {:ok, post3} = CommonAPI.post(wario, %{status: "WHA-HA-HA!"}) + + {:ok, job} = Instance.delete_users_and_activities("mushroom.kingdom") + :ok = ObanHelpers.perform(job) + + [mario, luigi, peach, wario] = Repo.reload(users) + + refute mario.is_active + refute luigi.is_active + refute peach.is_active + refute peach.name == "Peach" + + assert wario.is_active + assert wario.name == "Wario" + + assert [nil, nil, %{}] = Repo.reload([post1, post2, post3]) end end diff --git a/test/web/instances/instances_test.exs b/test/pleroma/instances_test.exs index d2618025c..03f9e4e97 100644 --- a/test/web/instances/instances_test.exs +++ b/test/pleroma/instances_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.InstancesTest do @@ -32,9 +32,9 @@ defmodule Pleroma.InstancesTest do assert Instances.reachable?(URI.parse(url).host) end - test "returns true on non-binary input" do - assert Instances.reachable?(nil) - assert Instances.reachable?(1) + test "raises FunctionClauseError exception on non-binary input" do + assert_raise FunctionClauseError, fn -> Instances.reachable?(nil) end + assert_raise FunctionClauseError, fn -> Instances.reachable?(1) end end end diff --git a/test/federation/federation_test.exs b/test/pleroma/integration/federation_test.exs index 10d71fb88..da433e2c0 100644 --- a/test/federation/federation_test.exs +++ b/test/pleroma/integration/federation_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Integration.FederationTest do diff --git a/test/integration/mastodon_websocket_test.exs b/test/pleroma/integration/mastodon_websocket_test.exs index ea17e9feb..43ec57893 100644 --- a/test/integration/mastodon_websocket_test.exs +++ b/test/pleroma/integration/mastodon_websocket_test.exs @@ -1,8 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Integration.MastodonWebsocketTest do + # Needs a streamer, needs to stay synchronous use Pleroma.DataCase import ExUnit.CaptureLog @@ -49,6 +50,7 @@ defmodule Pleroma.Integration.MastodonWebsocketTest do test "allows public streams without authentication" do assert {:ok, _} = start_socket("?stream=public") assert {:ok, _} = start_socket("?stream=public:local") + assert {:ok, _} = start_socket("?stream=public:remote&instance=lain.com") assert {:ok, _} = start_socket("?stream=hashtag&tag=lain") end @@ -78,7 +80,7 @@ defmodule Pleroma.Integration.MastodonWebsocketTest do Pleroma.Repo.insert( OAuth.App.register_changeset(%OAuth.App{}, %{ client_name: "client", - scopes: ["scope"], + scopes: ["read"], redirect_uris: "url" }) ) @@ -99,30 +101,30 @@ defmodule Pleroma.Integration.MastodonWebsocketTest do test "accepts the 'user' stream", %{token: token} = _state do assert {:ok, _} = start_socket("?stream=user&access_token=#{token.token}") - assert capture_log(fn -> - assert {:error, {401, _}} = start_socket("?stream=user") - Process.sleep(30) - end) =~ ":badarg" + capture_log(fn -> + assert {:error, {401, _}} = start_socket("?stream=user") + Process.sleep(30) + end) end test "accepts the 'user:notification' stream", %{token: token} = _state do assert {:ok, _} = start_socket("?stream=user:notification&access_token=#{token.token}") - assert capture_log(fn -> - assert {:error, {401, _}} = start_socket("?stream=user:notification") - Process.sleep(30) - end) =~ ":badarg" + capture_log(fn -> + assert {:error, {401, _}} = start_socket("?stream=user:notification") + Process.sleep(30) + end) end test "accepts valid token on Sec-WebSocket-Protocol header", %{token: token} do assert {:ok, _} = start_socket("?stream=user", [{"Sec-WebSocket-Protocol", token.token}]) - assert capture_log(fn -> - assert {:error, {401, _}} = - start_socket("?stream=user", [{"Sec-WebSocket-Protocol", "I am a friend"}]) + capture_log(fn -> + assert {:error, {401, _}} = + start_socket("?stream=user", [{"Sec-WebSocket-Protocol", "I am a friend"}]) - Process.sleep(30) - end) =~ ":badarg" + Process.sleep(30) + end) end end end diff --git a/test/job_queue_monitor_test.exs b/test/pleroma/job_queue_monitor_test.exs index 65c1e9f29..eebf602c5 100644 --- a/test/job_queue_monitor_test.exs +++ b/test/pleroma/job_queue_monitor_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.JobQueueMonitorTest do diff --git a/test/keys_test.exs b/test/pleroma/keys_test.exs index 9e8528cba..9a15bf06e 100644 --- a/test/keys_test.exs +++ b/test/pleroma/keys_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.KeysTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true alias Pleroma.Keys diff --git a/test/list_test.exs b/test/pleroma/list_test.exs index b5572cbae..7e66ad385 100644 --- a/test/list_test.exs +++ b/test/pleroma/list_test.exs @@ -1,10 +1,10 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.ListTest do alias Pleroma.Repo - use Pleroma.DataCase + use Pleroma.DataCase, async: true import Pleroma.Factory diff --git a/test/marker_test.exs b/test/pleroma/marker_test.exs index 5b6d0b4a4..5f87a1c38 100644 --- a/test/marker_test.exs +++ b/test/pleroma/marker_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.MarkerTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true alias Pleroma.Marker import Pleroma.Factory @@ -33,8 +33,8 @@ defmodule Pleroma.MarkerTest do test "returns user markers" do user = insert(:user) marker = insert(:marker, user: user) - insert(:notification, user: user) - insert(:notification, user: user) + insert(:notification, user: user, activity: insert(:note_activity)) + insert(:notification, user: user, activity: insert(:note_activity)) insert(:marker, timeline: "home", user: user) assert Marker.get_markers( diff --git a/test/mfa/backup_codes_test.exs b/test/pleroma/mfa/backup_codes_test.exs index 7bc01b36b..59f984e32 100644 --- a/test/mfa/backup_codes_test.exs +++ b/test/pleroma/mfa/backup_codes_test.exs @@ -1,5 +1,9 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + defmodule Pleroma.MFA.BackupCodesTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true alias Pleroma.MFA.BackupCodes diff --git a/test/mfa/totp_test.exs b/test/pleroma/mfa/totp_test.exs index 50153d208..828993866 100644 --- a/test/mfa/totp_test.exs +++ b/test/pleroma/mfa/totp_test.exs @@ -1,5 +1,9 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + defmodule Pleroma.MFA.TOTPTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true alias Pleroma.MFA.TOTP diff --git a/test/mfa_test.exs b/test/pleroma/mfa_test.exs index 8875cefd9..76ba1a99d 100644 --- a/test/mfa_test.exs +++ b/test/pleroma/mfa_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.MFATest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true import Pleroma.Factory alias Pleroma.MFA @@ -30,8 +30,8 @@ defmodule Pleroma.MFATest do {:ok, [code1, code2]} = MFA.generate_backup_codes(user) updated_user = refresh_record(user) [hash1, hash2] = updated_user.multi_factor_authentication_settings.backup_codes - assert Pbkdf2.verify_pass(code1, hash1) - assert Pbkdf2.verify_pass(code2, hash2) + assert Pleroma.Password.Pbkdf2.verify_pass(code1, hash1) + assert Pleroma.Password.Pbkdf2.verify_pass(code2, hash2) end end diff --git a/test/migration_helper/notification_backfill_test.exs b/test/pleroma/migration_helper/notification_backfill_test.exs index 2a62a2b00..fd253b530 100644 --- a/test/migration_helper/notification_backfill_test.exs +++ b/test/pleroma/migration_helper/notification_backfill_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.MigrationHelper.NotificationBackfillTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true alias Pleroma.Activity alias Pleroma.MigrationHelper.NotificationBackfill diff --git a/test/moderation_log_test.exs b/test/pleroma/moderation_log_test.exs index 59f4d67f8..607301815 100644 --- a/test/moderation_log_test.exs +++ b/test/pleroma/moderation_log_test.exs @@ -1,12 +1,12 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.ModerationLogTest do alias Pleroma.Activity alias Pleroma.ModerationLog - use Pleroma.DataCase + use Pleroma.DataCase, async: true import Pleroma.Factory @@ -182,11 +182,14 @@ defmodule Pleroma.ModerationLogTest do end test "logging report update", %{moderator: moderator} do + user = insert(:user) + report = %Activity{ id: "9m9I1F4p8ftrTP6QTI", data: %{ "type" => "Flag", - "state" => "resolved" + "state" => "resolved", + "actor" => user.ap_id } } @@ -194,35 +197,46 @@ defmodule Pleroma.ModerationLogTest do ModerationLog.insert_log(%{ actor: moderator, action: "report_update", - subject: report + subject: report, + subject_actor: user }) log = Repo.one(ModerationLog) assert log.data["message"] == - "@#{moderator.nickname} updated report ##{report.id} with 'resolved' state" + "@#{moderator.nickname} updated report ##{report.id} (on user @#{user.nickname}) with 'resolved' state" end test "logging report response", %{moderator: moderator} do + user = insert(:user) + report = %Activity{ id: "9m9I1F4p8ftrTP6QTI", data: %{ - "type" => "Note" + "type" => "Note", + "actor" => user.ap_id } } - {:ok, _} = - ModerationLog.insert_log(%{ - actor: moderator, - action: "report_note", - subject: report, - text: "look at this" - }) + attrs = %{ + actor: moderator, + action: "report_note", + subject: report, + text: "look at this" + } - log = Repo.one(ModerationLog) + {:ok, log1} = ModerationLog.insert_log(attrs) + log = Repo.get(ModerationLog, log1.id) assert log.data["message"] == "@#{moderator.nickname} added note 'look at this' to report ##{report.id}" + + {:ok, log2} = ModerationLog.insert_log(Map.merge(attrs, %{subject_actor: user})) + + log = Repo.get(ModerationLog, log2.id) + + assert log.data["message"] == + "@#{moderator.nickname} added note 'look at this' to report ##{report.id} on user @#{user.nickname}" end test "logging status sensitivity update", %{moderator: moderator} do diff --git a/test/notification_test.exs b/test/pleroma/notification_test.exs index a09b08675..716af496d 100644 --- a/test/notification_test.exs +++ b/test/pleroma/notification_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.NotificationTest do @@ -32,6 +32,33 @@ defmodule Pleroma.NotificationTest do refute {:ok, [nil]} == Notification.create_notifications(activity) end + test "creates a notification for a report" do + reporting_user = insert(:user) + reported_user = insert(:user) + {:ok, moderator_user} = insert(:user) |> User.admin_api_update(%{is_moderator: true}) + + {:ok, activity} = CommonAPI.report(reporting_user, %{account_id: reported_user.id}) + + {:ok, [notification]} = Notification.create_notifications(activity) + + assert notification.user_id == moderator_user.id + assert notification.type == "pleroma:report" + end + + test "suppresses notification to reporter if reporter is an admin" do + reporting_admin = insert(:user, is_admin: true) + reported_user = insert(:user) + other_admin = insert(:user, is_admin: true) + + {:ok, activity} = CommonAPI.report(reporting_admin, %{account_id: reported_user.id}) + + {:ok, [notification]} = Notification.create_notifications(activity) + + refute notification.user_id == reporting_admin.id + assert notification.user_id == other_admin.id + assert notification.type == "pleroma:report" + end + test "creates a notification for an emoji reaction" do user = insert(:user) other_user = insert(:user) @@ -102,6 +129,19 @@ defmodule Pleroma.NotificationTest do end end + test "create_poll_notifications/1" do + [user1, user2, user3, _, _] = insert_list(5, :user) + question = insert(:question, user: user1) + activity = insert(:question_activity, question: question) + + {:ok, _, _} = CommonAPI.vote(user2, question, [0]) + {:ok, _, _} = CommonAPI.vote(user3, question, [1]) + + {:ok, notifications} = Notification.create_poll_notifications(activity) + + assert [user2.id, user3.id, user1.id] == Enum.map(notifications, & &1.user_id) + end + describe "CommonApi.post/2 notification-related functionality" do test_with_mock "creates but does NOT send notification to blocker user", Push, @@ -179,17 +219,19 @@ defmodule Pleroma.NotificationTest do describe "create_notification" do @tag needs_streamer: true test "it creates a notification for user and send to the 'user' and the 'user:notification' stream" do - user = insert(:user) + %{user: user, token: oauth_token} = oauth_access(["read"]) task = Task.async(fn -> - Streamer.get_topic_and_add_socket("user", user) + {:ok, _topic} = Streamer.get_topic_and_add_socket("user", user, oauth_token) assert_receive {:render_with_user, _, _, _}, 4_000 end) task_user_notification = Task.async(fn -> - Streamer.get_topic_and_add_socket("user:notification", user) + {:ok, _topic} = + Streamer.get_topic_and_add_socket("user:notification", user, oauth_token) + assert_receive {:render_with_user, _, _, _}, 4_000 end) @@ -227,7 +269,7 @@ defmodule Pleroma.NotificationTest do muter = insert(:user) muted = insert(:user) - {:ok, _user_relationships} = User.mute(muter, muted, false) + {:ok, _user_relationships} = User.mute(muter, muted, %{notifications: false}) {:ok, activity} = CommonAPI.post(muted, %{status: "Hi @#{muter.nickname}"}) @@ -344,7 +386,7 @@ defmodule Pleroma.NotificationTest do describe "follow / follow_request notifications" do test "it creates `follow` notification for approved Follow activity" do user = insert(:user) - followed_user = insert(:user, locked: false) + followed_user = insert(:user, is_locked: false) {:ok, _, _, _activity} = CommonAPI.follow(user, followed_user) assert FollowingRelationship.following?(user, followed_user) @@ -359,7 +401,7 @@ defmodule Pleroma.NotificationTest do test "it creates `follow_request` notification for pending Follow activity" do user = insert(:user) - followed_user = insert(:user, locked: true) + followed_user = insert(:user, is_locked: true) {:ok, _, _, _activity} = CommonAPI.follow(user, followed_user) refute FollowingRelationship.following?(user, followed_user) @@ -381,7 +423,7 @@ defmodule Pleroma.NotificationTest do test "it doesn't create a notification for follow-unfollow-follow chains" do user = insert(:user) - followed_user = insert(:user, locked: false) + followed_user = insert(:user, is_locked: false) {:ok, _, _, _activity} = CommonAPI.follow(user, followed_user) assert FollowingRelationship.following?(user, followed_user) @@ -395,10 +437,10 @@ defmodule Pleroma.NotificationTest do end test "dismisses the notification on follow request rejection" do - user = insert(:user, locked: true) + user = insert(:user, is_locked: true) follower = insert(:user) {:ok, _, _, _follow_activity} = CommonAPI.follow(follower, user) - assert [notification] = Notification.for_user(user) + assert [_notification] = Notification.for_user(user) {:ok, _follower} = CommonAPI.reject_follow_request(follower, user) assert [] = Notification.for_user(user) end @@ -595,6 +637,8 @@ defmodule Pleroma.NotificationTest do "actor" => user.ap_id, "object" => %{ "type" => "Note", + "id" => Pleroma.Web.ActivityPub.Utils.generate_object_id(), + "to" => ["https://www.w3.org/ns/activitystreams#Public"], "content" => "message with a Mention tag, but no explicit tagging", "tag" => [ %{ @@ -626,6 +670,9 @@ defmodule Pleroma.NotificationTest do "actor" => user.ap_id, "object" => %{ "type" => "Note", + "id" => Pleroma.Web.ActivityPub.Utils.generate_object_id(), + "to" => ["https://www.w3.org/ns/activitystreams#Public"], + "cc" => [other_user.ap_id], "content" => "hi everyone", "attributedTo" => user.ap_id } @@ -764,7 +811,7 @@ defmodule Pleroma.NotificationTest do other_user = insert(:user) {:ok, other_user} = User.block_domain(other_user, blocked_domain) - {:ok, other_user} = User.follow(other_user, user) + {:ok, other_user, user} = User.follow(other_user, user) {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"}) @@ -922,6 +969,7 @@ defmodule Pleroma.NotificationTest do "cc" => [], "object" => %{ "type" => "Note", + "id" => remote_user.ap_id <> "/objects/test", "content" => "Hello!", "tag" => [ %{ @@ -961,7 +1009,6 @@ defmodule Pleroma.NotificationTest do assert Enum.empty?(Notification.for_user(local_user)) end - @tag capture_log: true test "move activity generates a notification" do %{ap_id: old_ap_id} = old_user = insert(:user) %{ap_id: new_ap_id} = new_user = insert(:user, also_known_as: [old_ap_id]) @@ -971,18 +1018,6 @@ defmodule Pleroma.NotificationTest do User.follow(follower, old_user) User.follow(other_follower, old_user) - old_user_url = old_user.ap_id - - body = - File.read!("test/fixtures/users_mock/localhost.json") - |> String.replace("{{nickname}}", old_user.nickname) - |> Jason.encode!() - - Tesla.Mock.mock(fn - %{method: :get, url: ^old_user_url} -> - %Tesla.Env{status: 200, body: body} - end) - Pleroma.Web.ActivityPub.ActivityPub.move(old_user, new_user) ObanHelpers.perform_all() @@ -1013,7 +1048,7 @@ defmodule Pleroma.NotificationTest do test "it returns notifications for muted user without notifications", %{user: user} do muted = insert(:user) - {:ok, _user_relationships} = User.mute(user, muted, false) + {:ok, _user_relationships} = User.mute(user, muted, %{notifications: false}) {:ok, _activity} = CommonAPI.post(muted, %{status: "hey @#{user.nickname}"}) @@ -1055,7 +1090,7 @@ defmodule Pleroma.NotificationTest do blocked = insert(:user, ap_id: "http://some-domain.com") {:ok, user} = User.block_domain(user, "some-domain.com") - {:ok, _} = User.follow(user, blocked) + {:ok, _, _} = User.follow(user, blocked) {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"}) diff --git a/test/object/containment_test.exs b/test/pleroma/object/containment_test.exs index 90b6dccf2..fb2fb7d49 100644 --- a/test/object/containment_test.exs +++ b/test/pleroma/object/containment_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Object.ContainmentTest do diff --git a/test/object/fetcher_test.exs b/test/pleroma/object/fetcher_test.exs index 16cfa7f5c..bd0a6e497 100644 --- a/test/object/fetcher_test.exs +++ b/test/pleroma/object/fetcher_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Object.FetcherTest do @@ -8,8 +8,9 @@ defmodule Pleroma.Object.FetcherTest do alias Pleroma.Activity alias Pleroma.Object alias Pleroma.Object.Fetcher - import Tesla.Mock + import Mock + import Tesla.Mock setup do mock(fn @@ -19,6 +20,17 @@ defmodule Pleroma.Object.FetcherTest do %{method: :get, url: "https://mastodon.example.org/users/userisgone404"} -> %Tesla.Env{status: 404} + %{ + method: :get, + url: + "https://patch.cx/media/03ca3c8b4ac3ddd08bf0f84be7885f2f88de0f709112131a22d83650819e36c2.json" + } -> + %Tesla.Env{ + status: 200, + headers: [{"content-type", "application/json"}], + body: File.read!("test/fixtures/spoofed-object.json") + } + env -> apply(HttpRequestMock, :request, [env]) end) @@ -32,25 +44,36 @@ defmodule Pleroma.Object.FetcherTest do %{method: :get, url: "https://social.sakamoto.gq/notice/9wTkLEnuq47B25EehM"} -> %Tesla.Env{ status: 200, - body: File.read!("test/fixtures/fetch_mocks/9wTkLEnuq47B25EehM.json") + body: File.read!("test/fixtures/fetch_mocks/9wTkLEnuq47B25EehM.json"), + headers: HttpRequestMock.activitypub_object_headers() } %{method: :get, url: "https://social.sakamoto.gq/users/eal"} -> %Tesla.Env{ status: 200, - body: File.read!("test/fixtures/fetch_mocks/eal.json") + body: File.read!("test/fixtures/fetch_mocks/eal.json"), + headers: HttpRequestMock.activitypub_object_headers() } %{method: :get, url: "https://busshi.moe/users/tuxcrafting/statuses/104410921027210069"} -> %Tesla.Env{ status: 200, - body: File.read!("test/fixtures/fetch_mocks/104410921027210069.json") + body: File.read!("test/fixtures/fetch_mocks/104410921027210069.json"), + headers: HttpRequestMock.activitypub_object_headers() } %{method: :get, url: "https://busshi.moe/users/tuxcrafting"} -> %Tesla.Env{ status: 500 } + + %{ + method: :get, + url: "https://stereophonic.space/objects/02997b83-3ea7-4b63-94af-ef3aa2d4ed17" + } -> + %Tesla.Env{ + status: 500 + } end) :ok @@ -71,20 +94,20 @@ defmodule Pleroma.Object.FetcherTest do setup do: clear_config([:instance, :federation_incoming_replies_max_depth]) test "it returns thread depth exceeded error if thread depth is exceeded" do - Pleroma.Config.put([:instance, :federation_incoming_replies_max_depth], 0) + clear_config([:instance, :federation_incoming_replies_max_depth], 0) assert {:error, "Max thread distance exceeded."} = Fetcher.fetch_object_from_id(@ap_id, depth: 1) end test "it fetches object if max thread depth is restricted to 0 and depth is not specified" do - Pleroma.Config.put([:instance, :federation_incoming_replies_max_depth], 0) + clear_config([:instance, :federation_incoming_replies_max_depth], 0) assert {:ok, _} = Fetcher.fetch_object_from_id(@ap_id) end test "it fetches object if requested depth does not exceed max thread depth" do - Pleroma.Config.put([:instance, :federation_incoming_replies_max_depth], 10) + clear_config([:instance, :federation_incoming_replies_max_depth], 10) assert {:ok, _} = Fetcher.fetch_object_from_id(@ap_id, depth: 10) end @@ -109,8 +132,7 @@ defmodule Pleroma.Object.FetcherTest do {:ok, object} = Fetcher.fetch_object_from_id("http://mastodon.example.org/@admin/99541947525187367") - assert activity = Activity.get_create_by_object_ap_id(object.data["id"]) - assert activity.data["id"] + assert _activity = Activity.get_create_by_object_ap_id(object.data["id"]) {:ok, object_again} = Fetcher.fetch_object_from_id("http://mastodon.example.org/@admin/99541947525187367") @@ -120,6 +142,23 @@ defmodule Pleroma.Object.FetcherTest do assert object == object_again end + + test "Return MRF reason when fetched status is rejected by one" do + clear_config([:mrf_keyword, :reject], ["yeah"]) + clear_config([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.KeywordPolicy]) + + assert {:reject, "[KeywordPolicy] Matches with rejected keyword"} == + Fetcher.fetch_object_from_id( + "http://mastodon.example.org/@admin/99541947525187367" + ) + end + + test "it does not fetch a spoofed object uploaded on an instance as an attachment" do + assert {:error, _} = + Fetcher.fetch_object_from_id( + "https://patch.cx/media/03ca3c8b4ac3ddd08bf0f84be7885f2f88de0f709112131a22d83650819e36c2.json" + ) + end end describe "implementation quirks" do @@ -212,7 +251,7 @@ defmodule Pleroma.Object.FetcherTest do Pleroma.Signature, [:passthrough], [] do - Pleroma.Config.put([:activitypub, :sign_object_fetches], true) + clear_config([:activitypub, :sign_object_fetches], true) Fetcher.fetch_object_from_id("http://mastodon.example.org/@admin/99541947525187367") @@ -223,7 +262,7 @@ defmodule Pleroma.Object.FetcherTest do Pleroma.Signature, [:passthrough], [] do - Pleroma.Config.put([:activitypub, :sign_object_fetches], false) + clear_config([:activitypub, :sign_object_fetches], false) Fetcher.fetch_object_from_id("http://mastodon.example.org/@admin/99541947525187367") diff --git a/test/object_test.exs b/test/pleroma/object_test.exs index 198d3b1cf..8320660a5 100644 --- a/test/object_test.exs +++ b/test/pleroma/object_test.exs @@ -1,14 +1,17 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.ObjectTest do use Pleroma.DataCase use Oban.Testing, repo: Pleroma.Repo + import ExUnit.CaptureLog import Pleroma.Factory import Tesla.Mock + alias Pleroma.Activity + alias Pleroma.Hashtag alias Pleroma.Object alias Pleroma.Repo alias Pleroma.Tests.ObanHelpers @@ -78,11 +81,11 @@ defmodule Pleroma.ObjectTest do setup do: clear_config([:instance, :cleanup_attachments]) test "Disabled via config" do - Pleroma.Config.put([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local) - Pleroma.Config.put([:instance, :cleanup_attachments], false) + clear_config([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local) + clear_config([:instance, :cleanup_attachments], false) file = %Plug.Upload{ - content_type: "image/jpg", + content_type: "image/jpeg", path: Path.absname("test/fixtures/image.jpg"), filename: "an_image.jpg" } @@ -112,11 +115,11 @@ defmodule Pleroma.ObjectTest do end test "in subdirectories" do - Pleroma.Config.put([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local) - Pleroma.Config.put([:instance, :cleanup_attachments], true) + clear_config([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local) + clear_config([:instance, :cleanup_attachments], true) file = %Plug.Upload{ - content_type: "image/jpg", + content_type: "image/jpeg", path: Path.absname("test/fixtures/image.jpg"), filename: "an_image.jpg" } @@ -146,16 +149,16 @@ defmodule Pleroma.ObjectTest do end test "with dedupe enabled" do - Pleroma.Config.put([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local) - Pleroma.Config.put([Pleroma.Upload, :filters], [Pleroma.Upload.Filter.Dedupe]) - Pleroma.Config.put([:instance, :cleanup_attachments], true) + clear_config([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local) + clear_config([Pleroma.Upload, :filters], [Pleroma.Upload.Filter.Dedupe]) + clear_config([:instance, :cleanup_attachments], true) uploads_dir = Pleroma.Config.get!([Pleroma.Uploaders.Local, :uploads]) File.mkdir_p!(uploads_dir) file = %Plug.Upload{ - content_type: "image/jpg", + content_type: "image/jpeg", path: Path.absname("test/fixtures/image.jpg"), filename: "an_image.jpg" } @@ -184,11 +187,11 @@ defmodule Pleroma.ObjectTest do end test "with objects that have legacy data.url attribute" do - Pleroma.Config.put([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local) - Pleroma.Config.put([:instance, :cleanup_attachments], true) + clear_config([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local) + clear_config([:instance, :cleanup_attachments], true) file = %Plug.Upload{ - content_type: "image/jpg", + content_type: "image/jpeg", path: Path.absname("test/fixtures/image.jpg"), filename: "an_image.jpg" } @@ -220,12 +223,12 @@ defmodule Pleroma.ObjectTest do end test "With custom base_url" do - Pleroma.Config.put([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local) - Pleroma.Config.put([Pleroma.Upload, :base_url], "https://sub.domain.tld/dir/") - Pleroma.Config.put([:instance, :cleanup_attachments], true) + clear_config([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local) + clear_config([Pleroma.Upload, :base_url], "https://sub.domain.tld/dir/") + clear_config([:instance, :cleanup_attachments], true) file = %Plug.Upload{ - content_type: "image/jpg", + content_type: "image/jpeg", path: Path.absname("test/fixtures/image.jpg"), filename: "an_image.jpg" } @@ -256,23 +259,22 @@ defmodule Pleroma.ObjectTest do end describe "normalizer" do - test "fetches unknown objects by default" do - %Object{} = - object = Object.normalize("http://mastodon.example.org/@admin/99541947525187367") - - assert object.data["url"] == "http://mastodon.example.org/@admin/99541947525187367" + @url "http://mastodon.example.org/@admin/99541947525187367" + test "does not fetch unknown objects by default" do + assert nil == Object.normalize(@url) end - test "fetches unknown objects when fetch_remote is explicitly true" do - %Object{} = - object = Object.normalize("http://mastodon.example.org/@admin/99541947525187367", true) + test "fetches unknown objects when fetch is explicitly true" do + %Object{} = object = Object.normalize(@url, fetch: true) - assert object.data["url"] == "http://mastodon.example.org/@admin/99541947525187367" + assert object.data["url"] == @url end - test "does not fetch unknown objects when fetch_remote is false" do + test "does not fetch unknown objects when fetch is false" do assert is_nil( - Object.normalize("http://mastodon.example.org/@admin/99541947525187367", false) + Object.normalize(@url, + fetch: false + ) ) end end @@ -281,7 +283,11 @@ defmodule Pleroma.ObjectTest do setup do mock(fn %{method: :get, url: "https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d"} -> - %Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/poll_original.json")} + %Tesla.Env{ + status: 200, + body: File.read!("test/fixtures/tesla_mock/poll_original.json"), + headers: HttpRequestMock.activitypub_object_headers() + } env -> apply(HttpRequestMock, :request, [env]) @@ -306,7 +312,10 @@ defmodule Pleroma.ObjectTest do mock_modified: mock_modified } do %Object{} = - object = Object.normalize("https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d") + object = + Object.normalize("https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d", + fetch: true + ) Object.set_cache(object) @@ -315,7 +324,8 @@ defmodule Pleroma.ObjectTest do mock_modified.(%Tesla.Env{ status: 200, - body: File.read!("test/fixtures/tesla_mock/poll_modified.json") + body: File.read!("test/fixtures/tesla_mock/poll_modified.json"), + headers: HttpRequestMock.activitypub_object_headers() }) updated_object = Object.get_by_id_and_maybe_refetch(object.id, interval: -1) @@ -327,7 +337,10 @@ defmodule Pleroma.ObjectTest do test "returns the old object if refetch fails", %{mock_modified: mock_modified} do %Object{} = - object = Object.normalize("https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d") + object = + Object.normalize("https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d", + fetch: true + ) Object.set_cache(object) @@ -350,7 +363,10 @@ defmodule Pleroma.ObjectTest do mock_modified: mock_modified } do %Object{} = - object = Object.normalize("https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d") + object = + Object.normalize("https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d", + fetch: true + ) Object.set_cache(object) @@ -359,7 +375,8 @@ defmodule Pleroma.ObjectTest do mock_modified.(%Tesla.Env{ status: 200, - body: File.read!("test/fixtures/tesla_mock/poll_modified.json") + body: File.read!("test/fixtures/tesla_mock/poll_modified.json"), + headers: HttpRequestMock.activitypub_object_headers() }) updated_object = Object.get_by_id_and_maybe_refetch(object.id, interval: 100) @@ -371,7 +388,10 @@ defmodule Pleroma.ObjectTest do test "preserves internal fields on refetch", %{mock_modified: mock_modified} do %Object{} = - object = Object.normalize("https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d") + object = + Object.normalize("https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d", + fetch: true + ) Object.set_cache(object) @@ -387,7 +407,8 @@ defmodule Pleroma.ObjectTest do mock_modified.(%Tesla.Env{ status: 200, - body: File.read!("test/fixtures/tesla_mock/poll_modified.json") + body: File.read!("test/fixtures/tesla_mock/poll_modified.json"), + headers: HttpRequestMock.activitypub_object_headers() }) updated_object = Object.get_by_id_and_maybe_refetch(object.id, interval: -1) @@ -399,4 +420,28 @@ defmodule Pleroma.ObjectTest do assert updated_object.data["like_count"] == 1 end end + + describe ":hashtags association" do + test "Hashtag records are created with Object record and updated on its change" do + user = insert(:user) + + {:ok, %{object: object}} = + CommonAPI.post(user, %{status: "some text #hashtag1 #hashtag2 ..."}) + + assert [%Hashtag{name: "hashtag1"}, %Hashtag{name: "hashtag2"}] = + Enum.sort_by(object.hashtags, & &1.name) + + {:ok, object} = Object.update_data(object, %{"tag" => []}) + + assert [] = object.hashtags + + object = Object.get_by_id(object.id) |> Repo.preload(:hashtags) + assert [] = object.hashtags + + {:ok, object} = Object.update_data(object, %{"tag" => ["abc", "def"]}) + + assert [%Hashtag{name: "abc"}, %Hashtag{name: "def"}] = + Enum.sort_by(object.hashtags, & &1.name) + end + end end diff --git a/test/otp_version_test.exs b/test/pleroma/otp_version_test.exs index 7d2538ec8..736d440af 100644 --- a/test/otp_version_test.exs +++ b/test/pleroma/otp_version_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.OTPVersionTest do diff --git a/test/pagination_test.exs b/test/pleroma/pagination_test.exs index e526f23e8..bc26c8b46 100644 --- a/test/pagination_test.exs +++ b/test/pleroma/pagination_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.PaginationTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true import Pleroma.Factory diff --git a/test/pleroma/password/pbkdf2_test.exs b/test/pleroma/password/pbkdf2_test.exs new file mode 100644 index 000000000..e55348f9a --- /dev/null +++ b/test/pleroma/password/pbkdf2_test.exs @@ -0,0 +1,35 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Password.Pbkdf2Test do + use Pleroma.DataCase, async: true + + alias Pleroma.Password.Pbkdf2, as: Password + + test "it generates the same hash as pbkd2_elixir" do + # hash = Pbkdf2.hash_pwd_salt("password") + hash = + "$pbkdf2-sha512$1$QJpEYw8iBKcnY.4Rm0eCVw$UBPeWQ91RxSv3snxsb/ZzMeG/2aa03c541bbo8vQudREGNta5t8jBQrd00fyJp8RjaqfvgdZxy2rhSwljyu21g" + + # Use the same randomly generated salt + salt = Password.decode64("QJpEYw8iBKcnY.4Rm0eCVw") + + assert hash == Password.hash_pwd_salt("password", salt: salt) + end + + @tag skip: "Works when Pbkd2 is present. Source: trust me bro" + test "Pbkdf2 can verify passwords generated with it" do + # Commented to prevent warnings. + # hash = Password.hash_pwd_salt("password") + # assert Pbkdf2.verify_pass("password", hash) + end + + test "it verifies pbkdf2_elixir hashes" do + # hash = Pbkdf2.hash_pwd_salt("password") + hash = + "$pbkdf2-sha512$1$QJpEYw8iBKcnY.4Rm0eCVw$UBPeWQ91RxSv3snxsb/ZzMeG/2aa03c541bbo8vQudREGNta5t8jBQrd00fyJp8RjaqfvgdZxy2rhSwljyu21g" + + assert Password.verify_pass("password", hash) + end +end diff --git a/test/registration_test.exs b/test/pleroma/registration_test.exs index 7db8e3664..6e4ad9487 100644 --- a/test/registration_test.exs +++ b/test/pleroma/registration_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.RegistrationTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true import Pleroma.Factory diff --git a/test/migrations/20200716195806_autolinker_to_linkify_test.exs b/test/pleroma/repo/migrations/autolinker_to_linkify_test.exs index 250d11c61..a7d4d493c 100644 --- a/test/migrations/20200716195806_autolinker_to_linkify_test.exs +++ b/test/pleroma/repo/migrations/autolinker_to_linkify_test.exs @@ -1,3 +1,7 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + defmodule Pleroma.Repo.Migrations.AutolinkerToLinkifyTest do use Pleroma.DataCase import Pleroma.Factory @@ -33,7 +37,7 @@ defmodule Pleroma.Repo.Migrations.AutolinkerToLinkifyTest do strip_prefix: false ] - Pleroma.Config.put(Pleroma.Formatter, new_opts) + clear_config(Pleroma.Formatter, new_opts) assert new_opts == Pleroma.Config.get(Pleroma.Formatter) {text, _mentions, []} = diff --git a/test/pleroma/repo/migrations/confirm_logged_in_users_test.exs b/test/pleroma/repo/migrations/confirm_logged_in_users_test.exs new file mode 100644 index 000000000..99d17f62a --- /dev/null +++ b/test/pleroma/repo/migrations/confirm_logged_in_users_test.exs @@ -0,0 +1,40 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Repo.Migrations.ConfirmLoggedInUsersTest do + alias Pleroma.Repo + alias Pleroma.User + use Pleroma.DataCase, async: true + import Ecto.Query + import Pleroma.Factory + import Pleroma.Tests.Helpers + + setup_all do: require_migration("20201231185546_confirm_logged_in_users") + + test "up/0 confirms unconfirmed but previously-logged-in users", %{migration: migration} do + insert_list(25, :oauth_token) + Repo.update_all(User, set: [is_confirmed: false]) + insert_list(5, :user, is_confirmed: false) + + count = + User + |> where(is_confirmed: false) + |> Repo.aggregate(:count) + + assert count == 30 + + assert {25, nil} == migration.up() + + count = + User + |> where(is_confirmed: false) + |> Repo.aggregate(:count) + + assert count == 5 + end + + test "down/0 does nothing", %{migration: migration} do + assert :noop == migration.down() + end +end diff --git a/test/pleroma/repo/migrations/deprecate_public_endpoint_test.exs b/test/pleroma/repo/migrations/deprecate_public_endpoint_test.exs new file mode 100644 index 000000000..2ffc1b145 --- /dev/null +++ b/test/pleroma/repo/migrations/deprecate_public_endpoint_test.exs @@ -0,0 +1,60 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Repo.Migrations.DeprecatePublicEndpointTest do + use Pleroma.DataCase + import Pleroma.Factory + import Pleroma.Tests.Helpers + alias Pleroma.ConfigDB + + setup do: clear_config(Pleroma.Upload) + setup do: clear_config(Pleroma.Uploaders.S3) + setup_all do: require_migration("20210113225652_deprecate_public_endpoint") + + test "up/0 migrates public_endpoint to base_url", %{migration: migration} do + s3_values = [ + public_endpoint: "https://coolhost.com/", + bucket: "secret_bucket" + ] + + insert(:config, group: :pleroma, key: Pleroma.Uploaders.S3, value: s3_values) + + upload_values = [ + uploader: Pleroma.Uploaders.S3 + ] + + insert(:config, group: :pleroma, key: Pleroma.Upload, value: upload_values) + + migration.up() + + assert [bucket: "secret_bucket"] == + ConfigDB.get_by_params(%{group: :pleroma, key: Pleroma.Uploaders.S3}).value + + assert [uploader: Pleroma.Uploaders.S3, base_url: "https://coolhost.com/"] == + ConfigDB.get_by_params(%{group: :pleroma, key: Pleroma.Upload}).value + end + + test "down/0 reverts base_url to public_endpoint", %{migration: migration} do + s3_values = [ + bucket: "secret_bucket" + ] + + insert(:config, group: :pleroma, key: Pleroma.Uploaders.S3, value: s3_values) + + upload_values = [ + uploader: Pleroma.Uploaders.S3, + base_url: "https://coolhost.com/" + ] + + insert(:config, group: :pleroma, key: Pleroma.Upload, value: upload_values) + + migration.down() + + assert [bucket: "secret_bucket", public_endpoint: "https://coolhost.com/"] == + ConfigDB.get_by_params(%{group: :pleroma, key: Pleroma.Uploaders.S3}).value + + assert [uploader: Pleroma.Uploaders.S3] == + ConfigDB.get_by_params(%{group: :pleroma, key: Pleroma.Upload}).value + end +end diff --git a/test/migrations/20200802170532_fix_legacy_tags_test.exs b/test/pleroma/repo/migrations/fix_legacy_tags_test.exs index 3b4dee407..0a1d1d0bb 100644 --- a/test/migrations/20200802170532_fix_legacy_tags_test.exs +++ b/test/pleroma/repo/migrations/fix_legacy_tags_test.exs @@ -1,6 +1,10 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + defmodule Pleroma.Repo.Migrations.FixLegacyTagsTest do alias Pleroma.User - use Pleroma.DataCase + use Pleroma.DataCase, async: true import Pleroma.Factory import Pleroma.Tests.Helpers diff --git a/test/migrations/20200722185515_fix_malformed_formatter_config_test.exs b/test/pleroma/repo/migrations/fix_malformed_formatter_config_test.exs index d3490478e..65c9961b0 100644 --- a/test/migrations/20200722185515_fix_malformed_formatter_config_test.exs +++ b/test/pleroma/repo/migrations/fix_malformed_formatter_config_test.exs @@ -1,3 +1,7 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + defmodule Pleroma.Repo.Migrations.FixMalformedFormatterConfigTest do use Pleroma.DataCase import Pleroma.Factory @@ -30,7 +34,7 @@ defmodule Pleroma.Repo.Migrations.FixMalformedFormatterConfigTest do strip_prefix: false ] - Pleroma.Config.put(Pleroma.Formatter, new_opts) + clear_config(Pleroma.Formatter, new_opts) assert new_opts == Pleroma.Config.get(Pleroma.Formatter) {text, _mentions, []} = diff --git a/test/migrations/20200724133313_move_welcome_settings_test.exs b/test/pleroma/repo/migrations/move_welcome_settings_test.exs index 739f24547..1da6b8a04 100644 --- a/test/migrations/20200724133313_move_welcome_settings_test.exs +++ b/test/pleroma/repo/migrations/move_welcome_settings_test.exs @@ -1,5 +1,9 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + defmodule Pleroma.Repo.Migrations.MoveWelcomeSettingsTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true import Pleroma.Factory import Pleroma.Tests.Helpers alias Pleroma.ConfigDB diff --git a/test/pleroma/repo/migrations/rename_instance_chat_test.exs b/test/pleroma/repo/migrations/rename_instance_chat_test.exs new file mode 100644 index 000000000..acd45600c --- /dev/null +++ b/test/pleroma/repo/migrations/rename_instance_chat_test.exs @@ -0,0 +1,52 @@ +defmodule Pleroma.Repo.Migrations.RenameInstanceChatTest do + use Pleroma.DataCase + import Pleroma.Factory + import Pleroma.Tests.Helpers + alias Pleroma.ConfigDB + + setup do: clear_config([:instance]) + setup do: clear_config([:chat]) + setup_all do: require_migration("20200806175913_rename_instance_chat") + + describe "up/0" do + test "migrates chat settings to shout", %{migration: migration} do + insert(:config, group: :pleroma, key: :instance, value: [chat_limit: 6000]) + insert(:config, group: :pleroma, key: :chat, value: [enabled: true]) + + assert migration.up() == :ok + + assert ConfigDB.get_by_params(%{group: :pleroma, key: :chat}) == nil + assert ConfigDB.get_by_params(%{group: :pleroma, key: :instance}) == nil + + assert ConfigDB.get_by_params(%{group: :pleroma, key: :shout}).value == [ + limit: 6000, + enabled: true + ] + end + + test "does nothing when chat settings are not set", %{migration: migration} do + assert migration.up() == :noop + assert ConfigDB.get_by_params(%{group: :pleroma, key: :chat}) == nil + assert ConfigDB.get_by_params(%{group: :pleroma, key: :shout}) == nil + end + end + + describe "down/0" do + test "migrates shout settings back to instance and chat", %{migration: migration} do + insert(:config, group: :pleroma, key: :shout, value: [limit: 42, enabled: true]) + + assert migration.down() == :ok + + assert ConfigDB.get_by_params(%{group: :pleroma, key: :chat}).value == [enabled: true] + assert ConfigDB.get_by_params(%{group: :pleroma, key: :instance}).value == [chat_limit: 42] + assert ConfigDB.get_by_params(%{group: :pleroma, key: :shout}) == nil + end + + test "does nothing when shout settings are not set", %{migration: migration} do + assert migration.down() == :noop + assert ConfigDB.get_by_params(%{group: :pleroma, key: :chat}) == nil + assert ConfigDB.get_by_params(%{group: :pleroma, key: :instance}) == nil + assert ConfigDB.get_by_params(%{group: :pleroma, key: :shout}) == nil + end + end +end diff --git a/test/repo_test.exs b/test/pleroma/repo_test.exs index 92e827c95..9e14bdbd1 100644 --- a/test/repo_test.exs +++ b/test/pleroma/repo_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.RepoTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true import Pleroma.Factory alias Pleroma.User @@ -37,7 +37,9 @@ defmodule Pleroma.RepoTest do test "get one-to-many assoc from repo" do user = insert(:user) - notification = refresh_record(insert(:notification, user: user)) + + notification = + refresh_record(insert(:notification, user: user, activity: insert(:note_activity))) assert Repo.get_assoc(user, :notifications) == {:ok, [notification]} end @@ -47,4 +49,32 @@ defmodule Pleroma.RepoTest do assert Repo.get_assoc(token, :user) == {:error, :not_found} end end + + describe "chunk_stream/3" do + test "fetch records one-by-one" do + users = insert_list(50, :user) + + {fetch_users, 50} = + from(t in User) + |> Repo.chunk_stream(5) + |> Enum.reduce({[], 0}, fn %User{} = user, {acc, count} -> + {acc ++ [user], count + 1} + end) + + assert users == fetch_users + end + + test "fetch records in bulk" do + users = insert_list(50, :user) + + {fetch_users, 10} = + from(t in User) + |> Repo.chunk_stream(5, :batches) + |> Enum.reduce({[], 0}, fn users, {acc, count} -> + {acc ++ users, count + 1} + end) + + assert users == fetch_users + end + end end diff --git a/test/report_note_test.exs b/test/pleroma/report_note_test.exs index 25c1d6a61..2620560a0 100644 --- a/test/report_note_test.exs +++ b/test/pleroma/report_note_test.exs @@ -1,10 +1,10 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.ReportNoteTest do alias Pleroma.ReportNote - use Pleroma.DataCase + use Pleroma.DataCase, async: true import Pleroma.Factory test "create/3" do diff --git a/test/reverse_proxy/reverse_proxy_test.exs b/test/pleroma/reverse_proxy_test.exs index 8df63de65..a4dd8e99a 100644 --- a/test/reverse_proxy/reverse_proxy_test.exs +++ b/test/pleroma/reverse_proxy_test.exs @@ -1,10 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.ReverseProxyTest do - use Pleroma.Web.ConnCase, async: true - + use Pleroma.Web.ConnCase import ExUnit.CaptureLog import Mox @@ -19,24 +18,23 @@ defmodule Pleroma.ReverseProxyTest do setup :verify_on_exit! - defp user_agent_mock(user_agent, invokes) do - json = Jason.encode!(%{"user-agent": user_agent}) - + defp request_mock(invokes) do ClientMock - |> expect(:request, fn :get, url, _, _, _ -> + |> expect(:request, fn :get, url, headers, _body, _opts -> Registry.register(ClientMock, url, 0) + body = headers |> Enum.into(%{}) |> Jason.encode!() {:ok, 200, [ {"content-type", "application/json"}, - {"content-length", byte_size(json) |> to_string()} - ], %{url: url}} + {"content-length", byte_size(body) |> to_string()} + ], %{url: url, body: body}} end) - |> expect(:stream_body, invokes, fn %{url: url} = client -> + |> expect(:stream_body, invokes, fn %{url: url, body: body} = client -> case Registry.lookup(ClientMock, url) do [{_, 0}] -> Registry.update_value(ClientMock, url, &(&1 + 1)) - {:ok, json, client} + {:ok, body, client} [{_, 1}] -> Registry.unregister(ClientMock, url) @@ -47,7 +45,7 @@ defmodule Pleroma.ReverseProxyTest do describe "reverse proxy" do test "do not track successful request", %{conn: conn} do - user_agent_mock("hackney/1.15.1", 2) + request_mock(2) url = "/success" conn = ReverseProxy.call(conn, url) @@ -57,18 +55,15 @@ defmodule Pleroma.ReverseProxyTest do end end - describe "user-agent" do - test "don't keep", %{conn: conn} do - user_agent_mock("hackney/1.15.1", 2) - conn = ReverseProxy.call(conn, "/user-agent") - assert json_response(conn, 200) == %{"user-agent" => "hackney/1.15.1"} - end + test "use Pleroma's user agent in the request; don't pass the client's", %{conn: conn} do + request_mock(2) - test "keep", %{conn: conn} do - user_agent_mock(Pleroma.Application.user_agent(), 2) - conn = ReverseProxy.call(conn, "/user-agent-keep", keep_user_agent: true) - assert json_response(conn, 200) == %{"user-agent" => Pleroma.Application.user_agent()} - end + conn = + conn + |> Plug.Conn.put_req_header("user-agent", "fake/1.0") + |> ReverseProxy.call("/user-agent") + + assert json_response(conn, 200) == %{"user-agent" => Pleroma.Application.user_agent()} end test "closed connection", %{conn: conn} do @@ -115,7 +110,7 @@ defmodule Pleroma.ReverseProxyTest do describe "max_body" do test "length returns error if content-length more than option", %{conn: conn} do - user_agent_mock("hackney/1.15.1", 0) + request_mock(0) assert capture_log(fn -> ReverseProxy.call(conn, "/huge-file", max_body_length: 4) diff --git a/test/runtime_test.exs b/test/pleroma/runtime_test.exs index a1a6c57cd..b9e769602 100644 --- a/test/runtime_test.exs +++ b/test/pleroma/runtime_test.exs @@ -1,11 +1,12 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.RuntimeTest do use ExUnit.Case, async: true test "it loads custom runtime modules" do - assert {:module, RuntimeModule} == Code.ensure_compiled(RuntimeModule) + assert {:module, Fixtures.Modules.RuntimeModule} == + Code.ensure_compiled(Fixtures.Modules.RuntimeModule) end end diff --git a/test/safe_jsonb_set_test.exs b/test/pleroma/safe_jsonb_set_test.exs index 748540570..69d696c1b 100644 --- a/test/safe_jsonb_set_test.exs +++ b/test/pleroma/safe_jsonb_set_test.exs @@ -1,5 +1,9 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + defmodule Pleroma.SafeJsonbSetTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true test "it doesn't wipe the object when asked to set the value to NULL" do assert %{rows: [[%{"key" => "value", "test" => nil}]]} = diff --git a/test/scheduled_activity_test.exs b/test/pleroma/scheduled_activity_test.exs index 7faa5660d..ef91e9bce 100644 --- a/test/scheduled_activity_test.exs +++ b/test/pleroma/scheduled_activity_test.exs @@ -1,22 +1,21 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.ScheduledActivityTest do use Pleroma.DataCase - alias Pleroma.DataCase + alias Pleroma.ScheduledActivity + import Pleroma.Factory setup do: clear_config([ScheduledActivity, :enabled]) - setup context do - DataCase.ensure_local_uploader(context) - end + setup [:ensure_local_uploader] describe "creation" do test "scheduled activities with jobs when ScheduledActivity enabled" do - Pleroma.Config.put([ScheduledActivity, :enabled], true) + clear_config([ScheduledActivity, :enabled], true) user = insert(:user) today = @@ -35,7 +34,7 @@ defmodule Pleroma.ScheduledActivityTest do end test "scheduled activities without jobs when ScheduledActivity disabled" do - Pleroma.Config.put([ScheduledActivity, :enabled], false) + clear_config([ScheduledActivity, :enabled], false) user = insert(:user) today = diff --git a/test/signature_test.exs b/test/pleroma/signature_test.exs index a7a75aa4d..047c537e0 100644 --- a/test/signature_test.exs +++ b/test/pleroma/signature_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.SignatureTest do diff --git a/test/stats_test.exs b/test/pleroma/stats_test.exs index f09d8d31a..fd3195969 100644 --- a/test/stats_test.exs +++ b/test/pleroma/stats_test.exs @@ -1,10 +1,13 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.StatsTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true + import Pleroma.Factory + + alias Pleroma.Stats alias Pleroma.Web.CommonAPI describe "user count" do @@ -13,7 +16,7 @@ defmodule Pleroma.StatsTest do _internal = insert(:user, local: true, nickname: nil) _internal = Pleroma.Web.ActivityPub.Relay.get_actor() - assert match?(%{stats: %{user_count: 1}}, Pleroma.Stats.calculate_stat_data()) + assert match?(%{stats: %{user_count: 1}}, Stats.calculate_stat_data()) end end @@ -47,23 +50,23 @@ defmodule Pleroma.StatsTest do end) assert %{"direct" => 3, "private" => 4, "public" => 1, "unlisted" => 2} = - Pleroma.Stats.get_status_visibility_count() + Stats.get_status_visibility_count() end test "on status delete" do user = insert(:user) {:ok, activity} = CommonAPI.post(user, %{visibility: "public", status: "hey"}) - assert %{"public" => 1} = Pleroma.Stats.get_status_visibility_count() + assert %{"public" => 1} = Stats.get_status_visibility_count() CommonAPI.delete(activity.id, user) - assert %{"public" => 0} = Pleroma.Stats.get_status_visibility_count() + assert %{"public" => 0} = Stats.get_status_visibility_count() end test "on status visibility update" do user = insert(:user) {:ok, activity} = CommonAPI.post(user, %{visibility: "public", status: "hey"}) - assert %{"public" => 1, "private" => 0} = Pleroma.Stats.get_status_visibility_count() + assert %{"public" => 1, "private" => 0} = Stats.get_status_visibility_count() {:ok, _} = CommonAPI.update_activity_scope(activity.id, %{visibility: "private"}) - assert %{"public" => 0, "private" => 1} = Pleroma.Stats.get_status_visibility_count() + assert %{"public" => 0, "private" => 1} = Stats.get_status_visibility_count() end test "doesn't count unrelated activities" do @@ -75,7 +78,7 @@ defmodule Pleroma.StatsTest do CommonAPI.repeat(activity.id, other_user) assert %{"direct" => 0, "private" => 0, "public" => 1, "unlisted" => 0} = - Pleroma.Stats.get_status_visibility_count() + Stats.get_status_visibility_count() end end @@ -110,10 +113,10 @@ defmodule Pleroma.StatsTest do end) assert %{"direct" => 10, "private" => 0, "public" => 1, "unlisted" => 5} = - Pleroma.Stats.get_status_visibility_count(local_instance) + Stats.get_status_visibility_count(local_instance) assert %{"direct" => 0, "private" => 20, "public" => 0, "unlisted" => 0} = - Pleroma.Stats.get_status_visibility_count(instance2) + Stats.get_status_visibility_count(instance2) end end end diff --git a/test/pleroma/upload/filter/analyze_metadata_test.exs b/test/pleroma/upload/filter/analyze_metadata_test.exs new file mode 100644 index 000000000..4b636a684 --- /dev/null +++ b/test/pleroma/upload/filter/analyze_metadata_test.exs @@ -0,0 +1,33 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Upload.Filter.AnalyzeMetadataTest do + use Pleroma.DataCase, async: true + alias Pleroma.Upload.Filter.AnalyzeMetadata + + test "adds the dimensions and blurhash for images" do + upload = %Pleroma.Upload{ + name: "an… image.jpg", + content_type: "image/jpeg", + path: Path.absname("test/fixtures/image.jpg"), + tempfile: Path.absname("test/fixtures/image.jpg") + } + + {:ok, :filtered, meta} = AnalyzeMetadata.filter(upload) + + assert %{width: 1024, height: 768} = meta + assert meta.blurhash + end + + test "adds the dimensions for videos" do + upload = %Pleroma.Upload{ + name: "coolvideo.mp4", + content_type: "video/mp4", + path: Path.absname("test/fixtures/video.mp4"), + tempfile: Path.absname("test/fixtures/video.mp4") + } + + assert {:ok, :filtered, %{width: 480, height: 480}} = AnalyzeMetadata.filter(upload) + end +end diff --git a/test/upload/filter/anonymize_filename_test.exs b/test/pleroma/upload/filter/anonymize_filename_test.exs index adff70f57..9387c1abc 100644 --- a/test/upload/filter/anonymize_filename_test.exs +++ b/test/pleroma/upload/filter/anonymize_filename_test.exs @@ -1,11 +1,10 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Upload.Filter.AnonymizeFilenameTest do use Pleroma.DataCase - alias Pleroma.Config alias Pleroma.Upload setup do @@ -13,7 +12,7 @@ defmodule Pleroma.Upload.Filter.AnonymizeFilenameTest do upload_file = %Upload{ name: "an… image.jpg", - content_type: "image/jpg", + content_type: "image/jpeg", path: Path.absname("test/fixtures/image_tmp.jpg") } @@ -23,19 +22,19 @@ defmodule Pleroma.Upload.Filter.AnonymizeFilenameTest do setup do: clear_config([Pleroma.Upload.Filter.AnonymizeFilename, :text]) test "it replaces filename on pre-defined text", %{upload_file: upload_file} do - Config.put([Upload.Filter.AnonymizeFilename, :text], "custom-file.png") - {:ok, %Upload{name: name}} = Upload.Filter.AnonymizeFilename.filter(upload_file) + clear_config([Upload.Filter.AnonymizeFilename, :text], "custom-file.png") + {:ok, :filtered, %Upload{name: name}} = Upload.Filter.AnonymizeFilename.filter(upload_file) assert name == "custom-file.png" end test "it replaces filename on pre-defined text expression", %{upload_file: upload_file} do - Config.put([Upload.Filter.AnonymizeFilename, :text], "custom-file.{extension}") - {:ok, %Upload{name: name}} = Upload.Filter.AnonymizeFilename.filter(upload_file) + clear_config([Upload.Filter.AnonymizeFilename, :text], "custom-file.{extension}") + {:ok, :filtered, %Upload{name: name}} = Upload.Filter.AnonymizeFilename.filter(upload_file) assert name == "custom-file.jpg" end test "it replaces filename on random text", %{upload_file: upload_file} do - {:ok, %Upload{name: name}} = Upload.Filter.AnonymizeFilename.filter(upload_file) + {:ok, :filtered, %Upload{name: name}} = Upload.Filter.AnonymizeFilename.filter(upload_file) assert <<_::bytes-size(14)>> <> ".jpg" = name refute name == "an… image.jpg" end diff --git a/test/upload/filter/dedupe_test.exs b/test/pleroma/upload/filter/dedupe_test.exs index 966c353f7..f00ba12f9 100644 --- a/test/upload/filter/dedupe_test.exs +++ b/test/pleroma/upload/filter/dedupe_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Upload.Filter.DedupeTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true alias Pleroma.Upload alias Pleroma.Upload.Filter.Dedupe @@ -18,13 +18,14 @@ defmodule Pleroma.Upload.Filter.DedupeTest do upload = %Upload{ name: "an… image.jpg", - content_type: "image/jpg", + content_type: "image/jpeg", path: Path.absname("test/fixtures/image_tmp.jpg"), tempfile: Path.absname("test/fixtures/image_tmp.jpg") } assert { :ok, + :filtered, %Pleroma.Upload{id: @shasum, path: @shasum <> ".jpg"} } = Dedupe.filter(upload) end diff --git a/test/upload/filter/exiftool_test.exs b/test/pleroma/upload/filter/exiftool_test.exs index 8ed7d650b..cfbe34be8 100644 --- a/test/upload/filter/exiftool_test.exs +++ b/test/pleroma/upload/filter/exiftool_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Upload.Filter.ExiftoolTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true alias Pleroma.Upload.Filter test "apply exiftool filter" do @@ -16,12 +16,12 @@ defmodule Pleroma.Upload.Filter.ExiftoolTest do upload = %Pleroma.Upload{ name: "image_with_GPS_data.jpg", - content_type: "image/jpg", + content_type: "image/jpeg", path: Path.absname("test/fixtures/DSCN0010.jpg"), tempfile: Path.absname("test/fixtures/DSCN0010_tmp.jpg") } - assert Filter.Exiftool.filter(upload) == :ok + assert Filter.Exiftool.filter(upload) == {:ok, :filtered} {exif_original, 0} = System.cmd("exiftool", ["test/fixtures/DSCN0010.jpg"]) {exif_filtered, 0} = System.cmd("exiftool", ["test/fixtures/DSCN0010_tmp.jpg"]) @@ -30,4 +30,13 @@ defmodule Pleroma.Upload.Filter.ExiftoolTest do assert String.match?(exif_original, ~r/GPS/) refute String.match?(exif_filtered, ~r/GPS/) end + + test "verify webp files are skipped" do + upload = %Pleroma.Upload{ + name: "sample.webp", + content_type: "image/webp" + } + + assert Filter.Exiftool.filter(upload) == {:ok, :noop} + end end diff --git a/test/upload/filter/mogrifun_test.exs b/test/pleroma/upload/filter/mogrifun_test.exs index 2426a8496..d2b183e90 100644 --- a/test/upload/filter/mogrifun_test.exs +++ b/test/pleroma/upload/filter/mogrifun_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Upload.Filter.MogrifunTest do @@ -17,7 +17,7 @@ defmodule Pleroma.Upload.Filter.MogrifunTest do upload = %Upload{ name: "an… image.jpg", - content_type: "image/jpg", + content_type: "image/jpeg", path: Path.absname("test/fixtures/image_tmp.jpg"), tempfile: Path.absname("test/fixtures/image_tmp.jpg") } @@ -36,7 +36,7 @@ defmodule Pleroma.Upload.Filter.MogrifunTest do save: fn _f, _o -> :ok end ]} ]) do - assert Filter.Mogrifun.filter(upload) == :ok + assert Filter.Mogrifun.filter(upload) == {:ok, :filtered} end Task.await(task) diff --git a/test/upload/filter/mogrify_test.exs b/test/pleroma/upload/filter/mogrify_test.exs index 62ca30487..d62cd83b4 100644 --- a/test/upload/filter/mogrify_test.exs +++ b/test/pleroma/upload/filter/mogrify_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Upload.Filter.MogrifyTest do @@ -18,7 +18,7 @@ defmodule Pleroma.Upload.Filter.MogrifyTest do upload = %Pleroma.Upload{ name: "an… image.jpg", - content_type: "image/jpg", + content_type: "image/jpeg", path: Path.absname("test/fixtures/image_tmp.jpg"), tempfile: Path.absname("test/fixtures/image_tmp.jpg") } @@ -33,7 +33,7 @@ defmodule Pleroma.Upload.Filter.MogrifyTest do custom: fn _m, _a -> :ok end, custom: fn m, a, o -> send(task.pid, {:apply_filter, {m, a, o}}) end, save: fn _f, _o -> :ok end do - assert Filter.Mogrify.filter(upload) == :ok + assert Filter.Mogrify.filter(upload) == {:ok, :filtered} end Task.await(task) diff --git a/test/upload/filter_test.exs b/test/pleroma/upload/filter_test.exs index 352b66402..f0053ed9b 100644 --- a/test/upload/filter_test.exs +++ b/test/pleroma/upload/filter_test.exs @@ -1,17 +1,16 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Upload.FilterTest do use Pleroma.DataCase - alias Pleroma.Config alias Pleroma.Upload.Filter setup do: clear_config([Pleroma.Upload.Filter.AnonymizeFilename, :text]) test "applies filters" do - Config.put([Pleroma.Upload.Filter.AnonymizeFilename, :text], "custom-file.png") + clear_config([Pleroma.Upload.Filter.AnonymizeFilename, :text], "custom-file.png") File.cp!( "test/fixtures/image.jpg", @@ -20,7 +19,7 @@ defmodule Pleroma.Upload.FilterTest do upload = %Pleroma.Upload{ name: "an… image.jpg", - content_type: "image/jpg", + content_type: "image/jpeg", path: Path.absname("test/fixtures/image_tmp.jpg"), tempfile: Path.absname("test/fixtures/image_tmp.jpg") } diff --git a/test/upload_test.exs b/test/pleroma/upload_test.exs index b06b54487..f1ab82a57 100644 --- a/test/upload_test.exs +++ b/test/pleroma/upload_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.UploadTest do @@ -11,7 +11,7 @@ defmodule Pleroma.UploadTest do alias Pleroma.Uploaders.Uploader @upload_file %Plug.Upload{ - content_type: "image/jpg", + content_type: "image/jpeg", path: Path.absname("test/fixtures/image_tmp.jpg"), filename: "image.jpg" } @@ -112,7 +112,7 @@ defmodule Pleroma.UploadTest do File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg") file = %Plug.Upload{ - content_type: "image/jpg", + content_type: "image/jpeg", path: Path.absname("test/fixtures/image_tmp.jpg"), filename: "image.jpg" } @@ -124,7 +124,7 @@ defmodule Pleroma.UploadTest do File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg") file = %Plug.Upload{ - content_type: "image/jpg", + content_type: "image/jpeg", path: Path.absname("test/fixtures/image_tmp.jpg"), filename: "image.jpg" } @@ -133,14 +133,14 @@ defmodule Pleroma.UploadTest do assert %{"url" => [%{"href" => url}]} = data - assert String.starts_with?(url, Pleroma.Web.base_url() <> "/media/") + assert String.starts_with?(url, Pleroma.Upload.base_url()) end test "copies the file to the configured folder with deduping" do File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg") file = %Plug.Upload{ - content_type: "image/jpg", + content_type: "image/jpeg", path: Path.absname("test/fixtures/image_tmp.jpg"), filename: "an [image.jpg" } @@ -148,15 +148,15 @@ defmodule Pleroma.UploadTest do {:ok, data} = Upload.store(file, filters: [Pleroma.Upload.Filter.Dedupe]) assert List.first(data["url"])["href"] == - Pleroma.Web.base_url() <> - "/media/e30397b58d226d6583ab5b8b3c5defb0c682bda5c31ef07a9f57c1c4986e3781.jpg" + Pleroma.Upload.base_url() <> + "e30397b58d226d6583ab5b8b3c5defb0c682bda5c31ef07a9f57c1c4986e3781.jpg" end test "copies the file to the configured folder without deduping" do File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg") file = %Plug.Upload{ - content_type: "image/jpg", + content_type: "image/jpeg", path: Path.absname("test/fixtures/image_tmp.jpg"), filename: "an [image.jpg" } @@ -165,63 +165,31 @@ defmodule Pleroma.UploadTest do assert data["name"] == "an [image.jpg" end - test "fixes incorrect content type" do - File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg") - - file = %Plug.Upload{ - content_type: "application/octet-stream", - path: Path.absname("test/fixtures/image_tmp.jpg"), - filename: "an [image.jpg" + test "fixes incorrect content type when base64 is given" do + params = %{ + img: "data:image/png;base64,#{Base.encode64(File.read!("test/fixtures/image.jpg"))}" } - {:ok, data} = Upload.store(file, filters: [Pleroma.Upload.Filter.Dedupe]) + {:ok, data} = Upload.store(params) assert hd(data["url"])["mediaType"] == "image/jpeg" end - test "adds missing extension" do + test "adds extension when base64 is given" do File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg") - file = %Plug.Upload{ - content_type: "image/jpg", - path: Path.absname("test/fixtures/image_tmp.jpg"), - filename: "an [image" + params = %{ + img: "data:image/png;base64,#{Base.encode64(File.read!("test/fixtures/image.jpg"))}" } - {:ok, data} = Upload.store(file) - assert data["name"] == "an [image.jpg" - end - - test "fixes incorrect file extension" do - File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg") - - file = %Plug.Upload{ - content_type: "image/jpg", - path: Path.absname("test/fixtures/image_tmp.jpg"), - filename: "an [image.blah" - } - - {:ok, data} = Upload.store(file) - assert data["name"] == "an [image.jpg" - end - - test "don't modify filename of an unknown type" do - File.cp("test/fixtures/test.txt", "test/fixtures/test_tmp.txt") - - file = %Plug.Upload{ - content_type: "text/plain", - path: Path.absname("test/fixtures/test_tmp.txt"), - filename: "test.txt" - } - - {:ok, data} = Upload.store(file) - assert data["name"] == "test.txt" + {:ok, data} = Upload.store(params) + assert String.ends_with?(data["name"], ".jpg") end test "copies the file to the configured folder with anonymizing filename" do File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg") file = %Plug.Upload{ - content_type: "image/jpg", + content_type: "image/jpeg", path: Path.absname("test/fixtures/image_tmp.jpg"), filename: "an [image.jpg" } @@ -235,7 +203,7 @@ defmodule Pleroma.UploadTest do File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg") file = %Plug.Upload{ - content_type: "image/jpg", + content_type: "image/jpeg", path: Path.absname("test/fixtures/image_tmp.jpg"), filename: "an… image.jpg" } @@ -250,7 +218,7 @@ defmodule Pleroma.UploadTest do File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg") file = %Plug.Upload{ - content_type: "image/jpg", + content_type: "image/jpeg", path: Path.absname("test/fixtures/image_tmp.jpg"), filename: ":?#[]@!$&\\'()*+,;=.jpg" } @@ -272,7 +240,7 @@ defmodule Pleroma.UploadTest do File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg") file = %Plug.Upload{ - content_type: "image/jpg", + content_type: "image/jpeg", path: Path.absname("test/fixtures/image_tmp.jpg"), filename: "image.jpg" } diff --git a/test/uploaders/local_test.exs b/test/pleroma/uploaders/local_test.exs index 18122ff6c..0a5952f50 100644 --- a/test/uploaders/local_test.exs +++ b/test/pleroma/uploaders/local_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Uploaders.LocalTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true alias Pleroma.Uploaders.Local describe "get_file/1" do @@ -19,7 +19,7 @@ defmodule Pleroma.Uploaders.LocalTest do file = %Pleroma.Upload{ name: "image.jpg", - content_type: "image/jpg", + content_type: "image/jpeg", path: file_path, tempfile: Path.absname("test/fixtures/image_tmp.jpg") } @@ -38,7 +38,7 @@ defmodule Pleroma.Uploaders.LocalTest do file = %Pleroma.Upload{ name: "image.jpg", - content_type: "image/jpg", + content_type: "image/jpeg", path: file_path, tempfile: Path.absname("test/fixtures/image_tmp.jpg") } diff --git a/test/uploaders/s3_test.exs b/test/pleroma/uploaders/s3_test.exs index d949c90a5..2711e2c8d 100644 --- a/test/uploaders/s3_test.exs +++ b/test/pleroma/uploaders/s3_test.exs @@ -1,21 +1,21 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Uploaders.S3Test do use Pleroma.DataCase - alias Pleroma.Config alias Pleroma.Uploaders.S3 import Mock import ExUnit.CaptureLog - setup do: - clear_config(Pleroma.Uploaders.S3, - bucket: "test_bucket", - public_endpoint: "https://s3.amazonaws.com" - ) + setup do + clear_config([Pleroma.Upload, :uploader], Pleroma.Uploaders.S3) + clear_config([Pleroma.Upload, :base_url], "https://s3.amazonaws.com") + clear_config([Pleroma.Uploaders.S3]) + clear_config([Pleroma.Uploaders.S3, :bucket], "test_bucket") + end describe "get_file/1" do test "it returns path to local folder for files" do @@ -26,12 +26,14 @@ defmodule Pleroma.Uploaders.S3Test do end test "it returns path without bucket when truncated_namespace set to ''" do - Config.put([Pleroma.Uploaders.S3], + clear_config([Pleroma.Uploaders.S3], bucket: "test_bucket", - public_endpoint: "https://s3.amazonaws.com", + bucket_namespace: "myaccount", truncated_namespace: "" ) + clear_config([Pleroma.Upload, :base_url], "https://s3.amazonaws.com") + assert S3.get_file("test_image.jpg") == { :ok, {:url, "https://s3.amazonaws.com/test_image.jpg"} @@ -39,9 +41,8 @@ defmodule Pleroma.Uploaders.S3Test do end test "it returns path with bucket namespace when namespace is set" do - Config.put([Pleroma.Uploaders.S3], + clear_config([Pleroma.Uploaders.S3], bucket: "test_bucket", - public_endpoint: "https://s3.amazonaws.com", bucket_namespace: "family" ) @@ -56,7 +57,7 @@ defmodule Pleroma.Uploaders.S3Test do setup do file_upload = %Pleroma.Upload{ name: "image-tet.jpg", - content_type: "image/jpg", + content_type: "image/jpeg", path: "test_folder/image-tet.jpg", tempfile: Path.absname("test/instance_static/add/shortcode.png") } diff --git a/test/pleroma/user/backup_test.exs b/test/pleroma/user/backup_test.exs new file mode 100644 index 000000000..b16152876 --- /dev/null +++ b/test/pleroma/user/backup_test.exs @@ -0,0 +1,238 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.User.BackupTest do + use Oban.Testing, repo: Pleroma.Repo + use Pleroma.DataCase + + import Mock + import Pleroma.Factory + import Swoosh.TestAssertions + + alias Pleroma.Bookmark + alias Pleroma.Tests.ObanHelpers + alias Pleroma.User.Backup + alias Pleroma.Web.CommonAPI + alias Pleroma.Workers.BackupWorker + + setup do + clear_config([Pleroma.Upload, :uploader]) + clear_config([Backup, :limit_days]) + clear_config([Pleroma.Emails.Mailer, :enabled], true) + end + + test "it requries enabled email" do + clear_config([Pleroma.Emails.Mailer, :enabled], false) + user = insert(:user) + assert {:error, "Backups require enabled email"} == Backup.create(user) + end + + test "it requries user's email" do + user = insert(:user, %{email: nil}) + assert {:error, "Email is required"} == Backup.create(user) + end + + test "it creates a backup record and an Oban job" do + %{id: user_id} = user = insert(:user) + assert {:ok, %Oban.Job{args: args}} = Backup.create(user) + assert_enqueued(worker: BackupWorker, args: args) + + backup = Backup.get(args["backup_id"]) + assert %Backup{user_id: ^user_id, processed: false, file_size: 0} = backup + end + + test "it return an error if the export limit is over" do + %{id: user_id} = user = insert(:user) + limit_days = Pleroma.Config.get([Backup, :limit_days]) + assert {:ok, %Oban.Job{args: args}} = Backup.create(user) + backup = Backup.get(args["backup_id"]) + assert %Backup{user_id: ^user_id, processed: false, file_size: 0} = backup + + assert Backup.create(user) == {:error, "Last export was less than #{limit_days} days ago"} + end + + test "it process a backup record" do + clear_config([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local) + %{id: user_id} = user = insert(:user) + + assert {:ok, %Oban.Job{args: %{"backup_id" => backup_id} = args}} = Backup.create(user) + assert {:ok, backup} = perform_job(BackupWorker, args) + assert backup.file_size > 0 + assert %Backup{id: ^backup_id, processed: true, user_id: ^user_id} = backup + + delete_job_args = %{"op" => "delete", "backup_id" => backup_id} + + assert_enqueued(worker: BackupWorker, args: delete_job_args) + assert {:ok, backup} = perform_job(BackupWorker, delete_job_args) + refute Backup.get(backup_id) + + email = Pleroma.Emails.UserEmail.backup_is_ready_email(backup) + + assert_email_sent( + to: {user.name, user.email}, + html_body: email.html_body + ) + end + + test "it removes outdated backups after creating a fresh one" do + clear_config([Backup, :limit_days], -1) + clear_config([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local) + user = insert(:user) + + assert {:ok, job1} = Backup.create(user) + + assert {:ok, %Backup{}} = ObanHelpers.perform(job1) + assert {:ok, job2} = Backup.create(user) + assert Pleroma.Repo.aggregate(Backup, :count) == 2 + assert {:ok, backup2} = ObanHelpers.perform(job2) + + ObanHelpers.perform_all() + + assert [^backup2] = Pleroma.Repo.all(Backup) + end + + test "it creates a zip archive with user data" do + user = insert(:user, %{nickname: "cofe", name: "Cofe", ap_id: "http://cofe.io/users/cofe"}) + + {:ok, %{object: %{data: %{"id" => id1}}} = status1} = + CommonAPI.post(user, %{status: "status1"}) + + {:ok, %{object: %{data: %{"id" => id2}}} = status2} = + CommonAPI.post(user, %{status: "status2"}) + + {:ok, %{object: %{data: %{"id" => id3}}} = status3} = + CommonAPI.post(user, %{status: "status3"}) + + CommonAPI.favorite(user, status1.id) + CommonAPI.favorite(user, status2.id) + + Bookmark.create(user.id, status2.id) + Bookmark.create(user.id, status3.id) + + assert {:ok, backup} = user |> Backup.new() |> Repo.insert() + assert {:ok, path} = Backup.export(backup) + assert {:ok, zipfile} = :zip.zip_open(String.to_charlist(path), [:memory]) + assert {:ok, {'actor.json', json}} = :zip.zip_get('actor.json', zipfile) + + assert %{ + "@context" => [ + "https://www.w3.org/ns/activitystreams", + "http://localhost:4001/schemas/litepub-0.1.jsonld", + %{"@language" => "und"} + ], + "bookmarks" => "bookmarks.json", + "followers" => "http://cofe.io/users/cofe/followers", + "following" => "http://cofe.io/users/cofe/following", + "id" => "http://cofe.io/users/cofe", + "inbox" => "http://cofe.io/users/cofe/inbox", + "likes" => "likes.json", + "name" => "Cofe", + "outbox" => "http://cofe.io/users/cofe/outbox", + "preferredUsername" => "cofe", + "publicKey" => %{ + "id" => "http://cofe.io/users/cofe#main-key", + "owner" => "http://cofe.io/users/cofe" + }, + "type" => "Person", + "url" => "http://cofe.io/users/cofe" + } = Jason.decode!(json) + + assert {:ok, {'outbox.json', json}} = :zip.zip_get('outbox.json', zipfile) + + assert %{ + "@context" => "https://www.w3.org/ns/activitystreams", + "id" => "outbox.json", + "orderedItems" => [ + %{ + "object" => %{ + "actor" => "http://cofe.io/users/cofe", + "content" => "status1", + "type" => "Note" + }, + "type" => "Create" + }, + %{ + "object" => %{ + "actor" => "http://cofe.io/users/cofe", + "content" => "status2" + } + }, + %{ + "actor" => "http://cofe.io/users/cofe", + "object" => %{ + "content" => "status3" + } + } + ], + "totalItems" => 3, + "type" => "OrderedCollection" + } = Jason.decode!(json) + + assert {:ok, {'likes.json', json}} = :zip.zip_get('likes.json', zipfile) + + assert %{ + "@context" => "https://www.w3.org/ns/activitystreams", + "id" => "likes.json", + "orderedItems" => [^id1, ^id2], + "totalItems" => 2, + "type" => "OrderedCollection" + } = Jason.decode!(json) + + assert {:ok, {'bookmarks.json', json}} = :zip.zip_get('bookmarks.json', zipfile) + + assert %{ + "@context" => "https://www.w3.org/ns/activitystreams", + "id" => "bookmarks.json", + "orderedItems" => [^id2, ^id3], + "totalItems" => 2, + "type" => "OrderedCollection" + } = Jason.decode!(json) + + :zip.zip_close(zipfile) + File.rm!(path) + end + + describe "it uploads and deletes a backup archive" do + setup do + clear_config([Pleroma.Upload, :base_url], "https://s3.amazonaws.com") + clear_config([Pleroma.Uploaders.S3, :bucket], "test_bucket") + + user = insert(:user, %{nickname: "cofe", name: "Cofe", ap_id: "http://cofe.io/users/cofe"}) + + {:ok, status1} = CommonAPI.post(user, %{status: "status1"}) + {:ok, status2} = CommonAPI.post(user, %{status: "status2"}) + {:ok, status3} = CommonAPI.post(user, %{status: "status3"}) + CommonAPI.favorite(user, status1.id) + CommonAPI.favorite(user, status2.id) + Bookmark.create(user.id, status2.id) + Bookmark.create(user.id, status3.id) + + assert {:ok, backup} = user |> Backup.new() |> Repo.insert() + assert {:ok, path} = Backup.export(backup) + + [path: path, backup: backup] + end + + test "S3", %{path: path, backup: backup} do + clear_config([Pleroma.Upload, :uploader], Pleroma.Uploaders.S3) + clear_config([Pleroma.Uploaders.S3, :streaming_enabled], false) + + with_mock ExAws, + request: fn + %{http_method: :put} -> {:ok, :ok} + %{http_method: :delete} -> {:ok, %{status_code: 204}} + end do + assert {:ok, %Pleroma.Upload{}} = Backup.upload(backup, path) + assert {:ok, _backup} = Backup.delete(backup) + end + end + + test "Local", %{path: path, backup: backup} do + clear_config([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local) + + assert {:ok, %Pleroma.Upload{}} = Backup.upload(backup, path) + assert {:ok, _backup} = Backup.delete(backup) + end + end +end diff --git a/test/pleroma/user/import_test.exs b/test/pleroma/user/import_test.exs new file mode 100644 index 000000000..a84fce337 --- /dev/null +++ b/test/pleroma/user/import_test.exs @@ -0,0 +1,76 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.User.ImportTest do + alias Pleroma.Repo + alias Pleroma.Tests.ObanHelpers + alias Pleroma.User + + use Pleroma.DataCase + use Oban.Testing, repo: Pleroma.Repo + + import Pleroma.Factory + + setup_all do + Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) + :ok + end + + describe "follow_import" do + test "it imports user followings from list" do + [user1, user2, user3] = insert_list(3, :user) + + identifiers = [ + user2.ap_id, + user3.nickname + ] + + {:ok, job} = User.Import.follow_import(user1, identifiers) + + assert {:ok, result} = ObanHelpers.perform(job) + assert is_list(result) + assert result == [refresh_record(user2), refresh_record(user3)] + assert User.following?(user1, user2) + assert User.following?(user1, user3) + end + end + + describe "blocks_import" do + test "it imports user blocks from list" do + [user1, user2, user3] = insert_list(3, :user) + + identifiers = [ + user2.ap_id, + user3.nickname + ] + + {:ok, job} = User.Import.blocks_import(user1, identifiers) + + assert {:ok, result} = ObanHelpers.perform(job) + assert is_list(result) + assert result == [user2, user3] + assert User.blocks?(user1, user2) + assert User.blocks?(user1, user3) + end + end + + describe "mutes_import" do + test "it imports user mutes from list" do + [user1, user2, user3] = insert_list(3, :user) + + identifiers = [ + user2.ap_id, + user3.nickname + ] + + {:ok, job} = User.Import.mutes_import(user1, identifiers) + + assert {:ok, result} = ObanHelpers.perform(job) + assert is_list(result) + assert result == [user2, user3] + assert User.mutes?(user1, user2) + assert User.mutes?(user1, user3) + end + end +end diff --git a/test/user/notification_setting_test.exs b/test/pleroma/user/notification_setting_test.exs index 308da216a..6cb8803d9 100644 --- a/test/user/notification_setting_test.exs +++ b/test/pleroma/user/notification_setting_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.User.NotificationSettingTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true alias Pleroma.User.NotificationSetting diff --git a/test/pleroma/user/query_test.exs b/test/pleroma/user/query_test.exs new file mode 100644 index 000000000..363da7665 --- /dev/null +++ b/test/pleroma/user/query_test.exs @@ -0,0 +1,47 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.User.QueryTest do + use Pleroma.DataCase, async: true + + alias Pleroma.Repo + alias Pleroma.User + alias Pleroma.User.Query + alias Pleroma.Web.ActivityPub.InternalFetchActor + + import Pleroma.Factory + + describe "internal users" do + test "it filters out internal users by default" do + %User{nickname: "internal.fetch"} = InternalFetchActor.get_actor() + + assert [_user] = User |> Repo.all() + assert [] == %{} |> Query.build() |> Repo.all() + end + + test "it filters out users without nickname by default" do + insert(:user, %{nickname: nil}) + + assert [_user] = User |> Repo.all() + assert [] == %{} |> Query.build() |> Repo.all() + end + + test "it returns internal users when enabled" do + %User{nickname: "internal.fetch"} = InternalFetchActor.get_actor() + insert(:user, %{nickname: nil}) + + assert %{internal: true} |> Query.build() |> Repo.aggregate(:count) == 2 + end + end + + test "is_suggested param" do + _user1 = insert(:user, is_suggested: false) + user2 = insert(:user, is_suggested: true) + + assert [^user2] = + %{is_suggested: true} + |> User.Query.build() + |> Repo.all() + end +end diff --git a/test/user/welcome_chat_massage_test.exs b/test/pleroma/user/welcome_chat_message_test.exs index fe26d6e4d..42a45fa19 100644 --- a/test/user/welcome_chat_massage_test.exs +++ b/test/pleroma/user/welcome_chat_message_test.exs @@ -1,11 +1,10 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.User.WelcomeChatMessageTest do use Pleroma.DataCase - alias Pleroma.Config alias Pleroma.User.WelcomeChatMessage import Pleroma.Factory @@ -17,10 +16,10 @@ defmodule Pleroma.User.WelcomeChatMessageTest do welcome_user = insert(:user, name: "mewmew") user = insert(:user) - Config.put([:welcome, :chat_message, :enabled], true) - Config.put([:welcome, :chat_message, :sender_nickname], welcome_user.nickname) + clear_config([:welcome, :chat_message, :enabled], true) + clear_config([:welcome, :chat_message, :sender_nickname], welcome_user.nickname) - Config.put( + clear_config( [:welcome, :chat_message, :message], "Hello, welcome to Blob/Cat!" ) @@ -28,8 +27,10 @@ defmodule Pleroma.User.WelcomeChatMessageTest do {:ok, %Pleroma.Activity{} = activity} = WelcomeChatMessage.post_message(user) assert user.ap_id in activity.recipients - assert Pleroma.Object.normalize(activity).data["type"] == "ChatMessage" - assert Pleroma.Object.normalize(activity).data["content"] == "Hello, welcome to Blob/Cat!" + assert Pleroma.Object.normalize(activity, fetch: false).data["type"] == "ChatMessage" + + assert Pleroma.Object.normalize(activity, fetch: false).data["content"] == + "Hello, welcome to Blob/Cat!" end end end diff --git a/test/user/welcome_email_test.exs b/test/pleroma/user/welcome_email_test.exs index d005d11b2..c3d383a7f 100644 --- a/test/user/welcome_email_test.exs +++ b/test/pleroma/user/welcome_email_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.User.WelcomeEmailTest do @@ -18,15 +18,15 @@ defmodule Pleroma.User.WelcomeEmailTest do test "send a welcome email" do user = insert(:user, name: "Jimm") - Config.put([:welcome, :email, :enabled], true) - Config.put([:welcome, :email, :sender], "welcome@pleroma.app") + clear_config([:welcome, :email, :enabled], true) + clear_config([:welcome, :email, :sender], "welcome@pleroma.app") - Config.put( + clear_config( [:welcome, :email, :subject], "Hello, welcome to pleroma: <%= instance_name %>" ) - Config.put( + clear_config( [:welcome, :email, :html], "<h1>Hello <%= user.name %>.</h1> <p>Welcome to <%= instance_name %></p>" ) @@ -44,7 +44,7 @@ defmodule Pleroma.User.WelcomeEmailTest do html_body: "<h1>Hello #{user.name}.</h1> <p>Welcome to #{instance_name}</p>" ) - Config.put([:welcome, :email, :sender], {"Pleroma App", "welcome@pleroma.app"}) + clear_config([:welcome, :email, :sender], {"Pleroma App", "welcome@pleroma.app"}) {:ok, _job} = WelcomeEmail.send_email(user) diff --git a/test/user/welcome_message_test.exs b/test/pleroma/user/welcome_message_test.exs index 3cd6f5cb7..28afde943 100644 --- a/test/user/welcome_message_test.exs +++ b/test/pleroma/user/welcome_message_test.exs @@ -1,11 +1,10 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.User.WelcomeMessageTest do use Pleroma.DataCase - alias Pleroma.Config alias Pleroma.User.WelcomeMessage import Pleroma.Factory @@ -17,10 +16,10 @@ defmodule Pleroma.User.WelcomeMessageTest do welcome_user = insert(:user) user = insert(:user, name: "Jimm") - Config.put([:welcome, :direct_message, :enabled], true) - Config.put([:welcome, :direct_message, :sender_nickname], welcome_user.nickname) + clear_config([:welcome, :direct_message, :enabled], true) + clear_config([:welcome, :direct_message, :sender_nickname], welcome_user.nickname) - Config.put( + clear_config( [:welcome, :direct_message, :message], "Hello. Welcome to Pleroma" ) @@ -28,7 +27,9 @@ defmodule Pleroma.User.WelcomeMessageTest do {:ok, %Pleroma.Activity{} = activity} = WelcomeMessage.post_message(user) assert user.ap_id in activity.recipients assert activity.data["directMessage"] == true - assert Pleroma.Object.normalize(activity).data["content"] =~ "Hello. Welcome to Pleroma" + + assert Pleroma.Object.normalize(activity, fetch: false).data["content"] =~ + "Hello. Welcome to Pleroma" end end end diff --git a/test/user_invite_token_test.exs b/test/pleroma/user_invite_token_test.exs index 63f18f13c..233d4e864 100644 --- a/test/user_invite_token_test.exs +++ b/test/pleroma/user_invite_token_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.UserInviteTokenTest do diff --git a/test/user_relationship_test.exs b/test/pleroma/user_relationship_test.exs index f12406097..b2b074607 100644 --- a/test/user_relationship_test.exs +++ b/test/pleroma/user_relationship_test.exs @@ -1,11 +1,11 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.UserRelationshipTest do alias Pleroma.UserRelationship - use Pleroma.DataCase + use Pleroma.DataCase, async: true import Pleroma.Factory diff --git a/test/user_search_test.exs b/test/pleroma/user_search_test.exs index 01976bf58..69167bb0c 100644 --- a/test/user_search_test.exs +++ b/test/pleroma/user_search_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.UserSearchTest do @@ -17,6 +17,46 @@ defmodule Pleroma.UserSearchTest do describe "User.search" do setup do: clear_config([:instance, :limit_to_local_content]) + test "returns a resolved user as the first result" do + clear_config([:instance, :limit_to_local_content], false) + user = insert(:user, %{nickname: "no_relation", ap_id: "https://lain.com/users/lain"}) + _user = insert(:user, %{nickname: "com_user"}) + + [first_user, _second_user] = User.search("https://lain.com/users/lain", resolve: true) + + assert first_user.id == user.id + end + + test "returns a user with matching ap_id as the first result" do + user = insert(:user, %{nickname: "no_relation", ap_id: "https://lain.com/users/lain"}) + _user = insert(:user, %{nickname: "com_user"}) + + [first_user, _second_user] = User.search("https://lain.com/users/lain") + + assert first_user.id == user.id + end + + test "doesn't die if two users have the same uri" do + insert(:user, %{uri: "https://gensokyo.2hu/@raymoo"}) + insert(:user, %{uri: "https://gensokyo.2hu/@raymoo"}) + assert [_first_user, _second_user] = User.search("https://gensokyo.2hu/@raymoo") + end + + test "returns a user with matching uri as the first result" do + user = + insert(:user, %{ + nickname: "no_relation", + ap_id: "https://lain.com/users/lain", + uri: "https://lain.com/@lain" + }) + + _user = insert(:user, %{nickname: "com_user"}) + + [first_user, _second_user] = User.search("https://lain.com/@lain") + + assert first_user.id == user.id + end + test "excludes invisible users from results" do user = insert(:user, %{nickname: "john t1000"}) insert(:user, %{invisible: true, nickname: "john t800"}) @@ -25,6 +65,15 @@ defmodule Pleroma.UserSearchTest do assert found_user.id == user.id end + # Note: as in Mastodon, `is_discoverable` doesn't anyhow relate to user searchability + test "includes non-discoverable users in results" do + insert(:user, %{nickname: "john 3000", is_discoverable: false}) + insert(:user, %{nickname: "john 3001"}) + + users = User.search("john") + assert Enum.count(users) == 2 + end + test "excludes service actors from results" do insert(:user, actor_type: "Application", nickname: "user1") service = insert(:user, actor_type: "Service", nickname: "user2") @@ -102,8 +151,8 @@ defmodule Pleroma.UserSearchTest do follower = insert(:user, %{name: "Doe"}) friend = insert(:user, %{name: "Doe"}) - {:ok, follower} = User.follow(follower, u1) - {:ok, u1} = User.follow(u1, friend) + {:ok, follower, u1} = User.follow(follower, u1) + {:ok, u1, friend} = User.follow(u1, friend) assert [friend.id, follower.id, u2.id] -- Enum.map(User.search("doe", resolve: false, for_user: u1), & &1.id) == [] @@ -116,9 +165,9 @@ defmodule Pleroma.UserSearchTest do following_jimi = insert(:user, %{name: "Lizz Wright"}) follower_lizz = insert(:user, %{name: "Jimi"}) - {:ok, lizz} = User.follow(lizz, following_lizz) - {:ok, _jimi} = User.follow(jimi, following_jimi) - {:ok, _follower_lizz} = User.follow(follower_lizz, lizz) + {:ok, lizz, following_lizz} = User.follow(lizz, following_lizz) + {:ok, _jimi, _following_jimi} = User.follow(jimi, following_jimi) + {:ok, _follower_lizz, _lizz} = User.follow(follower_lizz, lizz) assert Enum.map(User.search("jimi", following: true, for_user: lizz), & &1.id) == [ following_lizz.id @@ -150,7 +199,7 @@ defmodule Pleroma.UserSearchTest do end test "find only local users for authenticated users when `limit_to_local_content` is `:all`" do - Pleroma.Config.put([:instance, :limit_to_local_content], :all) + clear_config([:instance, :limit_to_local_content], :all) %{id: id} = insert(:user, %{name: "lain"}) insert(:user, %{name: "ebn", nickname: "lain@mastodon.social", local: false}) @@ -160,7 +209,7 @@ defmodule Pleroma.UserSearchTest do end test "find all users for unauthenticated users when `limit_to_local_content` is `false`" do - Pleroma.Config.put([:instance, :limit_to_local_content], false) + clear_config([:instance, :limit_to_local_content], false) u1 = insert(:user, %{name: "lain"}) u2 = insert(:user, %{name: "ebn", nickname: "lain@mastodon.social", local: false}) diff --git a/test/user_test.exs b/test/pleroma/user_test.exs index 50f72549e..6cd93c34c 100644 --- a/test/user_test.exs +++ b/test/pleroma/user_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.UserTest do @@ -151,7 +151,7 @@ defmodule Pleroma.UserTest do test "ap_id returns the activity pub id for the user" do user = UserBuilder.build() - expected_ap_id = "#{Pleroma.Web.base_url()}/users/#{user.nickname}" + expected_ap_id = "#{Pleroma.Web.Endpoint.url()}/users/#{user.nickname}" assert expected_ap_id == User.ap_id(user) end @@ -174,7 +174,7 @@ defmodule Pleroma.UserTest do test "returns all pending follow requests" do unlocked = insert(:user) - locked = insert(:user, locked: true) + locked = insert(:user, is_locked: true) follower = insert(:user) CommonAPI.follow(follower, unlocked) @@ -187,7 +187,7 @@ defmodule Pleroma.UserTest do end test "doesn't return already accepted or duplicate follow requests" do - locked = insert(:user, locked: true) + locked = insert(:user, is_locked: true) pending_follower = insert(:user) accepted_follower = insert(:user) @@ -201,17 +201,17 @@ defmodule Pleroma.UserTest do end test "doesn't return follow requests for deactivated accounts" do - locked = insert(:user, locked: true) - pending_follower = insert(:user, %{deactivated: true}) + locked = insert(:user, is_locked: true) + pending_follower = insert(:user, %{is_active: false}) CommonAPI.follow(pending_follower, locked) - assert true == pending_follower.deactivated + refute pending_follower.is_active assert [] = User.get_follow_requests(locked) end test "clears follow requests when requester is blocked" do - followed = insert(:user, locked: true) + followed = insert(:user, is_locked: true) follower = insert(:user) CommonAPI.follow(follower, followed) @@ -233,7 +233,7 @@ defmodule Pleroma.UserTest do {:ok, _user_relationship} = User.block(user, blocked) {:ok, _user_relationship} = User.block(reverse_blocked, user) - {:ok, user} = User.follow(user, followed_zero) + {:ok, user, followed_zero} = User.follow(user, followed_zero) {:ok, user} = User.follow_all(user, [followed_one, followed_two, blocked, reverse_blocked]) @@ -262,7 +262,7 @@ defmodule Pleroma.UserTest do user = insert(:user) followed = insert(:user) - {:ok, user} = User.follow(user, followed) + {:ok, user, followed} = User.follow(user, followed) user = User.get_cached_by_id(user.id) followed = User.get_cached_by_ap_id(followed.ap_id) @@ -275,7 +275,7 @@ defmodule Pleroma.UserTest do test "can't follow a deactivated users" do user = insert(:user) - followed = insert(:user, %{deactivated: true}) + followed = insert(:user, %{is_active: false}) {:error, _} = User.follow(user, followed) end @@ -299,10 +299,10 @@ defmodule Pleroma.UserTest do end test "local users do not automatically follow local locked accounts" do - follower = insert(:user, locked: true) - followed = insert(:user, locked: true) + follower = insert(:user, is_locked: true) + followed = insert(:user, is_locked: true) - {:ok, follower} = User.maybe_direct_follow(follower, followed) + {:ok, follower, followed} = User.maybe_direct_follow(follower, followed) refute User.following?(follower, followed) end @@ -311,7 +311,7 @@ defmodule Pleroma.UserTest do setup do: clear_config([:instance, :external_user_synchronization]) test "unfollow with syncronizes external user" do - Pleroma.Config.put([:instance, :external_user_synchronization], true) + clear_config([:instance, :external_user_synchronization], true) followed = insert(:user, @@ -330,7 +330,7 @@ defmodule Pleroma.UserTest do following_address: "http://localhost:4001/users/fuser2/following" }) - {:ok, user} = User.follow(user, followed, :follow_accept) + {:ok, user, followed} = User.follow(user, followed, :follow_accept) {:ok, user, _activity} = User.unfollow(user, followed) @@ -343,7 +343,7 @@ defmodule Pleroma.UserTest do followed = insert(:user) user = insert(:user) - {:ok, user} = User.follow(user, followed, :follow_accept) + {:ok, user, followed} = User.follow(user, followed, :follow_accept) assert User.following(user) == [user.follower_address, followed.follower_address] @@ -388,6 +388,7 @@ defmodule Pleroma.UserTest do } setup do: clear_config([:instance, :autofollowed_nicknames]) + setup do: clear_config([:instance, :autofollowing_nicknames]) setup do: clear_config([:welcome]) setup do: clear_config([:instance, :account_activation_required]) @@ -395,7 +396,7 @@ defmodule Pleroma.UserTest do user = insert(:user) remote_user = insert(:user, %{local: false}) - Pleroma.Config.put([:instance, :autofollowed_nicknames], [ + clear_config([:instance, :autofollowed_nicknames], [ user.nickname, remote_user.nickname ]) @@ -408,11 +409,28 @@ defmodule Pleroma.UserTest do refute User.following?(registered_user, remote_user) end + test "it adds automatic followers for new registered accounts" do + user1 = insert(:user) + user2 = insert(:user) + + clear_config([:instance, :autofollowing_nicknames], [ + user1.nickname, + user2.nickname + ]) + + cng = User.register_changeset(%User{}, @full_user_data) + + {:ok, registered_user} = User.register(cng) + + assert User.following?(user1, registered_user) + assert User.following?(user2, registered_user) + end + test "it sends a welcome message if it is set" do welcome_user = insert(:user) - Pleroma.Config.put([:welcome, :direct_message, :enabled], true) - Pleroma.Config.put([:welcome, :direct_message, :sender_nickname], welcome_user.nickname) - Pleroma.Config.put([:welcome, :direct_message, :message], "Hello, this is a direct message") + clear_config([:welcome, :direct_message, :enabled], true) + clear_config([:welcome, :direct_message, :sender_nickname], welcome_user.nickname) + clear_config([:welcome, :direct_message, :message], "Hello, this is a direct message") cng = User.register_changeset(%User{}, @full_user_data) {:ok, registered_user} = User.register(cng) @@ -420,15 +438,54 @@ defmodule Pleroma.UserTest do activity = Repo.one(Pleroma.Activity) assert registered_user.ap_id in activity.recipients - assert Object.normalize(activity).data["content"] =~ "direct message" + assert Object.normalize(activity, fetch: false).data["content"] =~ "direct message" assert activity.actor == welcome_user.ap_id end test "it sends a welcome chat message if it is set" do welcome_user = insert(:user) - Pleroma.Config.put([:welcome, :chat_message, :enabled], true) - Pleroma.Config.put([:welcome, :chat_message, :sender_nickname], welcome_user.nickname) - Pleroma.Config.put([:welcome, :chat_message, :message], "Hello, this is a chat message") + clear_config([:welcome, :chat_message, :enabled], true) + clear_config([:welcome, :chat_message, :sender_nickname], welcome_user.nickname) + clear_config([:welcome, :chat_message, :message], "Hello, this is a chat message") + + cng = User.register_changeset(%User{}, @full_user_data) + {:ok, registered_user} = User.register(cng) + ObanHelpers.perform_all() + + activity = Repo.one(Pleroma.Activity) + assert registered_user.ap_id in activity.recipients + assert Object.normalize(activity, fetch: false).data["content"] =~ "chat message" + assert activity.actor == welcome_user.ap_id + end + + setup do: + clear_config(:mrf_simple, + media_removal: [], + media_nsfw: [], + federated_timeline_removal: [], + report_removal: [], + reject: [], + followers_only: [], + accept: [], + avatar_removal: [], + banner_removal: [], + reject_deletes: [] + ) + + setup do: + clear_config(:mrf, + policies: [ + Pleroma.Web.ActivityPub.MRF.SimplePolicy + ] + ) + + test "it sends a welcome chat message when Simple policy applied to local instance" do + clear_config([:mrf_simple, :media_nsfw], [{"localhost", ""}]) + + welcome_user = insert(:user) + clear_config([:welcome, :chat_message, :enabled], true) + clear_config([:welcome, :chat_message, :sender_nickname], welcome_user.nickname) + clear_config([:welcome, :chat_message, :message], "Hello, this is a chat message") cng = User.register_changeset(%User{}, @full_user_data) {:ok, registered_user} = User.register(cng) @@ -436,16 +493,16 @@ defmodule Pleroma.UserTest do activity = Repo.one(Pleroma.Activity) assert registered_user.ap_id in activity.recipients - assert Object.normalize(activity).data["content"] =~ "chat message" + assert Object.normalize(activity, fetch: false).data["content"] =~ "chat message" assert activity.actor == welcome_user.ap_id end test "it sends a welcome email message if it is set" do welcome_user = insert(:user) - Pleroma.Config.put([:welcome, :email, :enabled], true) - Pleroma.Config.put([:welcome, :email, :sender], welcome_user.email) + clear_config([:welcome, :email, :enabled], true) + clear_config([:welcome, :email, :sender], welcome_user.email) - Pleroma.Config.put( + clear_config( [:welcome, :email, :subject], "Hello, welcome to cool site: <%= instance_name %>" ) @@ -465,16 +522,76 @@ defmodule Pleroma.UserTest do end test "it sends a confirm email" do - Pleroma.Config.put([:instance, :account_activation_required], true) + clear_config([:instance, :account_activation_required], true) cng = User.register_changeset(%User{}, @full_user_data) {:ok, registered_user} = User.register(cng) ObanHelpers.perform_all() - assert_email_sent(Pleroma.Emails.UserEmail.account_confirmation_email(registered_user)) + + Pleroma.Emails.UserEmail.account_confirmation_email(registered_user) + # temporary hackney fix until hackney max_connections bug is fixed + # https://git.pleroma.social/pleroma/pleroma/-/issues/2101 + |> Swoosh.Email.put_private(:hackney_options, ssl_options: [versions: [:"tlsv1.2"]]) + |> assert_email_sent() + end + + test "sends a pending approval email" do + clear_config([:instance, :account_approval_required], true) + + {:ok, user} = + User.register_changeset(%User{}, @full_user_data) + |> User.register() + + ObanHelpers.perform_all() + + assert_email_sent( + from: Pleroma.Config.Helpers.sender(), + to: {user.name, user.email}, + subject: "Your account is awaiting approval" + ) + end + + test "it sends a registration confirmed email if no others will be sent" do + clear_config([:welcome, :email, :enabled], false) + clear_config([:instance, :account_activation_required], false) + clear_config([:instance, :account_approval_required], false) + + {:ok, user} = + User.register_changeset(%User{}, @full_user_data) + |> User.register() + + ObanHelpers.perform_all() + + instance_name = Pleroma.Config.get([:instance, :name]) + sender = Pleroma.Config.get([:instance, :notify_email]) + + assert_email_sent( + from: {instance_name, sender}, + to: {user.name, user.email}, + subject: "Account registered on #{instance_name}" + ) + end + + test "it fails gracefully with invalid email config" do + cng = User.register_changeset(%User{}, @full_user_data) + + # Disable the mailer but enable all the things that want to send emails + clear_config([Pleroma.Emails.Mailer, :enabled], false) + clear_config([:instance, :account_activation_required], true) + clear_config([:instance, :account_approval_required], true) + clear_config([:welcome, :email, :enabled], true) + clear_config([:welcome, :email, :sender], "lain@lain.com") + + # The user is still created + assert {:ok, %User{nickname: "nick"}} = User.register(cng) + + # No emails are sent + ObanHelpers.perform_all() + refute_email_sent() end test "it requires an email, name, nickname and password, bio is optional when account_activation_required is enabled" do - Pleroma.Config.put([:instance, :account_activation_required], true) + clear_config([:instance, :account_activation_required], true) @full_user_data |> Map.keys() @@ -487,7 +604,7 @@ defmodule Pleroma.UserTest do end test "it requires an name, nickname and password, bio and email are optional when account_activation_required is disabled" do - Pleroma.Config.put([:instance, :account_activation_required], false) + clear_config([:instance, :account_activation_required], false) @full_user_data |> Map.keys() @@ -562,7 +679,7 @@ defmodule Pleroma.UserTest do {:ok, user} = Repo.insert(changeset) - refute user.confirmation_pending + assert user.is_confirmed end end @@ -583,17 +700,17 @@ defmodule Pleroma.UserTest do {:ok, user} = Repo.insert(changeset) - assert user.confirmation_pending + refute user.is_confirmed assert user.confirmation_token end test "it creates confirmed user if :confirmed option is given" do - changeset = User.register_changeset(%User{}, @full_user_data, need_confirmation: false) + changeset = User.register_changeset(%User{}, @full_user_data, confirmed: true) assert changeset.valid? {:ok, user} = Repo.insert(changeset) - refute user.confirmation_pending + assert user.is_confirmed refute user.confirmation_token end end @@ -616,7 +733,7 @@ defmodule Pleroma.UserTest do {:ok, user} = Repo.insert(changeset) - assert user.approval_pending + refute user.is_approved assert user.registration_reason == "I'm a cool guy :)" end @@ -833,6 +950,13 @@ defmodule Pleroma.UserTest do refute cs.valid? end) end + + test "it is invalid given a local user" do + user = insert(:user) + cs = User.remote_user_changeset(user, %{name: "tom from myspace"}) + + refute cs.valid? + end end describe "followers and friends" do @@ -842,8 +966,8 @@ defmodule Pleroma.UserTest do follower_two = insert(:user) not_follower = insert(:user) - {:ok, follower_one} = User.follow(follower_one, user) - {:ok, follower_two} = User.follow(follower_two, user) + {:ok, follower_one, user} = User.follow(follower_one, user) + {:ok, follower_two, user} = User.follow(follower_two, user) res = User.get_followers(user) @@ -858,8 +982,8 @@ defmodule Pleroma.UserTest do followed_two = insert(:user) not_followed = insert(:user) - {:ok, user} = User.follow(user, followed_one) - {:ok, user} = User.follow(user, followed_two) + {:ok, user, followed_one} = User.follow(user, followed_one) + {:ok, user, followed_two} = User.follow(user, followed_two) res = User.get_friends(user) @@ -932,23 +1056,6 @@ defmodule Pleroma.UserTest do end end - describe "follow_import" do - test "it imports user followings from list" do - [user1, user2, user3] = insert_list(3, :user) - - identifiers = [ - user2.ap_id, - user3.nickname - ] - - {:ok, job} = User.follow_import(user1, identifiers) - - assert {:ok, result} = ObanHelpers.perform(job) - assert is_list(result) - assert result == [user2, user3] - end - end - describe "mutes" do test "it mutes people" do user = insert(:user) @@ -963,6 +1070,27 @@ defmodule Pleroma.UserTest do assert User.muted_notifications?(user, muted_user) end + test "expiring" do + user = insert(:user) + muted_user = insert(:user) + + {:ok, _user_relationships} = User.mute(user, muted_user, %{expires_in: 60}) + assert User.mutes?(user, muted_user) + + worker = Pleroma.Workers.MuteExpireWorker + args = %{"op" => "unmute_user", "muter_id" => user.id, "mutee_id" => muted_user.id} + + assert_enqueued( + worker: worker, + args: args + ) + + assert :ok = perform_job(worker, args) + + refute User.mutes?(user, muted_user) + refute User.muted_notifications?(user, muted_user) + end + test "it unmutes users" do user = insert(:user) muted_user = insert(:user) @@ -974,6 +1102,17 @@ defmodule Pleroma.UserTest do refute User.muted_notifications?(user, muted_user) end + test "it unmutes users by id" do + user = insert(:user) + muted_user = insert(:user) + + {:ok, _user_relationships} = User.mute(user, muted_user) + {:ok, _user_mute} = User.unmute(user.id, muted_user.id) + + refute User.mutes?(user, muted_user) + refute User.muted_notifications?(user, muted_user) + end + test "it mutes user without notifications" do user = insert(:user) muted_user = insert(:user) @@ -981,7 +1120,7 @@ defmodule Pleroma.UserTest do refute User.mutes?(user, muted_user) refute User.muted_notifications?(user, muted_user) - {:ok, _user_relationships} = User.mute(user, muted_user, false) + {:ok, _user_relationships} = User.mute(user, muted_user, %{notifications: false}) assert User.mutes?(user, muted_user) refute User.muted_notifications?(user, muted_user) @@ -1014,8 +1153,8 @@ defmodule Pleroma.UserTest do blocker = insert(:user) blocked = insert(:user) - {:ok, blocker} = User.follow(blocker, blocked) - {:ok, blocked} = User.follow(blocked, blocker) + {:ok, blocker, blocked} = User.follow(blocker, blocked) + {:ok, blocked, blocker} = User.follow(blocked, blocker) assert User.following?(blocker, blocked) assert User.following?(blocked, blocker) @@ -1033,7 +1172,7 @@ defmodule Pleroma.UserTest do blocker = insert(:user) blocked = insert(:user) - {:ok, blocker} = User.follow(blocker, blocked) + {:ok, blocker, blocked} = User.follow(blocker, blocked) assert User.following?(blocker, blocked) refute User.following?(blocked, blocker) @@ -1051,7 +1190,7 @@ defmodule Pleroma.UserTest do blocker = insert(:user) blocked = insert(:user) - {:ok, blocked} = User.follow(blocked, blocker) + {:ok, blocked, blocker} = User.follow(blocked, blocker) refute User.following?(blocker, blocked) assert User.following?(blocked, blocker) @@ -1149,29 +1288,12 @@ defmodule Pleroma.UserTest do good_eggo = insert(:user, %{ap_id: "https://meanies.social/user/cuteposter"}) {:ok, user} = User.block_domain(user, "meanies.social") - {:ok, user} = User.follow(user, good_eggo) + {:ok, user, good_eggo} = User.follow(user, good_eggo) refute User.blocks?(user, good_eggo) end end - describe "blocks_import" do - test "it imports user blocks from list" do - [user1, user2, user3] = insert_list(3, :user) - - identifiers = [ - user2.ap_id, - user3.nickname - ] - - {:ok, job} = User.blocks_import(user1, identifiers) - - assert {:ok, result} = ObanHelpers.perform(job) - assert is_list(result) - assert result == [user2, user3] - end - end - describe "get_recipients_from_activity" do test "works for announces" do actor = insert(:user) @@ -1200,8 +1322,8 @@ defmodule Pleroma.UserTest do assert Enum.map([actor, addressed], & &1.ap_id) -- Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == [] - {:ok, user} = User.follow(user, actor) - {:ok, _user_two} = User.follow(user_two, actor) + {:ok, user, actor} = User.follow(user, actor) + {:ok, _user_two, _actor} = User.follow(user_two, actor) recipients = User.get_recipients_from_activity(activity) assert length(recipients) == 3 assert user in recipients @@ -1222,30 +1344,30 @@ defmodule Pleroma.UserTest do assert Enum.map([actor, addressed], & &1.ap_id) -- Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == [] - {:ok, _actor} = User.follow(actor, user) - {:ok, _actor} = User.follow(actor, user_two) + {:ok, _actor, _user} = User.follow(actor, user) + {:ok, _actor, _user_two} = User.follow(actor, user_two) recipients = User.get_recipients_from_activity(activity) assert length(recipients) == 2 assert addressed in recipients end end - describe ".deactivate" do + describe ".set_activation" do test "can de-activate then re-activate a user" do user = insert(:user) - assert false == user.deactivated - {:ok, user} = User.deactivate(user) - assert true == user.deactivated - {:ok, user} = User.deactivate(user, false) - assert false == user.deactivated + assert user.is_active + {:ok, user} = User.set_activation(user, false) + refute user.is_active + {:ok, user} = User.set_activation(user, true) + assert user.is_active end test "hide a user from followers" do user = insert(:user) user2 = insert(:user) - {:ok, user} = User.follow(user, user2) - {:ok, _user} = User.deactivate(user) + {:ok, user, user2} = User.follow(user, user2) + {:ok, _user} = User.set_activation(user, false) user2 = User.get_cached_by_id(user2.id) @@ -1257,11 +1379,11 @@ defmodule Pleroma.UserTest do user = insert(:user) user2 = insert(:user) - {:ok, user2} = User.follow(user2, user) + {:ok, user2, user} = User.follow(user2, user) assert user2.following_count == 1 assert User.following_count(user2) == 1 - {:ok, _user} = User.deactivate(user) + {:ok, _user} = User.set_activation(user, false) user2 = User.get_cached_by_id(user2.id) @@ -1275,7 +1397,7 @@ defmodule Pleroma.UserTest do user = insert(:user) user2 = insert(:user) - {:ok, user2} = User.follow(user2, user) + {:ok, user2, user} = User.follow(user2, user) {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{user2.nickname}"}) @@ -1291,7 +1413,7 @@ defmodule Pleroma.UserTest do user: user2 }) - {:ok, _user} = User.deactivate(user) + {:ok, _user} = User.set_activation(user, false) assert [] == ActivityPub.fetch_public_activities(%{}) assert [] == Pleroma.Notification.for_user(user2) @@ -1305,17 +1427,17 @@ defmodule Pleroma.UserTest do describe "approve" do test "approves a user" do - user = insert(:user, approval_pending: true) - assert true == user.approval_pending + user = insert(:user, is_approved: false) + refute user.is_approved {:ok, user} = User.approve(user) - assert false == user.approval_pending + assert user.is_approved end test "approves a list of users" do unapproved_users = [ - insert(:user, approval_pending: true), - insert(:user, approval_pending: true), - insert(:user, approval_pending: true) + insert(:user, is_approved: false), + insert(:user, is_approved: false), + insert(:user, is_approved: false) ] {:ok, users} = User.approve(unapproved_users) @@ -1323,9 +1445,101 @@ defmodule Pleroma.UserTest do assert Enum.count(users) == 3 Enum.each(users, fn user -> - assert false == user.approval_pending + assert user.is_approved end) end + + test "it sends welcome email if it is set" do + clear_config([:welcome, :email, :enabled], true) + clear_config([:welcome, :email, :sender], "tester@test.me") + + user = insert(:user, is_approved: false) + welcome_user = insert(:user, email: "tester@test.me") + instance_name = Pleroma.Config.get([:instance, :name]) + + User.approve(user) + + ObanHelpers.perform_all() + + assert_email_sent( + from: {instance_name, welcome_user.email}, + to: {user.name, user.email}, + html_body: "Welcome to #{instance_name}" + ) + end + + test "approving an approved user does not trigger post-register actions" do + clear_config([:welcome, :email, :enabled], true) + + user = insert(:user, is_approved: true) + User.approve(user) + + ObanHelpers.perform_all() + + assert_no_email_sent() + end + end + + describe "confirm" do + test "confirms a user" do + user = insert(:user, is_confirmed: false) + refute user.is_confirmed + {:ok, user} = User.confirm(user) + assert user.is_confirmed + end + + test "confirms a list of users" do + unconfirmed_users = [ + insert(:user, is_confirmed: false), + insert(:user, is_confirmed: false), + insert(:user, is_confirmed: false) + ] + + {:ok, users} = User.confirm(unconfirmed_users) + + assert Enum.count(users) == 3 + + Enum.each(users, fn user -> + assert user.is_confirmed + end) + end + + test "sends approval emails when `is_approved: false`" do + admin = insert(:user, is_admin: true) + user = insert(:user, is_confirmed: false, is_approved: false) + User.confirm(user) + + ObanHelpers.perform_all() + + user_email = Pleroma.Emails.UserEmail.approval_pending_email(user) + admin_email = Pleroma.Emails.AdminEmail.new_unapproved_registration(admin, user) + + notify_email = Pleroma.Config.get([:instance, :notify_email]) + instance_name = Pleroma.Config.get([:instance, :name]) + + # User approval email + assert_email_sent( + from: {instance_name, notify_email}, + to: {user.name, user.email}, + html_body: user_email.html_body + ) + + # Admin email + assert_email_sent( + from: {instance_name, notify_email}, + to: {admin.name, admin.email}, + html_body: admin_email.html_body + ) + end + + test "confirming a confirmed user does not trigger post-register actions" do + user = insert(:user, is_confirmed: true, is_approved: false) + User.confirm(user) + + ObanHelpers.perform_all() + + assert_no_email_sent() + end end describe "delete" do @@ -1348,10 +1562,10 @@ defmodule Pleroma.UserTest do test "it deactivates a user, all follow relationships and all activities", %{user: user} do follower = insert(:user) - {:ok, follower} = User.follow(follower, user) + {:ok, follower, user} = User.follow(follower, user) - locked_user = insert(:user, name: "locked", locked: true) - {:ok, _} = User.follow(user, locked_user, :follow_pending) + locked_user = insert(:user, name: "locked", is_locked: true) + {:ok, _, _} = User.follow(user, locked_user, :follow_pending) object = insert(:note, user: user) activity = insert(:note_activity, user: user, note: object) @@ -1369,7 +1583,7 @@ defmodule Pleroma.UserTest do follower = User.get_cached_by_id(follower.id) refute User.following?(follower, user) - assert %{deactivated: true} = User.get_by_id(user.id) + assert %{is_active: false} = User.get_by_id(user.id) assert [] == User.get_follow_requests(locked_user) @@ -1388,35 +1602,19 @@ defmodule Pleroma.UserTest do end end - describe "delete/1 when confirmation is pending" do - setup do - user = insert(:user, confirmation_pending: true) - {:ok, user: user} - end - - test "deletes user from database when activation required", %{user: user} do - clear_config([:instance, :account_activation_required], true) - - {:ok, job} = User.delete(user) - {:ok, _} = ObanHelpers.perform(job) - - refute User.get_cached_by_id(user.id) - refute User.get_by_id(user.id) - end + test "delete/1 when confirmation is pending deletes the user" do + clear_config([:instance, :account_activation_required], true) + user = insert(:user, is_confirmed: false) - test "deactivates user when activation is not required", %{user: user} do - clear_config([:instance, :account_activation_required], false) - - {:ok, job} = User.delete(user) - {:ok, _} = ObanHelpers.perform(job) + {:ok, job} = User.delete(user) + {:ok, _} = ObanHelpers.perform(job) - assert %{deactivated: true} = User.get_cached_by_id(user.id) - assert %{deactivated: true} = User.get_by_id(user.id) - end + refute User.get_cached_by_id(user.id) + refute User.get_by_id(user.id) end test "delete/1 when approval is pending deletes the user" do - user = insert(:user, approval_pending: true) + user = insert(:user, is_approved: false) {:ok, job} = User.delete(user) {:ok, _} = ObanHelpers.perform(job) @@ -1440,24 +1638,23 @@ defmodule Pleroma.UserTest do note_count: 9, follower_count: 9, following_count: 9001, - locked: true, - confirmation_pending: true, + is_locked: true, + is_confirmed: true, password_reset_pending: true, - approval_pending: true, + is_approved: true, registration_reason: "ahhhhh", confirmation_token: "qqqq", domain_blocks: ["lain.com"], - deactivated: true, + is_active: false, ap_enabled: true, is_moderator: true, is_admin: true, - mastofe_settings: %{"a" => "b"}, mascot: %{"a" => "b"}, emoji: %{"a" => "b"}, pleroma_settings_store: %{"q" => "x"}, fields: [%{"gg" => "qq"}], raw_fields: [%{"gg" => "qq"}], - discoverable: true, + is_discoverable: true, also_known_as: ["https://lol.olo/users/loll"] }) @@ -1471,8 +1668,8 @@ defmodule Pleroma.UserTest do email: nil, name: nil, password_hash: nil, - keys: nil, - public_key: nil, + keys: "RSA begin buplic key", + public_key: "--PRIVATE KEYE--", avatar: %{}, tags: [], last_refreshed_at: nil, @@ -1482,28 +1679,77 @@ defmodule Pleroma.UserTest do note_count: 0, follower_count: 0, following_count: 0, - locked: false, - confirmation_pending: false, + is_locked: false, + is_confirmed: true, password_reset_pending: false, - approval_pending: false, + is_approved: true, registration_reason: nil, confirmation_token: nil, domain_blocks: [], - deactivated: true, + is_active: false, ap_enabled: false, is_moderator: false, is_admin: false, - mastofe_settings: nil, mascot: nil, emoji: %{}, pleroma_settings_store: %{}, fields: [], raw_fields: [], - discoverable: false, + is_discoverable: false, also_known_as: [] } = user end + test "delete/1 purges a remote user" do + user = + insert(:user, %{ + name: "qqqqqqq", + avatar: %{"a" => "b"}, + banner: %{"a" => "b"}, + local: false + }) + + {:ok, job} = User.delete(user) + {:ok, _} = ObanHelpers.perform(job) + user = User.get_by_id(user.id) + + assert user.name == nil + assert user.avatar == %{} + assert user.banner == %{} + end + + describe "set_suggestion" do + test "suggests a user" do + user = insert(:user, is_suggested: false) + refute user.is_suggested + {:ok, user} = User.set_suggestion(user, true) + assert user.is_suggested + end + + test "suggests a list of users" do + unsuggested_users = [ + insert(:user, is_suggested: false), + insert(:user, is_suggested: false), + insert(:user, is_suggested: false) + ] + + {:ok, users} = User.set_suggestion(unsuggested_users, true) + + assert Enum.count(users) == 3 + + Enum.each(users, fn user -> + assert user.is_suggested + end) + end + + test "unsuggests a user" do + user = insert(:user, is_suggested: true) + assert user.is_suggested + {:ok, user} = User.set_suggestion(user, false) + refute user.is_suggested + end + end + test "get_public_key_for_ap_id fetches a user that's not in the db" do assert {:ok, _key} = User.get_public_key_for_ap_id("http://mastodon.example.org/users/admin") end @@ -1553,14 +1799,14 @@ defmodule Pleroma.UserTest do setup do: clear_config([:instance, :account_activation_required]) test "return confirmation_pending for unconfirm user" do - Pleroma.Config.put([:instance, :account_activation_required], true) - user = insert(:user, confirmation_pending: true) + clear_config([:instance, :account_activation_required], true) + user = insert(:user, is_confirmed: false) assert User.account_status(user) == :confirmation_pending end test "return active for confirmed user" do - Pleroma.Config.put([:instance, :account_activation_required], true) - user = insert(:user, confirmation_pending: false) + clear_config([:instance, :account_activation_required], true) + user = insert(:user, is_confirmed: true) assert User.account_status(user) == :active end @@ -1575,15 +1821,15 @@ defmodule Pleroma.UserTest do end test "returns :deactivated for deactivated user" do - user = insert(:user, local: true, confirmation_pending: false, deactivated: true) + user = insert(:user, local: true, is_confirmed: true, is_active: false) assert User.account_status(user) == :deactivated end test "returns :approval_pending for unapproved user" do - user = insert(:user, local: true, approval_pending: true) + user = insert(:user, local: true, is_approved: false) assert User.account_status(user) == :approval_pending - user = insert(:user, local: true, confirmation_pending: true, approval_pending: true) + user = insert(:user, local: true, is_confirmed: false, is_approved: false) assert User.account_status(user) == :approval_pending end end @@ -1637,26 +1883,28 @@ defmodule Pleroma.UserTest do assert User.visible_for(user, user) == :visible end - test "returns false when the account is unauthenticated and auth is required" do - Pleroma.Config.put([:instance, :account_activation_required], true) + test "returns false when the account is unconfirmed and confirmation is required" do + clear_config([:instance, :account_activation_required], true) - user = insert(:user, local: true, confirmation_pending: true) + user = insert(:user, local: true, is_confirmed: false) other_user = insert(:user, local: true) refute User.visible_for(user, other_user) == :visible end - test "returns true when the account is unauthenticated and auth is not required" do - user = insert(:user, local: true, confirmation_pending: true) + test "returns true when the account is unconfirmed and confirmation is required but the account is remote" do + clear_config([:instance, :account_activation_required], true) + + user = insert(:user, local: false, is_confirmed: false) other_user = insert(:user, local: true) assert User.visible_for(user, other_user) == :visible end - test "returns true when the account is unauthenticated and being viewed by a privileged account (auth required)" do - Pleroma.Config.put([:instance, :account_activation_required], true) + test "returns true when the account is unconfirmed and being viewed by a privileged account (confirmation required)" do + clear_config([:instance, :account_activation_required], true) - user = insert(:user, local: true, confirmation_pending: true) + user = insert(:user, local: true, is_confirmed: false) other_user = insert(:user, local: true, is_admin: true) assert User.visible_for(user, other_user) == :visible @@ -1670,9 +1918,7 @@ defmodule Pleroma.UserTest do bio = "A.k.a. @nick@domain.com" expected_text = - ~s(A.k.a. <span class="h-card"><a class="u-url mention" data-user="#{remote_user.id}" href="#{ - remote_user.ap_id - }" rel="ugc">@<span>nick@domain.com</span></a></span>) + ~s(A.k.a. <span class="h-card"><a class="u-url mention" data-user="#{remote_user.id}" href="#{remote_user.ap_id}" rel="ugc">@<span>nick@domain.com</span></a></span>) assert expected_text == User.parse_bio(bio, user) end @@ -1700,9 +1946,9 @@ defmodule Pleroma.UserTest do follower2 = insert(:user) follower3 = insert(:user) - {:ok, follower} = User.follow(follower, user) - {:ok, _follower2} = User.follow(follower2, user) - {:ok, _follower3} = User.follow(follower3, user) + {:ok, follower, user} = User.follow(follower, user) + {:ok, _follower2, _user} = User.follow(follower2, user) + {:ok, _follower3, _user} = User.follow(follower3, user) {:ok, _user_relationship} = User.block(user, follower) user = refresh_record(user) @@ -1724,7 +1970,7 @@ defmodule Pleroma.UserTest do users = Enum.map(1..total, fn _ -> - insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false) + insert(:user, last_digest_emailed_at: days_ago(20), is_active: true) end) inactive_users_ids = @@ -1742,7 +1988,7 @@ defmodule Pleroma.UserTest do users = Enum.map(1..total, fn _ -> - insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false) + insert(:user, last_digest_emailed_at: days_ago(20), is_active: true) end) {inactive, active} = Enum.split(users, trunc(total / 2)) @@ -1775,7 +2021,7 @@ defmodule Pleroma.UserTest do users = Enum.map(1..total, fn _ -> - insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false) + insert(:user, last_digest_emailed_at: days_ago(20), is_active: true) end) [sender | recipients] = users @@ -1813,24 +2059,6 @@ defmodule Pleroma.UserTest do end end - describe "toggle_confirmation/1" do - test "if user is confirmed" do - user = insert(:user, confirmation_pending: false) - {:ok, user} = User.toggle_confirmation(user) - - assert user.confirmation_pending - assert user.confirmation_token - end - - test "if user is unconfirmed" do - user = insert(:user, confirmation_pending: true, confirmation_token: "some token") - {:ok, user} = User.toggle_confirmation(user) - - refute user.confirmation_pending - refute user.confirmation_token - end - end - describe "ensure_keys_present" do test "it creates keys for a user and stores them in info" do user = insert(:user) @@ -1863,7 +2091,7 @@ defmodule Pleroma.UserTest do user1 = insert(:user, local: false, ap_id: "http://localhost:4001/users/masto_closed") user2 = insert(:user, local: false, ap_id: "http://localhost:4001/users/fuser2") insert(:user, local: true) - insert(:user, local: false, deactivated: true) + insert(:user, local: false, is_active: false) {:ok, user1: user1, user2: user2} end @@ -1929,7 +2157,7 @@ defmodule Pleroma.UserTest do setup do: clear_config([:instance, :external_user_synchronization]) test "updates the counters normally on following/getting a follow when disabled" do - Pleroma.Config.put([:instance, :external_user_synchronization], false) + clear_config([:instance, :external_user_synchronization], false) user = insert(:user) other_user = @@ -1943,15 +2171,14 @@ defmodule Pleroma.UserTest do assert other_user.following_count == 0 assert other_user.follower_count == 0 - {:ok, user} = Pleroma.User.follow(user, other_user) - other_user = Pleroma.User.get_by_id(other_user.id) + {:ok, user, other_user} = Pleroma.User.follow(user, other_user) assert user.following_count == 1 assert other_user.follower_count == 1 end test "syncronizes the counters with the remote instance for the followed when enabled" do - Pleroma.Config.put([:instance, :external_user_synchronization], false) + clear_config([:instance, :external_user_synchronization], false) user = insert(:user) @@ -1966,15 +2193,14 @@ defmodule Pleroma.UserTest do assert other_user.following_count == 0 assert other_user.follower_count == 0 - Pleroma.Config.put([:instance, :external_user_synchronization], true) - {:ok, _user} = User.follow(user, other_user) - other_user = User.get_by_id(other_user.id) + clear_config([:instance, :external_user_synchronization], true) + {:ok, _user, other_user} = User.follow(user, other_user) assert other_user.follower_count == 437 end test "syncronizes the counters with the remote instance for the follower when enabled" do - Pleroma.Config.put([:instance, :external_user_synchronization], false) + clear_config([:instance, :external_user_synchronization], false) user = insert(:user) @@ -1989,8 +2215,8 @@ defmodule Pleroma.UserTest do assert other_user.following_count == 0 assert other_user.follower_count == 0 - Pleroma.Config.put([:instance, :external_user_synchronization], true) - {:ok, other_user} = User.follow(other_user, user) + clear_config([:instance, :external_user_synchronization], true) + {:ok, other_user, _user} = User.follow(other_user, user) assert other_user.following_count == 152 end @@ -2001,11 +2227,40 @@ defmodule Pleroma.UserTest do [user: insert(:user)] end - test "blank email returns error", %{user: user} do + test "blank email returns error if we require an email on registration", %{user: user} do + orig_account_activation_required = + Pleroma.Config.get([:instance, :account_activation_required]) + + Pleroma.Config.put([:instance, :account_activation_required], true) + + on_exit(fn -> + Pleroma.Config.put( + [:instance, :account_activation_required], + orig_account_activation_required + ) + end) + assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, "") assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, nil) end + test "blank email should be fine if we do not require an email on registration", %{user: user} do + orig_account_activation_required = + Pleroma.Config.get([:instance, :account_activation_required]) + + Pleroma.Config.put([:instance, :account_activation_required], false) + + on_exit(fn -> + Pleroma.Config.put( + [:instance, :account_activation_required], + orig_account_activation_required + ) + end) + + assert {:ok, %User{email: nil}} = User.change_email(user, "") + assert {:ok, %User{email: nil}} = User.change_email(user, nil) + end + test "non unique email returns error", %{user: user} do %{email: email} = insert(:user) @@ -2021,6 +2276,25 @@ defmodule Pleroma.UserTest do test "changes email", %{user: user} do assert {:ok, %User{email: "cofe@cofe.party"}} = User.change_email(user, "cofe@cofe.party") end + + test "adds email", %{user: user} do + orig_account_activation_required = + Pleroma.Config.get([:instance, :account_activation_required]) + + Pleroma.Config.put([:instance, :account_activation_required], false) + + on_exit(fn -> + Pleroma.Config.put( + [:instance, :account_activation_required], + orig_account_activation_required + ) + end) + + assert {:ok, _} = User.change_email(user, "") + Pleroma.Config.put([:instance, :account_activation_required], true) + + assert {:ok, %User{email: "cofe2@cofe.party"}} = User.change_email(user, "cofe2@cofe.party") + end end describe "get_cached_by_nickname_or_id" do @@ -2036,43 +2310,43 @@ defmodule Pleroma.UserTest do test "allows getting remote users by id no matter what :limit_to_local_content is set to", %{ remote_user: remote_user } do - Pleroma.Config.put([:instance, :limit_to_local_content], false) + clear_config([:instance, :limit_to_local_content], false) assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id) - Pleroma.Config.put([:instance, :limit_to_local_content], true) + clear_config([:instance, :limit_to_local_content], true) assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id) - Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated) + clear_config([:instance, :limit_to_local_content], :unauthenticated) assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id) end test "disallows getting remote users by nickname without authentication when :limit_to_local_content is set to :unauthenticated", %{remote_user: remote_user} do - Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated) + clear_config([:instance, :limit_to_local_content], :unauthenticated) assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname) end test "allows getting remote users by nickname with authentication when :limit_to_local_content is set to :unauthenticated", %{remote_user: remote_user, local_user: local_user} do - Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated) + clear_config([:instance, :limit_to_local_content], :unauthenticated) assert %User{} = User.get_cached_by_nickname_or_id(remote_user.nickname, for: local_user) end test "disallows getting remote users by nickname when :limit_to_local_content is set to true", %{remote_user: remote_user} do - Pleroma.Config.put([:instance, :limit_to_local_content], true) + clear_config([:instance, :limit_to_local_content], true) assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname) end test "allows getting local users by nickname no matter what :limit_to_local_content is set to", %{local_user: local_user} do - Pleroma.Config.put([:instance, :limit_to_local_content], false) + clear_config([:instance, :limit_to_local_content], false) assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname) - Pleroma.Config.put([:instance, :limit_to_local_content], true) + clear_config([:instance, :limit_to_local_content], true) assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname) - Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated) + clear_config([:instance, :limit_to_local_content], :unauthenticated) assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname) end end @@ -2091,6 +2365,36 @@ defmodule Pleroma.UserTest do end end + describe "local_nickname/1" do + test "returns nickname without host" do + assert User.local_nickname("@mentioned") == "mentioned" + assert User.local_nickname("a_local_nickname") == "a_local_nickname" + assert User.local_nickname("nickname@host.com") == "nickname" + end + end + + describe "full_nickname/1" do + test "returns fully qualified nickname for local and remote users" do + local_user = + insert(:user, nickname: "local_user", ap_id: "https://somehost.com/users/local_user") + + remote_user = insert(:user, nickname: "remote@host.com", local: false) + + assert User.full_nickname(local_user) == "local_user@somehost.com" + assert User.full_nickname(remote_user) == "remote@host.com" + end + + test "strips leading @ from mentions" do + assert User.full_nickname("@mentioned") == "mentioned" + assert User.full_nickname("@nickname@host.com") == "nickname@host.com" + end + + test "does not modify nicknames" do + assert User.full_nickname("nickname") == "nickname" + assert User.full_nickname("nickname@host.com") == "nickname@host.com" + end + end + test "avatar fallback" do user = insert(:user) assert User.avatar_url(user) =~ "/images/avi.png" @@ -2102,4 +2406,96 @@ defmodule Pleroma.UserTest do assert User.avatar_url(user, no_default: true) == nil end + + test "get_host/1" do + user = insert(:user, ap_id: "https://lain.com/users/lain", nickname: "lain") + assert User.get_host(user) == "lain.com" + end + + test "update_last_active_at/1" do + user = insert(:user) + assert is_nil(user.last_active_at) + + test_started_at = NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second) + + assert {:ok, user} = User.update_last_active_at(user) + + assert user.last_active_at >= test_started_at + assert user.last_active_at <= NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second) + + last_active_at = + NaiveDateTime.utc_now() + |> NaiveDateTime.add(-:timer.hours(24), :millisecond) + |> NaiveDateTime.truncate(:second) + + assert {:ok, user} = + user + |> cast(%{last_active_at: last_active_at}, [:last_active_at]) + |> User.update_and_set_cache() + + assert user.last_active_at == last_active_at + assert {:ok, user} = User.update_last_active_at(user) + assert user.last_active_at >= test_started_at + assert user.last_active_at <= NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second) + end + + test "active_user_count/1" do + insert(:user) + insert(:user, %{local: false}) + insert(:user, %{last_active_at: NaiveDateTime.utc_now()}) + insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), days: -15)}) + insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), weeks: -6)}) + insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), months: -7)}) + insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), years: -2)}) + + assert User.active_user_count() == 2 + assert User.active_user_count(180) == 3 + assert User.active_user_count(365) == 4 + assert User.active_user_count(1000) == 5 + end + + describe "pins" do + setup do + user = insert(:user) + + [user: user, object_id: object_id_from_created_activity(user)] + end + + test "unique pins", %{user: user, object_id: object_id} do + assert {:ok, %{pinned_objects: %{^object_id => pinned_at1} = pins} = updated_user} = + User.add_pinned_object_id(user, object_id) + + assert Enum.count(pins) == 1 + + assert {:ok, %{pinned_objects: %{^object_id => pinned_at2} = pins}} = + User.add_pinned_object_id(updated_user, object_id) + + assert pinned_at1 == pinned_at2 + + assert Enum.count(pins) == 1 + end + + test "respects max_pinned_statuses limit", %{user: user, object_id: object_id} do + clear_config([:instance, :max_pinned_statuses], 1) + {:ok, updated} = User.add_pinned_object_id(user, object_id) + + object_id2 = object_id_from_created_activity(user) + + {:error, %{errors: errors}} = User.add_pinned_object_id(updated, object_id2) + assert Keyword.has_key?(errors, :pinned_objects) + end + + test "remove_pinned_object_id/2", %{user: user, object_id: object_id} do + assert {:ok, updated} = User.add_pinned_object_id(user, object_id) + + {:ok, after_remove} = User.remove_pinned_object_id(updated, object_id) + assert after_remove.pinned_objects == %{} + end + end + + defp object_id_from_created_activity(user) do + %{id: id} = insert(:note_activity, user: user) + %{object: %{data: %{"id" => object_id}}} = Activity.get_by_id_with_object(id) + object_id + end end diff --git a/test/pleroma/utils_test.exs b/test/pleroma/utils_test.exs new file mode 100644 index 000000000..c593a9490 --- /dev/null +++ b/test/pleroma/utils_test.exs @@ -0,0 +1,15 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.UtilsTest do + use ExUnit.Case, async: true + + describe "tmp_dir/1" do + test "returns unique temporary directory" do + {:ok, path} = Pleroma.Utils.tmp_dir("emoji") + assert path =~ ~r/\/emoji-(.*)-#{:os.getpid()}-(.*)/ + File.rm_rf(path) + end + end +end diff --git a/test/web/activity_pub/activity_pub_controller_test.exs b/test/pleroma/web/activity_pub/activity_pub_controller_test.exs index 57988dc1e..50315e21f 100644 --- a/test/web/activity_pub/activity_pub_controller_test.exs +++ b/test/pleroma/web/activity_pub/activity_pub_controller_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do @@ -7,7 +7,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do use Oban.Testing, repo: Pleroma.Repo alias Pleroma.Activity - alias Pleroma.Config alias Pleroma.Delivery alias Pleroma.Instances alias Pleroma.Object @@ -46,7 +45,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do end test "with the relay disabled, it returns 404", %{conn: conn} do - Config.put([:instance, :allow_relay], false) + clear_config([:instance, :allow_relay], false) conn |> get(activity_pub_path(conn, :relay)) @@ -54,7 +53,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do end test "on non-federating instance, it returns 404", %{conn: conn} do - Config.put([:instance, :federating], false) + clear_config([:instance, :federating], false) user = insert(:user) conn @@ -75,7 +74,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do end test "on non-federating instance, it returns 404", %{conn: conn} do - Config.put([:instance, :federating], false) + clear_config([:instance, :federating], false) user = insert(:user) conn @@ -156,21 +155,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do assert response == "Not found" end - - test "it requires authentication if instance is NOT federating", %{ - conn: conn - } do - user = insert(:user) - - conn = - put_req_header( - conn, - "accept", - "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"" - ) - - ensure_federating_or_authenticated(conn, "/users/#{user.nickname}.json", user) - end end describe "mastodon compatibility routes" do @@ -228,6 +212,41 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do end describe "/objects/:uuid" do + test "it doesn't return a local-only object", %{conn: conn} do + user = insert(:user) + {:ok, post} = CommonAPI.post(user, %{status: "test", visibility: "local"}) + + assert Pleroma.Web.ActivityPub.Visibility.is_local_public?(post) + + object = Object.normalize(post, fetch: false) + uuid = String.split(object.data["id"], "/") |> List.last() + + conn = + conn + |> put_req_header("accept", "application/json") + |> get("/objects/#{uuid}") + + assert json_response(conn, 404) + end + + test "returns local-only objects when authenticated", %{conn: conn} do + user = insert(:user) + {:ok, post} = CommonAPI.post(user, %{status: "test", visibility: "local"}) + + assert Pleroma.Web.ActivityPub.Visibility.is_local_public?(post) + + object = Object.normalize(post, fetch: false) + uuid = String.split(object.data["id"], "/") |> List.last() + + assert response = + conn + |> assign(:user, user) + |> put_req_header("accept", "application/activity+json") + |> get("/objects/#{uuid}") + + assert json_response(response, 200) == ObjectView.render("object.json", %{object: object}) + end + test "it returns a json representation of the object with accept application/json", %{ conn: conn } do @@ -284,6 +303,28 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do assert json_response(conn, 404) end + test "returns visible non-public messages when authenticated", %{conn: conn} do + note = insert(:direct_note) + uuid = String.split(note.data["id"], "/") |> List.last() + user = User.get_by_ap_id(note.data["actor"]) + marisa = insert(:user) + + assert conn + |> assign(:user, marisa) + |> put_req_header("accept", "application/activity+json") + |> get("/objects/#{uuid}") + |> json_response(404) + + assert response = + conn + |> assign(:user, user) + |> put_req_header("accept", "application/activity+json") + |> get("/objects/#{uuid}") + |> json_response(200) + + assert response == ObjectView.render("object.json", %{object: note}) + end + test "it returns 404 for tombstone objects", %{conn: conn} do tombstone = insert(:tombstone) uuid = String.split(tombstone.data["id"], "/") |> List.last() @@ -338,21 +379,42 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do assert "Not found" == json_response(conn2, :not_found) end + end - test "it requires authentication if instance is NOT federating", %{ - conn: conn - } do + describe "/activities/:uuid" do + test "it doesn't return a local-only activity", %{conn: conn} do user = insert(:user) - note = insert(:note) - uuid = String.split(note.data["id"], "/") |> List.last() + {:ok, post} = CommonAPI.post(user, %{status: "test", visibility: "local"}) - conn = put_req_header(conn, "accept", "application/activity+json") + assert Pleroma.Web.ActivityPub.Visibility.is_local_public?(post) + + uuid = String.split(post.data["id"], "/") |> List.last() - ensure_federating_or_authenticated(conn, "/objects/#{uuid}", user) + conn = + conn + |> put_req_header("accept", "application/json") + |> get("/activities/#{uuid}") + + assert json_response(conn, 404) + end + + test "returns local-only activities when authenticated", %{conn: conn} do + user = insert(:user) + {:ok, post} = CommonAPI.post(user, %{status: "test", visibility: "local"}) + + assert Pleroma.Web.ActivityPub.Visibility.is_local_public?(post) + + uuid = String.split(post.data["id"], "/") |> List.last() + + assert response = + conn + |> assign(:user, user) + |> put_req_header("accept", "application/activity+json") + |> get("/activities/#{uuid}") + + assert json_response(response, 200) == ObjectView.render("object.json", %{object: post}) end - end - describe "/activities/:uuid" do test "it returns a json representation of the activity", %{conn: conn} do activity = insert(:note_activity) uuid = String.split(activity.data["id"], "/") |> List.last() @@ -377,6 +439,28 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do assert json_response(conn, 404) end + test "returns visible non-public messages when authenticated", %{conn: conn} do + note = insert(:direct_note_activity) + uuid = String.split(note.data["id"], "/") |> List.last() + user = User.get_by_ap_id(note.data["actor"]) + marisa = insert(:user) + + assert conn + |> assign(:user, marisa) + |> put_req_header("accept", "application/activity+json") + |> get("/activities/#{uuid}") + |> json_response(404) + + assert response = + conn + |> assign(:user, user) + |> put_req_header("accept", "application/activity+json") + |> get("/activities/#{uuid}") + |> json_response(200) + + assert response == ObjectView.render("object.json", %{object: note}) + end + test "it caches a response", %{conn: conn} do activity = insert(:note_activity) uuid = String.split(activity.data["id"], "/") |> List.last() @@ -421,23 +505,11 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do assert "Not found" == json_response(conn2, :not_found) end - - test "it requires authentication if instance is NOT federating", %{ - conn: conn - } do - user = insert(:user) - activity = insert(:note_activity) - uuid = String.split(activity.data["id"], "/") |> List.last() - - conn = put_req_header(conn, "accept", "application/activity+json") - - ensure_federating_or_authenticated(conn, "/activities/#{uuid}", user) - end end describe "/inbox" do test "it inserts an incoming activity into the database", %{conn: conn} do - data = File.read!("test/fixtures/mastodon-post-activity.json") |> Poison.decode!() + data = File.read!("test/fixtures/mastodon-post-activity.json") |> Jason.decode!() conn = conn @@ -465,9 +537,9 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do data = File.read!("test/fixtures/mastodon-post-activity.json") - |> Poison.decode!() + |> Jason.decode!() |> Map.put("actor", user.ap_id) - |> put_in(["object", "attridbutedTo"], user.ap_id) + |> put_in(["object", "attributedTo"], user.ap_id) conn = conn @@ -482,7 +554,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do end test "it clears `unreachable` federation status of the sender", %{conn: conn} do - data = File.read!("test/fixtures/mastodon-post-activity.json") |> Poison.decode!() + data = File.read!("test/fixtures/mastodon-post-activity.json") |> Jason.decode!() sender_url = data["actor"] Instances.set_consistently_unreachable(sender_url) @@ -499,7 +571,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do end test "accept follow activity", %{conn: conn} do - Pleroma.Config.put([:instance, :federating], true) + clear_config([:instance, :federating], true) relay = Relay.get_actor() assert {:ok, %Activity{} = activity} = Relay.follow("https://relay.mastodon.host/actor") @@ -540,12 +612,12 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do test "without valid signature, " <> "it only accepts Create activities and requires enabled federation", %{conn: conn} do - data = File.read!("test/fixtures/mastodon-post-activity.json") |> Poison.decode!() - non_create_data = File.read!("test/fixtures/mastodon-announce.json") |> Poison.decode!() + data = File.read!("test/fixtures/mastodon-post-activity.json") |> Jason.decode!() + non_create_data = File.read!("test/fixtures/mastodon-announce.json") |> Jason.decode!() conn = put_req_header(conn, "content-type", "application/activity+json") - Config.put([:instance, :federating], false) + clear_config([:instance, :federating], false) conn |> post("/inbox", data) @@ -555,7 +627,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do |> post("/inbox", non_create_data) |> json_response(403) - Config.put([:instance, :federating], true) + clear_config([:instance, :federating], true) ret_conn = post(conn, "/inbox", data) assert "ok" == json_response(ret_conn, 200) @@ -564,20 +636,204 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do |> post("/inbox", non_create_data) |> json_response(400) end + + test "accepts Add/Remove activities", %{conn: conn} do + object_id = "c61d6733-e256-4fe1-ab13-1e369789423f" + + status = + File.read!("test/fixtures/statuses/note.json") + |> String.replace("{{nickname}}", "lain") + |> String.replace("{{object_id}}", object_id) + + object_url = "https://example.com/objects/#{object_id}" + + user = + File.read!("test/fixtures/users_mock/user.json") + |> String.replace("{{nickname}}", "lain") + + actor = "https://example.com/users/lain" + + Tesla.Mock.mock(fn + %{ + method: :get, + url: ^object_url + } -> + %Tesla.Env{ + status: 200, + body: status, + headers: [{"content-type", "application/activity+json"}] + } + + %{ + method: :get, + url: ^actor + } -> + %Tesla.Env{ + status: 200, + body: user, + headers: [{"content-type", "application/activity+json"}] + } + + %{method: :get, url: "https://example.com/users/lain/collections/featured"} -> + %Tesla.Env{ + status: 200, + body: + "test/fixtures/users_mock/masto_featured.json" + |> File.read!() + |> String.replace("{{domain}}", "example.com") + |> String.replace("{{nickname}}", "lain"), + headers: [{"content-type", "application/activity+json"}] + } + end) + + data = %{ + "id" => "https://example.com/objects/d61d6733-e256-4fe1-ab13-1e369789423f", + "actor" => actor, + "object" => object_url, + "target" => "https://example.com/users/lain/collections/featured", + "type" => "Add", + "to" => [Pleroma.Constants.as_public()] + } + + assert "ok" == + conn + |> assign(:valid_signature, true) + |> put_req_header("content-type", "application/activity+json") + |> post("/inbox", data) + |> json_response(200) + + ObanHelpers.perform(all_enqueued(worker: ReceiverWorker)) + assert Activity.get_by_ap_id(data["id"]) + user = User.get_cached_by_ap_id(data["actor"]) + assert user.pinned_objects[data["object"]] + + data = %{ + "id" => "https://example.com/objects/d61d6733-e256-4fe1-ab13-1e369789423d", + "actor" => actor, + "object" => object_url, + "target" => "https://example.com/users/lain/collections/featured", + "type" => "Remove", + "to" => [Pleroma.Constants.as_public()] + } + + assert "ok" == + conn + |> assign(:valid_signature, true) + |> put_req_header("content-type", "application/activity+json") + |> post("/inbox", data) + |> json_response(200) + + ObanHelpers.perform(all_enqueued(worker: ReceiverWorker)) + user = refresh_record(user) + refute user.pinned_objects[data["object"]] + end + + test "mastodon pin/unpin", %{conn: conn} do + status_id = "105786274556060421" + + status = + File.read!("test/fixtures/statuses/masto-note.json") + |> String.replace("{{nickname}}", "lain") + |> String.replace("{{status_id}}", status_id) + + status_url = "https://example.com/users/lain/statuses/#{status_id}" + + user = + File.read!("test/fixtures/users_mock/user.json") + |> String.replace("{{nickname}}", "lain") + + actor = "https://example.com/users/lain" + + Tesla.Mock.mock(fn + %{ + method: :get, + url: ^status_url + } -> + %Tesla.Env{ + status: 200, + body: status, + headers: [{"content-type", "application/activity+json"}] + } + + %{ + method: :get, + url: ^actor + } -> + %Tesla.Env{ + status: 200, + body: user, + headers: [{"content-type", "application/activity+json"}] + } + + %{method: :get, url: "https://example.com/users/lain/collections/featured"} -> + %Tesla.Env{ + status: 200, + body: + "test/fixtures/users_mock/masto_featured.json" + |> File.read!() + |> String.replace("{{domain}}", "example.com") + |> String.replace("{{nickname}}", "lain"), + headers: [{"content-type", "application/activity+json"}] + } + end) + + data = %{ + "@context" => "https://www.w3.org/ns/activitystreams", + "actor" => actor, + "object" => status_url, + "target" => "https://example.com/users/lain/collections/featured", + "type" => "Add" + } + + assert "ok" == + conn + |> assign(:valid_signature, true) + |> put_req_header("content-type", "application/activity+json") + |> post("/inbox", data) + |> json_response(200) + + ObanHelpers.perform(all_enqueued(worker: ReceiverWorker)) + assert Activity.get_by_object_ap_id_with_object(data["object"]) + user = User.get_cached_by_ap_id(data["actor"]) + assert user.pinned_objects[data["object"]] + + data = %{ + "actor" => actor, + "object" => status_url, + "target" => "https://example.com/users/lain/collections/featured", + "type" => "Remove" + } + + assert "ok" == + conn + |> assign(:valid_signature, true) + |> put_req_header("content-type", "application/activity+json") + |> post("/inbox", data) + |> json_response(200) + + ObanHelpers.perform(all_enqueued(worker: ReceiverWorker)) + assert Activity.get_by_object_ap_id_with_object(data["object"]) + user = refresh_record(user) + refute user.pinned_objects[data["object"]] + end end describe "/users/:nickname/inbox" do setup do data = File.read!("test/fixtures/mastodon-post-activity.json") - |> Poison.decode!() + |> Jason.decode!() [data: data] end test "it inserts an incoming activity into the database", %{conn: conn, data: data} do user = insert(:user) - data = Map.put(data, "bcc", [user.ap_id]) + + data = + data + |> Map.put("bcc", [user.ap_id]) + |> Kernel.put_in(["object", "bcc"], [user.ap_id]) conn = conn @@ -594,8 +850,11 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do user = insert(:user) data = - Map.put(data, "to", user.ap_id) - |> Map.delete("cc") + data + |> Map.put("to", user.ap_id) + |> Map.put("cc", []) + |> Kernel.put_in(["object", "to"], user.ap_id) + |> Kernel.put_in(["object", "cc"], []) conn = conn @@ -612,8 +871,11 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do user = insert(:user) data = - Map.put(data, "cc", user.ap_id) - |> Map.delete("to") + data + |> Map.put("to", []) + |> Map.put("cc", user.ap_id) + |> Kernel.put_in(["object", "to"], []) + |> Kernel.put_in(["object", "cc"], user.ap_id) conn = conn @@ -631,9 +893,13 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do user = insert(:user) data = - Map.put(data, "bcc", user.ap_id) - |> Map.delete("to") - |> Map.delete("cc") + data + |> Map.put("to", []) + |> Map.put("cc", []) + |> Map.put("bcc", user.ap_id) + |> Kernel.put_in(["object", "to"], []) + |> Kernel.put_in(["object", "cc"], []) + |> Kernel.put_in(["object", "bcc"], user.ap_id) conn = conn @@ -681,7 +947,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do recipient = insert(:user) actor = insert(:user, %{ap_id: "http://mastodon.example.org/users/actor"}) - {:ok, recipient} = User.follow(recipient, actor) + {:ok, recipient, actor} = User.follow(recipient, actor) object = data["object"] @@ -718,7 +984,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do test "it returns a note activity in a collection", %{conn: conn} do note_activity = insert(:direct_note_activity) - note_object = Object.normalize(note_activity) + note_object = Object.normalize(note_activity, fetch: false) user = User.get_cached_by_ap_id(hd(note_activity.data["to"])) conn = @@ -748,29 +1014,34 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do assert Instances.reachable?(sender_host) end + @tag capture_log: true test "it removes all follower collections but actor's", %{conn: conn} do [actor, recipient] = insert_pair(:user) - data = - File.read!("test/fixtures/activitypub-client-post-activity.json") - |> Poison.decode!() + to = [ + recipient.ap_id, + recipient.follower_address, + "https://www.w3.org/ns/activitystreams#Public" + ] - object = Map.put(data["object"], "attributedTo", actor.ap_id) + cc = [recipient.follower_address, actor.follower_address] - data = - data - |> Map.put("id", Utils.generate_object_id()) - |> Map.put("actor", actor.ap_id) - |> Map.put("object", object) - |> Map.put("cc", [ - recipient.follower_address, - actor.follower_address - ]) - |> Map.put("to", [ - recipient.ap_id, - recipient.follower_address, - "https://www.w3.org/ns/activitystreams#Public" - ]) + data = %{ + "@context" => ["https://www.w3.org/ns/activitystreams"], + "type" => "Create", + "id" => Utils.generate_activity_id(), + "to" => to, + "cc" => cc, + "actor" => actor.ap_id, + "object" => %{ + "type" => "Note", + "to" => to, + "cc" => cc, + "content" => "It's a note", + "attributedTo" => actor.ap_id, + "id" => Utils.generate_object_id() + } + } conn |> assign(:valid_signature, true) @@ -780,7 +1051,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do ObanHelpers.perform(all_enqueued(worker: ReceiverWorker)) - activity = Activity.get_by_ap_id(data["id"]) + assert activity = Activity.get_by_ap_id(data["id"]) assert activity.id assert actor.follower_address in activity.recipients @@ -805,6 +1076,141 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do assert json_response(ret_conn, 200) end + + @tag capture_log: true + test "forwarded report", %{conn: conn} do + admin = insert(:user, is_admin: true) + actor = insert(:user, local: false) + remote_domain = URI.parse(actor.ap_id).host + reported_user = insert(:user) + + note = insert(:note_activity, user: reported_user) + + data = %{ + "@context" => [ + "https://www.w3.org/ns/activitystreams", + "https://#{remote_domain}/schemas/litepub-0.1.jsonld", + %{ + "@language" => "und" + } + ], + "actor" => actor.ap_id, + "cc" => [ + reported_user.ap_id + ], + "content" => "test", + "context" => "context", + "id" => "http://#{remote_domain}/activities/02be56cf-35e3-46b4-b2c6-47ae08dfee9e", + "nickname" => reported_user.nickname, + "object" => [ + reported_user.ap_id, + %{ + "actor" => %{ + "actor_type" => "Person", + "approval_pending" => false, + "avatar" => "", + "confirmation_pending" => false, + "deactivated" => false, + "display_name" => "test user", + "id" => reported_user.id, + "local" => false, + "nickname" => reported_user.nickname, + "registration_reason" => nil, + "roles" => %{ + "admin" => false, + "moderator" => false + }, + "tags" => [], + "url" => reported_user.ap_id + }, + "content" => "", + "id" => note.data["id"], + "published" => note.data["published"], + "type" => "Note" + } + ], + "published" => note.data["published"], + "state" => "open", + "to" => [], + "type" => "Flag" + } + + conn + |> assign(:valid_signature, true) + |> put_req_header("content-type", "application/activity+json") + |> post("/users/#{reported_user.nickname}/inbox", data) + |> json_response(200) + + ObanHelpers.perform(all_enqueued(worker: ReceiverWorker)) + + assert Pleroma.Repo.aggregate(Activity, :count, :id) == 2 + + ObanHelpers.perform_all() + + Swoosh.TestAssertions.assert_email_sent( + to: {admin.name, admin.email}, + html_body: ~r/Reported Account:/i + ) + end + + @tag capture_log: true + test "forwarded report from mastodon", %{conn: conn} do + admin = insert(:user, is_admin: true) + actor = insert(:user, local: false) + remote_domain = URI.parse(actor.ap_id).host + remote_actor = "https://#{remote_domain}/actor" + [reported_user, another] = insert_list(2, :user) + + note = insert(:note_activity, user: reported_user) + + Pleroma.Web.CommonAPI.favorite(another, note.id) + + mock_json_body = + "test/fixtures/mastodon/application_actor.json" + |> File.read!() + |> String.replace("{{DOMAIN}}", remote_domain) + + Tesla.Mock.mock(fn %{url: ^remote_actor} -> + %Tesla.Env{ + status: 200, + body: mock_json_body, + headers: [{"content-type", "application/activity+json"}] + } + end) + + data = %{ + "@context" => "https://www.w3.org/ns/activitystreams", + "actor" => remote_actor, + "content" => "test report", + "id" => "https://#{remote_domain}/e3b12fd1-948c-446e-b93b-a5e67edbe1d8", + "object" => [ + reported_user.ap_id, + note.data["object"] + ], + "type" => "Flag" + } + + conn + |> assign(:valid_signature, true) + |> put_req_header("content-type", "application/activity+json") + |> post("/users/#{reported_user.nickname}/inbox", data) + |> json_response(200) + + ObanHelpers.perform(all_enqueued(worker: ReceiverWorker)) + + flag_activity = "Flag" |> Pleroma.Activity.Queries.by_type() |> Pleroma.Repo.one() + reported_user_ap_id = reported_user.ap_id + + [^reported_user_ap_id, flag_data] = flag_activity.data["object"] + + Enum.each(~w(actor content id published type), &Map.has_key?(flag_data, &1)) + ObanHelpers.perform_all() + + Swoosh.TestAssertions.assert_email_sent( + to: {admin.name, admin.email}, + html_body: ~r/#{note.data["object"]}/i + ) + end end describe "GET /users/:nickname/outbox" do @@ -869,7 +1275,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do test "it returns a note activity in a collection", %{conn: conn} do note_activity = insert(:note_activity) - note_object = Object.normalize(note_activity) + note_object = Object.normalize(note_activity, fetch: false) user = User.get_cached_by_ap_id(note_activity.data["actor"]) conn = @@ -894,25 +1300,46 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do assert response(conn, 200) =~ announce_activity.data["object"] end - test "it requires authentication if instance is NOT federating", %{ - conn: conn - } do - user = insert(:user) - conn = put_req_header(conn, "accept", "application/activity+json") + test "It returns poll Answers when authenticated", %{conn: conn} do + poller = insert(:user) + voter = insert(:user) + + {:ok, activity} = + CommonAPI.post(poller, %{ + status: "suya...", + poll: %{options: ["suya", "suya.", "suya.."], expires_in: 10} + }) + + assert question = Object.normalize(activity, fetch: false) + + {:ok, [activity], _object} = CommonAPI.vote(voter, question, [1]) - ensure_federating_or_authenticated(conn, "/users/#{user.nickname}/outbox", user) + assert outbox_get = + conn + |> assign(:user, voter) + |> put_req_header("accept", "application/activity+json") + |> get(voter.ap_id <> "/outbox?page=true") + |> json_response(200) + + assert [answer_outbox] = outbox_get["orderedItems"] + assert answer_outbox["id"] == activity.data["id"] end end describe "POST /users/:nickname/outbox (C2S)" do + setup do: clear_config([:instance, :limit]) + setup do [ activity: %{ "@context" => "https://www.w3.org/ns/activitystreams", "type" => "Create", - "object" => %{"type" => "Note", "content" => "AP C2S test"}, - "to" => "https://www.w3.org/ns/activitystreams#Public", - "cc" => [] + "object" => %{ + "type" => "Note", + "content" => "AP C2S test", + "to" => "https://www.w3.org/ns/activitystreams#Public", + "cc" => [] + } } ] end @@ -950,7 +1377,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do assert Activity.get_by_ap_id(result["id"]) assert result["object"] - assert %Object{data: object} = Object.normalize(result["object"]) + assert %Object{data: object} = Object.normalize(result["object"], fetch: false) assert object["content"] == activity["object"]["content"] end @@ -986,7 +1413,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do assert Activity.get_by_ap_id(response["id"]) assert response["object"] - assert %Object{data: response_object} = Object.normalize(response["object"]) + assert %Object{data: response_object} = Object.normalize(response["object"], fetch: false) assert response_object["sensitive"] == true assert response_object["content"] == activity["object"]["content"] @@ -1014,23 +1441,23 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do test "it erects a tombstone when receiving a delete activity", %{conn: conn} do note_activity = insert(:note_activity) - note_object = Object.normalize(note_activity) + note_object = Object.normalize(note_activity, fetch: false) user = User.get_cached_by_ap_id(note_activity.data["actor"]) data = %{ - type: "Delete", - object: %{ - id: note_object.data["id"] + "type" => "Delete", + "object" => %{ + "id" => note_object.data["id"] } } - conn = + result = conn |> assign(:user, user) |> put_req_header("content-type", "application/activity+json") |> post("/users/#{user.nickname}/outbox", data) + |> json_response(201) - result = json_response(conn, 201) assert Activity.get_by_ap_id(result["id"]) assert object = Object.get_by_ap_id(note_object.data["id"]) @@ -1039,7 +1466,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do test "it rejects delete activity of object from other actor", %{conn: conn} do note_activity = insert(:note_activity) - note_object = Object.normalize(note_activity) + note_object = Object.normalize(note_activity, fetch: false) user = insert(:user) data = %{ @@ -1055,12 +1482,12 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do |> put_req_header("content-type", "application/activity+json") |> post("/users/#{user.nickname}/outbox", data) - assert json_response(conn, 400) + assert json_response(conn, 403) end test "it increases like count when receiving a like action", %{conn: conn} do note_activity = insert(:note_activity) - note_object = Object.normalize(note_activity) + note_object = Object.normalize(note_activity, fetch: false) user = User.get_cached_by_ap_id(note_activity.data["actor"]) data = %{ @@ -1117,10 +1544,24 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do assert cirno_outbox["attributedTo"] == nil assert cirno_outbox["actor"] == cirno.ap_id - assert cirno_object = Object.normalize(cirno_outbox["object"]) + assert cirno_object = Object.normalize(cirno_outbox["object"], fetch: false) assert cirno_object.data["actor"] == cirno.ap_id assert cirno_object.data["attributedTo"] == cirno.ap_id end + + test "Character limitation", %{conn: conn, activity: activity} do + clear_config([:instance, :limit], 5) + user = insert(:user) + + result = + conn + |> assign(:user, user) + |> put_req_header("content-type", "application/activity+json") + |> post("/users/#{user.nickname}/outbox", activity) + |> json_response(400) + + assert result == "Character limit (5 characters) exceeded, contains 11 characters" + end end describe "/relay/followers" do @@ -1138,7 +1579,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do end test "on non-federating instance, it returns 404", %{conn: conn} do - Config.put([:instance, :federating], false) + clear_config([:instance, :federating], false) user = insert(:user) conn @@ -1159,7 +1600,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do end test "on non-federating instance, it returns 404", %{conn: conn} do - Config.put([:instance, :federating], false) + clear_config([:instance, :federating], false) user = insert(:user) conn @@ -1366,7 +1807,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do test "it tracks a signed object fetch", %{conn: conn} do user = insert(:user, local: false) activity = insert(:note_activity) - object = Object.normalize(activity) + object = Object.normalize(activity, fetch: false) object_path = String.trim_leading(object.data["id"], Pleroma.Web.Endpoint.url()) @@ -1382,7 +1823,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do test "it tracks a signed activity fetch", %{conn: conn} do user = insert(:user, local: false) activity = insert(:note_activity) - object = Object.normalize(activity) + object = Object.normalize(activity, fetch: false) activity_path = String.trim_leading(activity.data["id"], Pleroma.Web.Endpoint.url()) @@ -1399,7 +1840,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do user = insert(:user, local: false) other_user = insert(:user, local: false) activity = insert(:note_activity) - object = Object.normalize(activity) + object = Object.normalize(activity, fetch: false) object_path = String.trim_leading(object.data["id"], Pleroma.Web.Endpoint.url()) @@ -1423,7 +1864,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do user = insert(:user, local: false) other_user = insert(:user, local: false) activity = insert(:note_activity) - object = Object.normalize(activity) + object = Object.normalize(activity, fetch: false) activity_path = String.trim_leading(activity.data["id"], Pleroma.Web.Endpoint.url()) @@ -1471,7 +1912,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do desc = "Description of the image" image = %Plug.Upload{ - content_type: "image/jpg", + content_type: "image/jpeg", path: Path.absname("test/fixtures/image.jpg"), filename: "an_image.jpg" } @@ -1488,6 +1929,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do assert [%{"href" => object_href, "mediaType" => object_mediatype}] = object["url"] assert is_binary(object_href) assert object_mediatype == "image/jpeg" + assert String.ends_with?(object_href, ".jpg") activity_request = %{ "@context" => "https://www.w3.org/ns/activitystreams", @@ -1495,10 +1937,10 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do "object" => %{ "type" => "Note", "content" => "AP C2S test, attachment", - "attachment" => [object] - }, - "to" => "https://www.w3.org/ns/activitystreams#Public", - "cc" => [] + "attachment" => [object], + "to" => "https://www.w3.org/ns/activitystreams#Public", + "cc" => [] + } } activity_response = @@ -1512,7 +1954,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do assert activity_response["actor"] == user.ap_id assert %Object{data: %{"attachment" => [attachment]}} = - Object.normalize(activity_response["object"]) + Object.normalize(activity_response["object"], fetch: false) assert attachment["type"] == "Document" assert attachment["name"] == desc @@ -1531,4 +1973,29 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do |> json_response(403) end end + + test "pinned collection", %{conn: conn} do + clear_config([:instance, :max_pinned_statuses], 2) + user = insert(:user) + objects = insert_list(2, :note, user: user) + + Enum.reduce(objects, user, fn %{data: %{"id" => object_id}}, user -> + {:ok, updated} = User.add_pinned_object_id(user, object_id) + updated + end) + + %{nickname: nickname, featured_address: featured_address, pinned_objects: pinned_objects} = + refresh_record(user) + + %{"id" => ^featured_address, "orderedItems" => items, "totalItems" => 2} = + conn + |> get("/users/#{nickname}/collections/featured") + |> json_response(200) + + object_ids = Enum.map(items, & &1["id"]) + + assert Enum.all?(pinned_objects, fn {obj_id, _} -> + obj_id in object_ids + end) + end end diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/pleroma/web/activity_pub/activity_pub_test.exs index 03f968aaf..574ef0d71 100644 --- a/test/web/activity_pub/activity_pub_test.exs +++ b/test/pleroma/web/activity_pub/activity_pub_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.ActivityPubTest do @@ -190,37 +190,191 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do assert user.accepts_chat_messages end + + test "works for guppe actors" do + user_id = "https://gup.pe/u/bernie2020" + + Tesla.Mock.mock(fn + %{method: :get, url: ^user_id} -> + %Tesla.Env{ + status: 200, + body: File.read!("test/fixtures/guppe-actor.json"), + headers: [{"content-type", "application/activity+json"}] + } + end) + + {:ok, user} = ActivityPub.make_user_from_ap_id(user_id) + + assert user.name == "Bernie2020 group" + assert user.actor_type == "Group" + end + + test "works for bridgy actors" do + user_id = "https://fed.brid.gy/jk.nipponalba.scot" + + Tesla.Mock.mock(fn + %{method: :get, url: ^user_id} -> + %Tesla.Env{ + status: 200, + body: File.read!("test/fixtures/bridgy/actor.json"), + headers: [{"content-type", "application/activity+json"}] + } + end) + + {:ok, user} = ActivityPub.make_user_from_ap_id(user_id) + + assert user.actor_type == "Person" + + assert user.avatar == %{ + "type" => "Image", + "url" => [%{"href" => "https://jk.nipponalba.scot/images/profile.jpg"}] + } + + assert user.banner == %{ + "type" => "Image", + "url" => [%{"href" => "https://jk.nipponalba.scot/images/profile.jpg"}] + } + end + + test "fetches user featured collection" do + ap_id = "https://example.com/users/lain" + + featured_url = "https://example.com/users/lain/collections/featured" + + user_data = + "test/fixtures/users_mock/user.json" + |> File.read!() + |> String.replace("{{nickname}}", "lain") + |> Jason.decode!() + |> Map.put("featured", featured_url) + |> Jason.encode!() + + object_id = Ecto.UUID.generate() + + featured_data = + "test/fixtures/mastodon/collections/featured.json" + |> File.read!() + |> String.replace("{{domain}}", "example.com") + |> String.replace("{{nickname}}", "lain") + |> String.replace("{{object_id}}", object_id) + + object_url = "https://example.com/objects/#{object_id}" + + object_data = + "test/fixtures/statuses/note.json" + |> File.read!() + |> String.replace("{{object_id}}", object_id) + |> String.replace("{{nickname}}", "lain") + + Tesla.Mock.mock(fn + %{ + method: :get, + url: ^ap_id + } -> + %Tesla.Env{ + status: 200, + body: user_data, + headers: [{"content-type", "application/activity+json"}] + } + + %{ + method: :get, + url: ^featured_url + } -> + %Tesla.Env{ + status: 200, + body: featured_data, + headers: [{"content-type", "application/activity+json"}] + } + end) + + Tesla.Mock.mock_global(fn + %{ + method: :get, + url: ^object_url + } -> + %Tesla.Env{ + status: 200, + body: object_data, + headers: [{"content-type", "application/activity+json"}] + } + end) + + {:ok, user} = ActivityPub.make_user_from_ap_id(ap_id) + Process.sleep(50) + + assert user.featured_address == featured_url + assert Map.has_key?(user.pinned_objects, object_url) + + in_db = Pleroma.User.get_by_ap_id(ap_id) + assert in_db.featured_address == featured_url + assert Map.has_key?(user.pinned_objects, object_url) + + assert %{data: %{"id" => ^object_url}} = Object.get_by_ap_id(object_url) + end end test "it fetches the appropriate tag-restricted posts" do user = insert(:user) - {:ok, status_one} = CommonAPI.post(user, %{status: ". #test"}) + {:ok, status_one} = CommonAPI.post(user, %{status: ". #TEST"}) {:ok, status_two} = CommonAPI.post(user, %{status: ". #essais"}) - {:ok, status_three} = CommonAPI.post(user, %{status: ". #test #reject"}) + {:ok, status_three} = CommonAPI.post(user, %{status: ". #test #Reject"}) - fetch_one = ActivityPub.fetch_activities([], %{type: "Create", tag: "test"}) + {:ok, status_four} = CommonAPI.post(user, %{status: ". #Any1 #any2"}) + {:ok, status_five} = CommonAPI.post(user, %{status: ". #Any2 #any1"}) - fetch_two = ActivityPub.fetch_activities([], %{type: "Create", tag: ["test", "essais"]}) + for hashtag_timeline_strategy <- [:enabled, :disabled] do + clear_config([:features, :improved_hashtag_timeline], hashtag_timeline_strategy) - fetch_three = - ActivityPub.fetch_activities([], %{ - type: "Create", - tag: ["test", "essais"], - tag_reject: ["reject"] - }) + fetch_one = ActivityPub.fetch_activities([], %{type: "Create", tag: "test"}) - fetch_four = - ActivityPub.fetch_activities([], %{ - type: "Create", - tag: ["test"], - tag_all: ["test", "reject"] - }) + fetch_two = ActivityPub.fetch_activities([], %{type: "Create", tag: ["TEST", "essais"]}) + + fetch_three = + ActivityPub.fetch_activities([], %{ + type: "Create", + tag: ["test", "Essais"], + tag_reject: ["reject"] + }) + + fetch_four = + ActivityPub.fetch_activities([], %{ + type: "Create", + tag: ["test"], + tag_all: ["test", "REJECT"] + }) + + # Testing that deduplication (if needed) is done on DB (not Ecto) level; :limit is important + fetch_five = + ActivityPub.fetch_activities([], %{ + type: "Create", + tag: ["ANY1", "any2"], + limit: 2 + }) + + fetch_six = + ActivityPub.fetch_activities([], %{ + type: "Create", + tag: ["any1", "Any2"], + tag_all: [], + tag_reject: [] + }) + + # Regression test: passing empty lists as filter options shouldn't affect the results + assert fetch_five == fetch_six + + [fetch_one, fetch_two, fetch_three, fetch_four, fetch_five] = + Enum.map([fetch_one, fetch_two, fetch_three, fetch_four, fetch_five], fn statuses -> + Enum.map(statuses, fn s -> Repo.preload(s, object: :hashtags) end) + end) - assert fetch_one == [status_one, status_three] - assert fetch_two == [status_one, status_two, status_three] - assert fetch_three == [status_one, status_two] - assert fetch_four == [status_three] + assert fetch_one == [status_one, status_three] + assert fetch_two == [status_one, status_two, status_three] + assert fetch_three == [status_one, status_two] + assert fetch_four == [status_three] + assert fetch_five == [status_four, status_five] + end end describe "insertion" do @@ -239,7 +393,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do } } - assert {:error, {:remote_limit_error, _}} = ActivityPub.insert(data) + assert {:error, :remote_limit} = ActivityPub.insert(data) end test "doesn't drop activities with content being null" do @@ -321,7 +475,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do } {:ok, %Activity{} = activity} = ActivityPub.insert(data) - object = Pleroma.Object.normalize(activity) + object = Pleroma.Object.normalize(activity, fetch: false) assert is_binary(activity.data["context"]) assert is_binary(object.data["context"]) @@ -344,7 +498,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do } {:ok, %Activity{} = activity} = ActivityPub.insert(data) - assert object = Object.normalize(activity) + assert object = Object.normalize(activity, fetch: false) assert is_binary(object.data["id"]) end end @@ -386,9 +540,11 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do end describe "create activities" do - test "it reverts create" do - user = insert(:user) + setup do + [user: insert(:user)] + end + test "it reverts create", %{user: user} do with_mock(Utils, [:passthrough], maybe_federate: fn _ -> {:error, :reverted} end) do assert {:error, :reverted} = ActivityPub.create(%{ @@ -407,9 +563,47 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do assert Repo.aggregate(Object, :count, :id) == 0 end - test "removes doubled 'to' recipients" do - user = insert(:user) + test "creates activity if expiration is not configured and expires_at is not passed", %{ + user: user + } do + clear_config([Pleroma.Workers.PurgeExpiredActivity, :enabled], false) + + assert {:ok, _} = + ActivityPub.create(%{ + to: ["user1", "user2"], + actor: user, + context: "", + object: %{ + "to" => ["user1", "user2"], + "type" => "Note", + "content" => "testing" + } + }) + end + + test "rejects activity if expires_at present but expiration is not configured", %{user: user} do + clear_config([Pleroma.Workers.PurgeExpiredActivity, :enabled], false) + + assert {:error, :expired_activities_disabled} = + ActivityPub.create(%{ + to: ["user1", "user2"], + actor: user, + context: "", + object: %{ + "to" => ["user1", "user2"], + "type" => "Note", + "content" => "testing" + }, + additional: %{ + "expires_at" => DateTime.utc_now() + } + }) + assert Repo.aggregate(Activity, :count, :id) == 0 + assert Repo.aggregate(Object, :count, :id) == 0 + end + + test "removes doubled 'to' recipients", %{user: user} do {:ok, activity} = ActivityPub.create(%{ to: ["user1", "user1", "user2"], @@ -427,9 +621,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do assert activity.recipients == ["user1", "user2", user.ap_id] end - test "increases user note count only for public activities" do - user = insert(:user) - + test "increases user note count only for public activities", %{user: user} do {:ok, _} = CommonAPI.post(User.get_cached_by_id(user.id), %{ status: "1", @@ -458,8 +650,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do assert user.note_count == 2 end - test "increases replies count" do - user = insert(:user) + test "increases replies count", %{user: user} do user2 = insert(:user) {:ok, activity} = CommonAPI.post(user, %{status: "1", visibility: "public"}) @@ -468,22 +659,22 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do # public {:ok, _} = CommonAPI.post(user2, Map.put(reply_data, :visibility, "public")) - assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id) + assert %{data: _data, object: object} = Activity.get_by_ap_id_with_object(ap_id) assert object.data["repliesCount"] == 1 # unlisted {:ok, _} = CommonAPI.post(user2, Map.put(reply_data, :visibility, "unlisted")) - assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id) + assert %{data: _data, object: object} = Activity.get_by_ap_id_with_object(ap_id) assert object.data["repliesCount"] == 2 # private {:ok, _} = CommonAPI.post(user2, Map.put(reply_data, :visibility, "private")) - assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id) + assert %{data: _data, object: object} = Activity.get_by_ap_id_with_object(ap_id) assert object.data["repliesCount"] == 2 # direct {:ok, _} = CommonAPI.post(user2, Map.put(reply_data, :visibility, "direct")) - assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id) + assert %{data: _data, object: object} = Activity.get_by_ap_id_with_object(ap_id) assert object.data["repliesCount"] == 2 end end @@ -585,6 +776,32 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do assert Enum.member?(activities, activity_one) end + test "doesn't return activities from deactivated users" do + _user = insert(:user) + deactivated = insert(:user) + active = insert(:user) + {:ok, activity_one} = CommonAPI.post(deactivated, %{status: "hey!"}) + {:ok, activity_two} = CommonAPI.post(active, %{status: "yay!"}) + {:ok, _updated_user} = User.set_activation(deactivated, false) + + activities = ActivityPub.fetch_activities([], %{}) + + refute Enum.member?(activities, activity_one) + assert Enum.member?(activities, activity_two) + end + + test "always see your own posts even when they address people you block" do + user = insert(:user) + blockee = insert(:user) + + {:ok, _} = User.block(user, blockee) + {:ok, activity} = CommonAPI.post(user, %{status: "hey! @#{blockee.nickname}"}) + + activities = ActivityPub.fetch_activities([], %{blocking_user: user}) + + assert Enum.member?(activities, activity) + end + test "doesn't return transitive interactions concerning blocked users" do blocker = insert(:user) blockee = insert(:user) @@ -641,7 +858,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do {:ok, activity_two} = CommonAPI.post(blockee, %{status: "hey! @#{friend.nickname}"}) - assert object = Pleroma.Object.normalize(activity_two) + assert object = Pleroma.Object.normalize(activity_two, fetch: false) data = %{ "actor" => friend.ap_id, @@ -684,12 +901,27 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do refute repeat_activity in activities end + test "see your own posts even when they adress actors from blocked domains" do + user = insert(:user) + + domain = "dogwhistle.zone" + domain_user = insert(:user, %{ap_id: "https://#{domain}/@pundit"}) + + {:ok, user} = User.block_domain(user, domain) + + {:ok, activity} = CommonAPI.post(user, %{status: "hey! @#{domain_user.nickname}"}) + + activities = ActivityPub.fetch_activities([], %{blocking_user: user}) + + assert Enum.member?(activities, activity) + end + test "does return activities from followed users on blocked domains" do domain = "meanies.social" domain_user = insert(:user, %{ap_id: "https://#{domain}/@pundit"}) blocker = insert(:user) - {:ok, blocker} = User.follow(blocker, domain_user) + {:ok, blocker, domain_user} = User.follow(blocker, domain_user) {:ok, blocker} = User.block_domain(blocker, domain) assert User.following?(blocker, domain_user) @@ -715,6 +947,22 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do refute repeat_activity in activities end + test "returns your own posts regardless of mute" do + user = insert(:user) + muted = insert(:user) + + {:ok, muted_post} = CommonAPI.post(muted, %{status: "Im stupid"}) + + {:ok, reply} = + CommonAPI.post(user, %{status: "I'm muting you", in_reply_to_status_id: muted_post.id}) + + {:ok, _} = User.mute(user, muted) + + [activity] = ActivityPub.fetch_activities([], %{muting_user: user, skip_preload: true}) + + assert activity.id == reply.id + end + test "doesn't return muted activities" do activity_one = insert(:note_activity) activity_two = insert(:note_activity) @@ -800,7 +1048,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do user = insert(:user) booster = insert(:user) - {:ok, user} = User.follow(user, booster) + {:ok, user, booster} = User.follow(user, booster) {:ok, announce} = CommonAPI.repeat(activity_three.id, booster) @@ -992,7 +1240,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do describe "uploading files" do setup do test_file = %Plug.Upload{ - content_type: "image/jpg", + content_type: "image/jpeg", path: Path.absname("test/fixtures/image.jpg"), filename: "an_image.jpg" } @@ -1008,15 +1256,15 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do test "it sets the default description depending on the configuration", %{test_file: file} do clear_config([Pleroma.Upload, :default_description]) - Pleroma.Config.put([Pleroma.Upload, :default_description], nil) + clear_config([Pleroma.Upload, :default_description], nil) {:ok, %Object{} = object} = ActivityPub.upload(file) assert object.data["name"] == "" - Pleroma.Config.put([Pleroma.Upload, :default_description], :filename) + clear_config([Pleroma.Upload, :default_description], :filename) {:ok, %Object{} = object} = ActivityPub.upload(file) assert object.data["name"] == "an_image.jpg" - Pleroma.Config.put([Pleroma.Upload, :default_description], "unnamed attachment") + clear_config([Pleroma.Upload, :default_description], "unnamed attachment") {:ok, %Object{} = object} = ActivityPub.upload(file) assert object.data["name"] == "unnamed attachment" end @@ -1083,7 +1331,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do test "creates an undo activity for a pending follow request" do follower = insert(:user) - followed = insert(:user, %{locked: true}) + followed = insert(:user, %{is_locked: true}) {:ok, _, _, follow_activity} = CommonAPI.follow(follower, followed) {:ok, activity} = ActivityPub.unfollow(follower, followed) @@ -1105,13 +1353,13 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do user2 = insert(:user) user3 = insert(:user) - {:ok, user1} = User.follow(user1, user3) + {:ok, user1, user3} = User.follow(user1, user3) assert User.following?(user1, user3) - {:ok, user2} = User.follow(user2, user3) + {:ok, user2, user3} = User.follow(user2, user3) assert User.following?(user2, user3) - {:ok, user3} = User.follow(user3, user2) + {:ok, user3, user2} = User.follow(user3, user2) assert User.following?(user3, user2) {:ok, public_activity} = CommonAPI.post(user3, %{status: "hi 1"}) @@ -1245,6 +1493,31 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do assert_called(Utils.maybe_federate(%{activity | data: new_data})) end + + test_with_mock "reverts on error", + %{ + reporter: reporter, + context: context, + target_account: target_account, + reported_activity: reported_activity, + content: content + }, + Utils, + [:passthrough], + maybe_federate: fn _ -> {:error, :reverted} end do + assert {:error, :reverted} = + ActivityPub.flag(%{ + actor: reporter, + context: context, + account: target_account, + statuses: [reported_activity], + content: content + }) + + assert Repo.aggregate(Activity, :count, :id) == 1 + assert Repo.aggregate(Object, :count, :id) == 2 + assert Repo.aggregate(Notification, :count, :id) == 0 + end end test "fetch_activities/2 returns activities addressed to a list " do @@ -1373,19 +1646,25 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do mock(fn env -> case env.url do "http://localhost:4001/users/masto_hidden_counters/following" -> - json(%{ - "@context" => "https://www.w3.org/ns/activitystreams", - "id" => "http://localhost:4001/users/masto_hidden_counters/followers" - }) + json( + %{ + "@context" => "https://www.w3.org/ns/activitystreams", + "id" => "http://localhost:4001/users/masto_hidden_counters/followers" + }, + headers: HttpRequestMock.activitypub_object_headers() + ) "http://localhost:4001/users/masto_hidden_counters/following?page=1" -> %Tesla.Env{status: 403, body: ""} "http://localhost:4001/users/masto_hidden_counters/followers" -> - json(%{ - "@context" => "https://www.w3.org/ns/activitystreams", - "id" => "http://localhost:4001/users/masto_hidden_counters/following" - }) + json( + %{ + "@context" => "https://www.w3.org/ns/activitystreams", + "id" => "http://localhost:4001/users/masto_hidden_counters/following" + }, + headers: HttpRequestMock.activitypub_object_headers() + ) "http://localhost:4001/users/masto_hidden_counters/followers?page=1" -> %Tesla.Env{status: 403, body: ""} @@ -1773,6 +2052,14 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do |> Enum.map(& &1.id) assert activities_ids == [] + + activities_ids = + %{} + |> Map.put(:reply_visibility, "self") + |> Map.put(:reply_filtering_user, nil) + |> ActivityPub.fetch_public_activities() + + assert activities_ids == [] end test "home timeline", %{users: %{u1: user}} do @@ -1839,13 +2126,13 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do defp public_messages(_) do [u1, u2, u3, u4] = insert_list(4, :user) - {:ok, u1} = User.follow(u1, u2) - {:ok, u2} = User.follow(u2, u1) - {:ok, u1} = User.follow(u1, u4) - {:ok, u4} = User.follow(u4, u1) + {:ok, u1, u2} = User.follow(u1, u2) + {:ok, u2, u1} = User.follow(u2, u1) + {:ok, u1, u4} = User.follow(u1, u4) + {:ok, u4, u1} = User.follow(u4, u1) - {:ok, u2} = User.follow(u2, u3) - {:ok, u3} = User.follow(u3, u2) + {:ok, u2, u3} = User.follow(u2, u3) + {:ok, u3, u2} = User.follow(u3, u2) {:ok, a1} = CommonAPI.post(u1, %{status: "Status"}) @@ -1938,15 +2225,15 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do defp private_messages(_) do [u1, u2, u3, u4] = insert_list(4, :user) - {:ok, u1} = User.follow(u1, u2) - {:ok, u2} = User.follow(u2, u1) - {:ok, u1} = User.follow(u1, u3) - {:ok, u3} = User.follow(u3, u1) - {:ok, u1} = User.follow(u1, u4) - {:ok, u4} = User.follow(u4, u1) + {:ok, u1, u2} = User.follow(u1, u2) + {:ok, u2, u1} = User.follow(u2, u1) + {:ok, u1, u3} = User.follow(u1, u3) + {:ok, u3, u1} = User.follow(u3, u1) + {:ok, u1, u4} = User.follow(u1, u4) + {:ok, u4, u1} = User.follow(u4, u1) - {:ok, u2} = User.follow(u2, u3) - {:ok, u3} = User.follow(u3, u2) + {:ok, u2, u3} = User.follow(u2, u3) + {:ok, u3, u2} = User.follow(u3, u2) {:ok, a1} = CommonAPI.post(u1, %{status: "Status", visibility: "private"}) @@ -2069,18 +2356,25 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do end describe "global activity expiration" do - setup do: clear_config([:mrf, :policies]) - test "creates an activity expiration for local Create activities" do - Pleroma.Config.put( - [:mrf, :policies], - Pleroma.Web.ActivityPub.MRF.ActivityExpirationPolicy + clear_config([:mrf, :policies], Pleroma.Web.ActivityPub.MRF.ActivityExpirationPolicy) + + {:ok, activity} = ActivityBuilder.insert(%{"type" => "Create", "context" => "3hu"}) + {:ok, follow} = ActivityBuilder.insert(%{"type" => "Follow", "context" => "3hu"}) + + assert_enqueued( + worker: Pleroma.Workers.PurgeExpiredActivity, + args: %{activity_id: activity.id}, + scheduled_at: + activity.inserted_at + |> DateTime.from_naive!("Etc/UTC") + |> Timex.shift(days: 365) ) - {:ok, %{id: id_create}} = ActivityBuilder.insert(%{"type" => "Create", "context" => "3hu"}) - {:ok, _follow} = ActivityBuilder.insert(%{"type" => "Follow", "context" => "3hu"}) - - assert [%{activity_id: ^id_create}] = Pleroma.ActivityExpiration |> Repo.all() + refute_enqueued( + worker: Pleroma.Workers.PurgeExpiredActivity, + args: %{activity_id: follow.id} + ) end end @@ -2125,4 +2419,95 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do assert user.nickname == orig_user.nickname end end + + describe "reply filtering" do + test "`following` still contains announcements by friends" do + user = insert(:user) + followed = insert(:user) + not_followed = insert(:user) + + User.follow(user, followed) + + {:ok, followed_post} = CommonAPI.post(followed, %{status: "Hello"}) + + {:ok, not_followed_to_followed} = + CommonAPI.post(not_followed, %{ + status: "Also hello", + in_reply_to_status_id: followed_post.id + }) + + {:ok, retoot} = CommonAPI.repeat(not_followed_to_followed.id, followed) + + params = + %{} + |> Map.put(:type, ["Create", "Announce"]) + |> Map.put(:blocking_user, user) + |> Map.put(:muting_user, user) + |> Map.put(:reply_filtering_user, user) + |> Map.put(:reply_visibility, "following") + |> Map.put(:announce_filtering_user, user) + |> Map.put(:user, user) + + activities = + [user.ap_id | User.following(user)] + |> ActivityPub.fetch_activities(params) + + followed_post_id = followed_post.id + retoot_id = retoot.id + + assert [%{id: ^followed_post_id}, %{id: ^retoot_id}] = activities + + assert length(activities) == 2 + end + + # This test is skipped because, while this is the desired behavior, + # there seems to be no good way to achieve it with the method that + # we currently use for detecting to who a reply is directed. + # This is a TODO and should be fixed by a later rewrite of the code + # in question. + @tag skip: true + test "`following` still contains self-replies by friends" do + user = insert(:user) + followed = insert(:user) + not_followed = insert(:user) + + User.follow(user, followed) + + {:ok, followed_post} = CommonAPI.post(followed, %{status: "Hello"}) + {:ok, not_followed_post} = CommonAPI.post(not_followed, %{status: "Also hello"}) + + {:ok, _followed_to_not_followed} = + CommonAPI.post(followed, %{status: "sup", in_reply_to_status_id: not_followed_post.id}) + + {:ok, _followed_self_reply} = + CommonAPI.post(followed, %{status: "Also cofe", in_reply_to_status_id: followed_post.id}) + + params = + %{} + |> Map.put(:type, ["Create", "Announce"]) + |> Map.put(:blocking_user, user) + |> Map.put(:muting_user, user) + |> Map.put(:reply_filtering_user, user) + |> Map.put(:reply_visibility, "following") + |> Map.put(:announce_filtering_user, user) + |> Map.put(:user, user) + + activities = + [user.ap_id | User.following(user)] + |> ActivityPub.fetch_activities(params) + + assert length(activities) == 2 + end + end + + test "allow fetching of accounts with an empty string name field" do + Tesla.Mock.mock(fn + %{method: :get, url: "https://princess.cat/users/mewmew"} -> + file = File.read!("test/fixtures/mewmew_no_name.json") + %Tesla.Env{status: 200, body: file, headers: HttpRequestMock.activitypub_object_headers()} + end) + + {:ok, user} = ActivityPub.make_user_from_ap_id("https://princess.cat/users/mewmew") + assert user.name == " " + end end diff --git a/test/pleroma/web/activity_pub/builder_test.exs b/test/pleroma/web/activity_pub/builder_test.exs new file mode 100644 index 000000000..3fe32bce5 --- /dev/null +++ b/test/pleroma/web/activity_pub/builder_test.exs @@ -0,0 +1,48 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ActivityPub.BuilderTest do + alias Pleroma.Web.ActivityPub.Builder + alias Pleroma.Web.CommonAPI.ActivityDraft + use Pleroma.DataCase + + import Pleroma.Factory + + describe "note/1" do + test "returns note data" do + user = insert(:user) + note = insert(:note) + user2 = insert(:user) + user3 = insert(:user) + + draft = %ActivityDraft{ + user: user, + to: [user2.ap_id], + context: "2hu", + content_html: "<h1>This is :moominmamma: note</h1>", + in_reply_to: note.id, + tags: [name: "jimm"], + summary: "test summary", + cc: [user3.ap_id], + extra: %{"custom_tag" => "test"} + } + + expected = %{ + "actor" => user.ap_id, + "attachment" => [], + "cc" => [user3.ap_id], + "content" => "<h1>This is :moominmamma: note</h1>", + "context" => "2hu", + "sensitive" => false, + "summary" => "test summary", + "tag" => ["jimm"], + "to" => [user2.ap_id], + "type" => "Note", + "custom_tag" => "test" + } + + assert {:ok, ^expected, []} = Builder.note(draft) + end + end +end diff --git a/test/web/activity_pub/mrf/activity_expiration_policy_test.exs b/test/pleroma/web/activity_pub/mrf/activity_expiration_policy_test.exs index f25cf8b12..47b07fdd9 100644 --- a/test/web/activity_pub/mrf/activity_expiration_policy_test.exs +++ b/test/pleroma/web/activity_pub/mrf/activity_expiration_policy_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.MRF.ActivityExpirationPolicyTest do @@ -18,11 +18,11 @@ defmodule Pleroma.Web.ActivityPub.MRF.ActivityExpirationPolicyTest do "object" => %{"type" => "Note"} }) - assert Timex.diff(expires_at, NaiveDateTime.utc_now(), :days) == 364 + assert Timex.diff(expires_at, DateTime.utc_now(), :days) == 364 end test "keeps existing `expires_at` if it less than the config setting" do - expires_at = NaiveDateTime.utc_now() |> Timex.shift(days: 1) + expires_at = DateTime.utc_now() |> Timex.shift(days: 1) assert {:ok, %{"type" => "Create", "expires_at" => ^expires_at}} = ActivityExpirationPolicy.filter(%{ @@ -35,7 +35,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.ActivityExpirationPolicyTest do end test "overwrites existing `expires_at` if it greater than the config setting" do - too_distant_future = NaiveDateTime.utc_now() |> Timex.shift(years: 2) + too_distant_future = DateTime.utc_now() |> Timex.shift(years: 2) assert {:ok, %{"type" => "Create", "expires_at" => expires_at}} = ActivityExpirationPolicy.filter(%{ @@ -46,7 +46,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.ActivityExpirationPolicyTest do "object" => %{"type" => "Note"} }) - assert Timex.diff(expires_at, NaiveDateTime.utc_now(), :days) == 364 + assert Timex.diff(expires_at, DateTime.utc_now(), :days) == 364 end test "ignores remote activities" do diff --git a/test/web/activity_pub/mrf/anti_followbot_policy_test.exs b/test/pleroma/web/activity_pub/mrf/anti_followbot_policy_test.exs index 3c795f5ac..d5af3a9b6 100644 --- a/test/web/activity_pub/mrf/anti_followbot_policy_test.exs +++ b/test/pleroma/web/activity_pub/mrf/anti_followbot_policy_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.MRF.AntiFollowbotPolicyTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true import Pleroma.Factory alias Pleroma.Web.ActivityPub.MRF.AntiFollowbotPolicy diff --git a/test/web/activity_pub/mrf/anti_link_spam_policy_test.exs b/test/pleroma/web/activity_pub/mrf/anti_link_spam_policy_test.exs index 6867c9853..5b990451c 100644 --- a/test/web/activity_pub/mrf/anti_link_spam_policy_test.exs +++ b/test/pleroma/web/activity_pub/mrf/anti_link_spam_policy_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicyTest do diff --git a/test/web/activity_pub/mrf/ensure_re_prepended_test.exs b/test/pleroma/web/activity_pub/mrf/ensure_re_prepended_test.exs index 9a283f27d..89439b65f 100644 --- a/test/web/activity_pub/mrf/ensure_re_prepended_test.exs +++ b/test/pleroma/web/activity_pub/mrf/ensure_re_prepended_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.MRF.EnsureRePrependedTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true alias Pleroma.Activity alias Pleroma.Object diff --git a/test/pleroma/web/activity_pub/mrf/follow_bot_policy_test.exs b/test/pleroma/web/activity_pub/mrf/follow_bot_policy_test.exs new file mode 100644 index 000000000..a61562558 --- /dev/null +++ b/test/pleroma/web/activity_pub/mrf/follow_bot_policy_test.exs @@ -0,0 +1,126 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ActivityPub.MRF.FollowBotPolicyTest do + use Pleroma.DataCase, async: true + + alias Pleroma.User + alias Pleroma.Web.ActivityPub.MRF.FollowBotPolicy + + import Pleroma.Factory + + describe "FollowBotPolicy" do + test "follows remote users" do + bot = insert(:user, actor_type: "Service") + remote_user = insert(:user, local: false) + clear_config([:mrf_follow_bot, :follower_nickname], bot.nickname) + + message = %{ + "@context" => "https://www.w3.org/ns/activitystreams", + "to" => [remote_user.follower_address], + "cc" => ["https://www.w3.org/ns/activitystreams#Public"], + "type" => "Create", + "object" => %{ + "content" => "Test post", + "type" => "Note", + "attributedTo" => remote_user.ap_id, + "inReplyTo" => nil + }, + "actor" => remote_user.ap_id + } + + refute User.following?(bot, remote_user) + + assert User.get_follow_requests(remote_user) |> length == 0 + + FollowBotPolicy.filter(message) + + assert User.get_follow_requests(remote_user) |> length == 1 + end + + test "does not follow users with #nobot in bio" do + bot = insert(:user, actor_type: "Service") + remote_user = insert(:user, %{local: false, bio: "go away bots! #nobot"}) + clear_config([:mrf_follow_bot, :follower_nickname], bot.nickname) + + message = %{ + "@context" => "https://www.w3.org/ns/activitystreams", + "to" => [remote_user.follower_address], + "cc" => ["https://www.w3.org/ns/activitystreams#Public"], + "type" => "Create", + "object" => %{ + "content" => "I don't like follow bots", + "type" => "Note", + "attributedTo" => remote_user.ap_id, + "inReplyTo" => nil + }, + "actor" => remote_user.ap_id + } + + refute User.following?(bot, remote_user) + + assert User.get_follow_requests(remote_user) |> length == 0 + + FollowBotPolicy.filter(message) + + assert User.get_follow_requests(remote_user) |> length == 0 + end + + test "does not follow local users" do + bot = insert(:user, actor_type: "Service") + local_user = insert(:user, local: true) + clear_config([:mrf_follow_bot, :follower_nickname], bot.nickname) + + message = %{ + "@context" => "https://www.w3.org/ns/activitystreams", + "to" => [local_user.follower_address], + "cc" => ["https://www.w3.org/ns/activitystreams#Public"], + "type" => "Create", + "object" => %{ + "content" => "Hi I'm a local user", + "type" => "Note", + "attributedTo" => local_user.ap_id, + "inReplyTo" => nil + }, + "actor" => local_user.ap_id + } + + refute User.following?(bot, local_user) + + assert User.get_follow_requests(local_user) |> length == 0 + + FollowBotPolicy.filter(message) + + assert User.get_follow_requests(local_user) |> length == 0 + end + + test "does not follow users requiring follower approval" do + bot = insert(:user, actor_type: "Service") + remote_user = insert(:user, %{local: false, is_locked: true}) + clear_config([:mrf_follow_bot, :follower_nickname], bot.nickname) + + message = %{ + "@context" => "https://www.w3.org/ns/activitystreams", + "to" => [remote_user.follower_address], + "cc" => ["https://www.w3.org/ns/activitystreams#Public"], + "type" => "Create", + "object" => %{ + "content" => "I don't like randos following me", + "type" => "Note", + "attributedTo" => remote_user.ap_id, + "inReplyTo" => nil + }, + "actor" => remote_user.ap_id + } + + refute User.following?(bot, remote_user) + + assert User.get_follow_requests(remote_user) |> length == 0 + + FollowBotPolicy.filter(message) + + assert User.get_follow_requests(remote_user) |> length == 0 + end + end +end diff --git a/test/pleroma/web/activity_pub/mrf/force_bot_unlisted_policy_test.exs b/test/pleroma/web/activity_pub/mrf/force_bot_unlisted_policy_test.exs new file mode 100644 index 000000000..e3325d144 --- /dev/null +++ b/test/pleroma/web/activity_pub/mrf/force_bot_unlisted_policy_test.exs @@ -0,0 +1,60 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ActivityPub.MRF.ForceBotUnlistedPolicyTest do + use Pleroma.DataCase, async: true + import Pleroma.Factory + + alias Pleroma.Web.ActivityPub.MRF.ForceBotUnlistedPolicy + @public "https://www.w3.org/ns/activitystreams#Public" + + defp generate_messages(actor) do + {%{ + "actor" => actor.ap_id, + "type" => "Create", + "object" => %{}, + "to" => [@public, "f"], + "cc" => [actor.follower_address, "d"] + }, + %{ + "actor" => actor.ap_id, + "type" => "Create", + "object" => %{"to" => ["f", actor.follower_address], "cc" => ["d", @public]}, + "to" => ["f", actor.follower_address], + "cc" => ["d", @public] + }} + end + + test "removes from the federated timeline by nickname heuristics 1" do + actor = insert(:user, %{nickname: "annoying_ebooks@example.com"}) + + {message, except_message} = generate_messages(actor) + + assert ForceBotUnlistedPolicy.filter(message) == {:ok, except_message} + end + + test "removes from the federated timeline by nickname heuristics 2" do + actor = insert(:user, %{nickname: "cirnonewsnetworkbot@meow.cat"}) + + {message, except_message} = generate_messages(actor) + + assert ForceBotUnlistedPolicy.filter(message) == {:ok, except_message} + end + + test "removes from the federated timeline by actor type Application" do + actor = insert(:user, %{actor_type: "Application"}) + + {message, except_message} = generate_messages(actor) + + assert ForceBotUnlistedPolicy.filter(message) == {:ok, except_message} + end + + test "removes from the federated timeline by actor type Service" do + actor = insert(:user, %{actor_type: "Service"}) + + {message, except_message} = generate_messages(actor) + + assert ForceBotUnlistedPolicy.filter(message) == {:ok, except_message} + end +end diff --git a/test/pleroma/web/activity_pub/mrf/hashtag_policy_test.exs b/test/pleroma/web/activity_pub/mrf/hashtag_policy_test.exs new file mode 100644 index 000000000..13415bb79 --- /dev/null +++ b/test/pleroma/web/activity_pub/mrf/hashtag_policy_test.exs @@ -0,0 +1,31 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ActivityPub.MRF.HashtagPolicyTest do + use Oban.Testing, repo: Pleroma.Repo + use Pleroma.DataCase + + alias Pleroma.Web.ActivityPub.Transmogrifier + alias Pleroma.Web.CommonAPI + + import Pleroma.Factory + + test "it sets the sensitive property with relevant hashtags" do + user = insert(:user) + + {:ok, activity} = CommonAPI.post(user, %{status: "#nsfw hey"}) + {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) + + assert modified["object"]["sensitive"] + end + + test "it doesn't sets the sensitive property with irrelevant hashtags" do + user = insert(:user) + + {:ok, activity} = CommonAPI.post(user, %{status: "#cofe hey"}) + {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) + + refute modified["object"]["sensitive"] + end +end diff --git a/test/web/activity_pub/mrf/hellthread_policy_test.exs b/test/pleroma/web/activity_pub/mrf/hellthread_policy_test.exs index 26f5bcdaa..439672479 100644 --- a/test/web/activity_pub/mrf/hellthread_policy_test.exs +++ b/test/pleroma/web/activity_pub/mrf/hellthread_policy_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.MRF.HellthreadPolicyTest do @@ -34,7 +34,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.HellthreadPolicyTest do setup do: clear_config(:mrf_hellthread) test "doesn't die on chat messages" do - Pleroma.Config.put([:mrf_hellthread], %{delist_threshold: 2, reject_threshold: 0}) + clear_config([:mrf_hellthread], %{delist_threshold: 2, reject_threshold: 0}) user = insert(:user) other_user = insert(:user) @@ -48,7 +48,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.HellthreadPolicyTest do test "rejects the message if the recipient count is above reject_threshold", %{ message: message } do - Pleroma.Config.put([:mrf_hellthread], %{delist_threshold: 0, reject_threshold: 2}) + clear_config([:mrf_hellthread], %{delist_threshold: 0, reject_threshold: 2}) assert {:reject, "[HellthreadPolicy] 3 recipients is over the limit of 2"} == filter(message) @@ -57,7 +57,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.HellthreadPolicyTest do test "does not reject the message if the recipient count is below reject_threshold", %{ message: message } do - Pleroma.Config.put([:mrf_hellthread], %{delist_threshold: 0, reject_threshold: 3}) + clear_config([:mrf_hellthread], %{delist_threshold: 0, reject_threshold: 3}) assert {:ok, ^message} = filter(message) end @@ -68,7 +68,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.HellthreadPolicyTest do user: user, message: message } do - Pleroma.Config.put([:mrf_hellthread], %{delist_threshold: 2, reject_threshold: 0}) + clear_config([:mrf_hellthread], %{delist_threshold: 2, reject_threshold: 0}) {:ok, message} = filter(message) assert user.follower_address in message["to"] @@ -78,14 +78,14 @@ defmodule Pleroma.Web.ActivityPub.MRF.HellthreadPolicyTest do test "does not delist the message if the recipient count is below delist_threshold", %{ message: message } do - Pleroma.Config.put([:mrf_hellthread], %{delist_threshold: 4, reject_threshold: 0}) + clear_config([:mrf_hellthread], %{delist_threshold: 4, reject_threshold: 0}) assert {:ok, ^message} = filter(message) end end test "excludes follower collection and public URI from threshold count", %{message: message} do - Pleroma.Config.put([:mrf_hellthread], %{delist_threshold: 0, reject_threshold: 3}) + clear_config([:mrf_hellthread], %{delist_threshold: 0, reject_threshold: 3}) assert {:ok, ^message} = filter(message) end diff --git a/test/web/activity_pub/mrf/keyword_policy_test.exs b/test/pleroma/web/activity_pub/mrf/keyword_policy_test.exs index b3d0f3d90..8af4c5efa 100644 --- a/test/web/activity_pub/mrf/keyword_policy_test.exs +++ b/test/pleroma/web/activity_pub/mrf/keyword_policy_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicyTest do @@ -10,12 +10,12 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicyTest do setup do: clear_config(:mrf_keyword) setup do - Pleroma.Config.put([:mrf_keyword], %{reject: [], federated_timeline_removal: [], replace: []}) + clear_config([:mrf_keyword], %{reject: [], federated_timeline_removal: [], replace: []}) end describe "rejecting based on keywords" do test "rejects if string matches in content" do - Pleroma.Config.put([:mrf_keyword, :reject], ["pun"]) + clear_config([:mrf_keyword, :reject], ["pun"]) message = %{ "type" => "Create", @@ -30,7 +30,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicyTest do end test "rejects if string matches in summary" do - Pleroma.Config.put([:mrf_keyword, :reject], ["pun"]) + clear_config([:mrf_keyword, :reject], ["pun"]) message = %{ "type" => "Create", @@ -45,7 +45,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicyTest do end test "rejects if regex matches in content" do - Pleroma.Config.put([:mrf_keyword, :reject], [~r/comp[lL][aA][iI][nN]er/]) + clear_config([:mrf_keyword, :reject], [~r/comp[lL][aA][iI][nN]er/]) assert true == Enum.all?(["complainer", "compLainer", "compLAiNer", "compLAINer"], fn content -> @@ -63,7 +63,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicyTest do end test "rejects if regex matches in summary" do - Pleroma.Config.put([:mrf_keyword, :reject], [~r/comp[lL][aA][iI][nN]er/]) + clear_config([:mrf_keyword, :reject], [~r/comp[lL][aA][iI][nN]er/]) assert true == Enum.all?(["complainer", "compLainer", "compLAiNer", "compLAINer"], fn content -> @@ -83,7 +83,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicyTest do describe "delisting from ftl based on keywords" do test "delists if string matches in content" do - Pleroma.Config.put([:mrf_keyword, :federated_timeline_removal], ["pun"]) + clear_config([:mrf_keyword, :federated_timeline_removal], ["pun"]) message = %{ "to" => ["https://www.w3.org/ns/activitystreams#Public"], @@ -100,7 +100,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicyTest do end test "delists if string matches in summary" do - Pleroma.Config.put([:mrf_keyword, :federated_timeline_removal], ["pun"]) + clear_config([:mrf_keyword, :federated_timeline_removal], ["pun"]) message = %{ "to" => ["https://www.w3.org/ns/activitystreams#Public"], @@ -117,7 +117,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicyTest do end test "delists if regex matches in content" do - Pleroma.Config.put([:mrf_keyword, :federated_timeline_removal], [~r/comp[lL][aA][iI][nN]er/]) + clear_config([:mrf_keyword, :federated_timeline_removal], [~r/comp[lL][aA][iI][nN]er/]) assert true == Enum.all?(["complainer", "compLainer", "compLAiNer", "compLAINer"], fn content -> @@ -138,7 +138,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicyTest do end test "delists if regex matches in summary" do - Pleroma.Config.put([:mrf_keyword, :federated_timeline_removal], [~r/comp[lL][aA][iI][nN]er/]) + clear_config([:mrf_keyword, :federated_timeline_removal], [~r/comp[lL][aA][iI][nN]er/]) assert true == Enum.all?(["complainer", "compLainer", "compLAiNer", "compLAINer"], fn content -> @@ -161,7 +161,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicyTest do describe "replacing keywords" do test "replaces keyword if string matches in content" do - Pleroma.Config.put([:mrf_keyword, :replace], [{"opensource", "free software"}]) + clear_config([:mrf_keyword, :replace], [{"opensource", "free software"}]) message = %{ "type" => "Create", @@ -174,7 +174,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicyTest do end test "replaces keyword if string matches in summary" do - Pleroma.Config.put([:mrf_keyword, :replace], [{"opensource", "free software"}]) + clear_config([:mrf_keyword, :replace], [{"opensource", "free software"}]) message = %{ "type" => "Create", @@ -187,7 +187,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicyTest do end test "replaces keyword if regex matches in content" do - Pleroma.Config.put([:mrf_keyword, :replace], [ + clear_config([:mrf_keyword, :replace], [ {~r/open(-|\s)?source\s?(software)?/, "free software"} ]) @@ -205,7 +205,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicyTest do end test "replaces keyword if regex matches in summary" do - Pleroma.Config.put([:mrf_keyword, :replace], [ + clear_config([:mrf_keyword, :replace], [ {~r/open(-|\s)?source\s?(software)?/, "free software"} ]) diff --git a/test/web/activity_pub/mrf/mediaproxy_warming_policy_test.exs b/test/pleroma/web/activity_pub/mrf/media_proxy_warming_policy_test.exs index 313d59a66..96e715d0d 100644 --- a/test/web/activity_pub/mrf/mediaproxy_warming_policy_test.exs +++ b/test/pleroma/web/activity_pub/mrf/media_proxy_warming_policy_test.exs @@ -1,12 +1,12 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicyTest do - use Pleroma.DataCase + use ExUnit.Case + use Pleroma.Tests.Helpers alias Pleroma.HTTP - alias Pleroma.Tests.ObanHelpers alias Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy import Mock @@ -22,14 +22,16 @@ defmodule Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicyTest do } } + setup do: clear_config([:media_proxy, :enabled], true) + test "it prefetches media proxy URIs" do + Tesla.Mock.mock(fn %{method: :get, url: "http://example.com/image.jpg"} -> + {:ok, %Tesla.Env{status: 200, body: ""}} + end) + with_mock HTTP, get: fn _, _, _ -> {:ok, []} end do MediaProxyWarmingPolicy.filter(@message) - ObanHelpers.perform_all() - # Performing jobs which has been just enqueued - ObanHelpers.perform_all() - assert called(HTTP.get(:_, :_, :_)) end end diff --git a/test/web/activity_pub/mrf/mention_policy_test.exs b/test/pleroma/web/activity_pub/mrf/mention_policy_test.exs index 220309cc9..80ddcacbe 100644 --- a/test/web/activity_pub/mrf/mention_policy_test.exs +++ b/test/pleroma/web/activity_pub/mrf/mention_policy_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.MRF.MentionPolicyTest do @@ -23,7 +23,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.MentionPolicyTest do describe "allow" do test "empty" do - Pleroma.Config.put([:mrf_mention], %{actors: ["https://example.com/blocked"]}) + clear_config([:mrf_mention], %{actors: ["https://example.com/blocked"]}) message = %{ "type" => "Create" @@ -33,7 +33,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.MentionPolicyTest do end test "to" do - Pleroma.Config.put([:mrf_mention], %{actors: ["https://example.com/blocked"]}) + clear_config([:mrf_mention], %{actors: ["https://example.com/blocked"]}) message = %{ "type" => "Create", @@ -44,7 +44,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.MentionPolicyTest do end test "cc" do - Pleroma.Config.put([:mrf_mention], %{actors: ["https://example.com/blocked"]}) + clear_config([:mrf_mention], %{actors: ["https://example.com/blocked"]}) message = %{ "type" => "Create", @@ -55,7 +55,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.MentionPolicyTest do end test "both" do - Pleroma.Config.put([:mrf_mention], %{actors: ["https://example.com/blocked"]}) + clear_config([:mrf_mention], %{actors: ["https://example.com/blocked"]}) message = %{ "type" => "Create", @@ -69,7 +69,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.MentionPolicyTest do describe "deny" do test "to" do - Pleroma.Config.put([:mrf_mention], %{actors: ["https://example.com/blocked"]}) + clear_config([:mrf_mention], %{actors: ["https://example.com/blocked"]}) message = %{ "type" => "Create", @@ -81,7 +81,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.MentionPolicyTest do end test "cc" do - Pleroma.Config.put([:mrf_mention], %{actors: ["https://example.com/blocked"]}) + clear_config([:mrf_mention], %{actors: ["https://example.com/blocked"]}) message = %{ "type" => "Create", diff --git a/test/pleroma/web/activity_pub/mrf/no_empty_policy_test.exs b/test/pleroma/web/activity_pub/mrf/no_empty_policy_test.exs new file mode 100644 index 000000000..fbcf68414 --- /dev/null +++ b/test/pleroma/web/activity_pub/mrf/no_empty_policy_test.exs @@ -0,0 +1,154 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ActivityPub.MRF.NoEmptyPolicyTest do + use Pleroma.DataCase + alias Pleroma.Web.ActivityPub.MRF.NoEmptyPolicy + + setup_all do: clear_config([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.NoEmptyPolicy]) + + test "Notes with content are exempt" do + message = %{ + "actor" => "http://localhost:4001/users/testuser", + "cc" => ["http://localhost:4001/users/testuser/followers"], + "object" => %{ + "actor" => "http://localhost:4001/users/testuser", + "attachment" => [], + "cc" => ["http://localhost:4001/users/testuser/followers"], + "source" => "this is a test post", + "to" => ["https://www.w3.org/ns/activitystreams#Public"], + "type" => "Note" + }, + "to" => ["https://www.w3.org/ns/activitystreams#Public"], + "type" => "Create" + } + + assert NoEmptyPolicy.filter(message) == {:ok, message} + end + + test "Polls are exempt" do + message = %{ + "actor" => "http://localhost:4001/users/testuser", + "cc" => ["http://localhost:4001/users/testuser/followers"], + "object" => %{ + "actor" => "http://localhost:4001/users/testuser", + "attachment" => [], + "cc" => ["http://localhost:4001/users/testuser/followers"], + "oneOf" => [ + %{ + "name" => "chocolate", + "replies" => %{"totalItems" => 0, "type" => "Collection"}, + "type" => "Note" + }, + %{ + "name" => "vanilla", + "replies" => %{"totalItems" => 0, "type" => "Collection"}, + "type" => "Note" + } + ], + "source" => "@user2", + "to" => [ + "https://www.w3.org/ns/activitystreams#Public", + "http://localhost:4001/users/user2" + ], + "type" => "Question" + }, + "to" => [ + "https://www.w3.org/ns/activitystreams#Public", + "http://localhost:4001/users/user2" + ], + "type" => "Create" + } + + assert NoEmptyPolicy.filter(message) == {:ok, message} + end + + test "Notes with attachments are exempt" do + message = %{ + "actor" => "http://localhost:4001/users/testuser", + "cc" => ["http://localhost:4001/users/testuser/followers"], + "object" => %{ + "actor" => "http://localhost:4001/users/testuser", + "attachment" => [ + %{ + "actor" => "http://localhost:4001/users/testuser", + "mediaType" => "image/png", + "name" => "", + "type" => "Document", + "url" => [ + %{ + "href" => + "http://localhost:4001/media/68ba231cf12e1382ce458f1979969f8ed5cc07ba198a02e653464abaf39bdb90.png", + "mediaType" => "image/png", + "type" => "Link" + } + ] + } + ], + "cc" => ["http://localhost:4001/users/testuser/followers"], + "source" => "@user2", + "to" => [ + "https://www.w3.org/ns/activitystreams#Public", + "http://localhost:4001/users/user2" + ], + "type" => "Note" + }, + "to" => [ + "https://www.w3.org/ns/activitystreams#Public", + "http://localhost:4001/users/user2" + ], + "type" => "Create" + } + + assert NoEmptyPolicy.filter(message) == {:ok, message} + end + + test "Notes with only mentions are denied" do + message = %{ + "actor" => "http://localhost:4001/users/testuser", + "cc" => ["http://localhost:4001/users/testuser/followers"], + "object" => %{ + "actor" => "http://localhost:4001/users/testuser", + "attachment" => [], + "cc" => ["http://localhost:4001/users/testuser/followers"], + "source" => "@user2", + "to" => [ + "https://www.w3.org/ns/activitystreams#Public", + "http://localhost:4001/users/user2" + ], + "type" => "Note" + }, + "to" => [ + "https://www.w3.org/ns/activitystreams#Public", + "http://localhost:4001/users/user2" + ], + "type" => "Create" + } + + assert NoEmptyPolicy.filter(message) == {:reject, "[NoEmptyPolicy]"} + end + + test "Notes with no content are denied" do + message = %{ + "actor" => "http://localhost:4001/users/testuser", + "cc" => ["http://localhost:4001/users/testuser/followers"], + "object" => %{ + "actor" => "http://localhost:4001/users/testuser", + "attachment" => [], + "cc" => ["http://localhost:4001/users/testuser/followers"], + "source" => "", + "to" => [ + "https://www.w3.org/ns/activitystreams#Public" + ], + "type" => "Note" + }, + "to" => [ + "https://www.w3.org/ns/activitystreams#Public" + ], + "type" => "Create" + } + + assert NoEmptyPolicy.filter(message) == {:reject, "[NoEmptyPolicy]"} + end +end diff --git a/test/web/activity_pub/mrf/no_placeholder_text_policy_test.exs b/test/pleroma/web/activity_pub/mrf/no_placeholder_text_policy_test.exs index 64ea61dd4..81a6e0f50 100644 --- a/test/web/activity_pub/mrf/no_placeholder_text_policy_test.exs +++ b/test/pleroma/web/activity_pub/mrf/no_placeholder_text_policy_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.MRF.NoPlaceholderTextPolicyTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true alias Pleroma.Web.ActivityPub.MRF.NoPlaceholderTextPolicy test "it clears content object" do diff --git a/test/web/activity_pub/mrf/normalize_markup_test.exs b/test/pleroma/web/activity_pub/mrf/normalize_markup_test.exs index 9b39c45bd..edc330b6c 100644 --- a/test/web/activity_pub/mrf/normalize_markup_test.exs +++ b/test/pleroma/web/activity_pub/mrf/normalize_markup_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.MRF.NormalizeMarkupTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true alias Pleroma.Web.ActivityPub.MRF.NormalizeMarkup @html_sample """ diff --git a/test/web/activity_pub/mrf/object_age_policy_test.exs b/test/pleroma/web/activity_pub/mrf/object_age_policy_test.exs index cf6acc9a2..2f649a0a4 100644 --- a/test/web/activity_pub/mrf/object_age_policy_test.exs +++ b/test/pleroma/web/activity_pub/mrf/object_age_policy_test.exs @@ -1,10 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicyTest do use Pleroma.DataCase - alias Pleroma.Config alias Pleroma.User alias Pleroma.Web.ActivityPub.MRF.ObjectAgePolicy alias Pleroma.Web.ActivityPub.Visibility @@ -22,7 +21,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicyTest do defp get_old_message do File.read!("test/fixtures/mastodon-post-activity.json") - |> Poison.decode!() + |> Jason.decode!() + |> Map.drop(["published"]) end defp get_new_message do @@ -39,7 +39,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicyTest do describe "with reject action" do test "works with objects with empty to or cc fields" do - Config.put([:mrf_object_age, :actions], [:reject]) + clear_config([:mrf_object_age, :actions], [:reject]) data = get_old_message() @@ -50,7 +50,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicyTest do end test "it rejects an old post" do - Config.put([:mrf_object_age, :actions], [:reject]) + clear_config([:mrf_object_age, :actions], [:reject]) data = get_old_message() @@ -58,7 +58,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicyTest do end test "it allows a new post" do - Config.put([:mrf_object_age, :actions], [:reject]) + clear_config([:mrf_object_age, :actions], [:reject]) data = get_new_message() @@ -68,7 +68,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicyTest do describe "with delist action" do test "works with objects with empty to or cc fields" do - Config.put([:mrf_object_age, :actions], [:delist]) + clear_config([:mrf_object_age, :actions], [:delist]) data = get_old_message() @@ -83,7 +83,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicyTest do end test "it delists an old post" do - Config.put([:mrf_object_age, :actions], [:delist]) + clear_config([:mrf_object_age, :actions], [:delist]) data = get_old_message() @@ -95,7 +95,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicyTest do end test "it allows a new post" do - Config.put([:mrf_object_age, :actions], [:delist]) + clear_config([:mrf_object_age, :actions], [:delist]) data = get_new_message() @@ -107,7 +107,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicyTest do describe "with strip_followers action" do test "works with objects with empty to or cc fields" do - Config.put([:mrf_object_age, :actions], [:strip_followers]) + clear_config([:mrf_object_age, :actions], [:strip_followers]) data = get_old_message() @@ -123,7 +123,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicyTest do end test "it strips followers collections from an old post" do - Config.put([:mrf_object_age, :actions], [:strip_followers]) + clear_config([:mrf_object_age, :actions], [:strip_followers]) data = get_old_message() @@ -136,7 +136,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicyTest do end test "it allows a new post" do - Config.put([:mrf_object_age, :actions], [:strip_followers]) + clear_config([:mrf_object_age, :actions], [:strip_followers]) data = get_new_message() diff --git a/test/web/activity_pub/mrf/reject_non_public_test.exs b/test/pleroma/web/activity_pub/mrf/reject_non_public_test.exs index 58b46b9a2..63c68d798 100644 --- a/test/web/activity_pub/mrf/reject_non_public_test.exs +++ b/test/pleroma/web/activity_pub/mrf/reject_non_public_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.MRF.RejectNonPublicTest do @@ -21,7 +21,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.RejectNonPublicTest do "type" => "Create" } - assert {:ok, message} = RejectNonPublic.filter(message) + assert {:ok, _message} = RejectNonPublic.filter(message) end test "it's allowed when cc address contain public address" do @@ -34,7 +34,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.RejectNonPublicTest do "type" => "Create" } - assert {:ok, message} = RejectNonPublic.filter(message) + assert {:ok, _message} = RejectNonPublic.filter(message) end end @@ -49,8 +49,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.RejectNonPublicTest do "type" => "Create" } - Pleroma.Config.put([:mrf_rejectnonpublic, :allow_followersonly], true) - assert {:ok, message} = RejectNonPublic.filter(message) + clear_config([:mrf_rejectnonpublic, :allow_followersonly], true) + assert {:ok, _message} = RejectNonPublic.filter(message) end test "it's rejected when addrer of message in the follower addresses of user and it disabled in config" do @@ -63,7 +63,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.RejectNonPublicTest do "type" => "Create" } - Pleroma.Config.put([:mrf_rejectnonpublic, :allow_followersonly], false) + clear_config([:mrf_rejectnonpublic, :allow_followersonly], false) assert {:reject, _} = RejectNonPublic.filter(message) end end @@ -79,8 +79,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.RejectNonPublicTest do "type" => "Create" } - Pleroma.Config.put([:mrf_rejectnonpublic, :allow_direct], true) - assert {:ok, message} = RejectNonPublic.filter(message) + clear_config([:mrf_rejectnonpublic, :allow_direct], true) + assert {:ok, _message} = RejectNonPublic.filter(message) end test "it's reject when direct messages aren't allow" do @@ -93,7 +93,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.RejectNonPublicTest do "type" => "Create" } - Pleroma.Config.put([:mrf_rejectnonpublic, :allow_direct], false) + clear_config([:mrf_rejectnonpublic, :allow_direct], false) assert {:reject, _} = RejectNonPublic.filter(message) end end diff --git a/test/web/activity_pub/mrf/simple_policy_test.exs b/test/pleroma/web/activity_pub/mrf/simple_policy_test.exs index d7dde62c4..0a0f51bdb 100644 --- a/test/web/activity_pub/mrf/simple_policy_test.exs +++ b/test/pleroma/web/activity_pub/mrf/simple_policy_test.exs @@ -1,11 +1,10 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do use Pleroma.DataCase import Pleroma.Factory - alias Pleroma.Config alias Pleroma.Web.ActivityPub.MRF.SimplePolicy alias Pleroma.Web.CommonAPI @@ -25,7 +24,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do describe "when :media_removal" do test "is empty" do - Config.put([:mrf_simple, :media_removal], []) + clear_config([:mrf_simple, :media_removal], []) media_message = build_media_message() local_message = build_local_message() @@ -34,7 +33,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do end test "has a matching host" do - Config.put([:mrf_simple, :media_removal], ["remote.instance"]) + clear_config([:mrf_simple, :media_removal], [{"remote.instance", "Some reason"}]) media_message = build_media_message() local_message = build_local_message() @@ -47,7 +46,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do end test "match with wildcard domain" do - Config.put([:mrf_simple, :media_removal], ["*.remote.instance"]) + clear_config([:mrf_simple, :media_removal], [{"*.remote.instance", "Whatever reason"}]) media_message = build_media_message() local_message = build_local_message() @@ -62,7 +61,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do describe "when :media_nsfw" do test "is empty" do - Config.put([:mrf_simple, :media_nsfw], []) + clear_config([:mrf_simple, :media_nsfw], []) media_message = build_media_message() local_message = build_local_message() @@ -71,29 +70,23 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do end test "has a matching host" do - Config.put([:mrf_simple, :media_nsfw], ["remote.instance"]) + clear_config([:mrf_simple, :media_nsfw], [{"remote.instance", "Whetever"}]) media_message = build_media_message() local_message = build_local_message() assert SimplePolicy.filter(media_message) == - {:ok, - media_message - |> put_in(["object", "tag"], ["foo", "nsfw"]) - |> put_in(["object", "sensitive"], true)} + {:ok, put_in(media_message, ["object", "sensitive"], true)} assert SimplePolicy.filter(local_message) == {:ok, local_message} end test "match with wildcard domain" do - Config.put([:mrf_simple, :media_nsfw], ["*.remote.instance"]) + clear_config([:mrf_simple, :media_nsfw], [{"*.remote.instance", "yeah yeah"}]) media_message = build_media_message() local_message = build_local_message() assert SimplePolicy.filter(media_message) == - {:ok, - media_message - |> put_in(["object", "tag"], ["foo", "nsfw"]) - |> put_in(["object", "sensitive"], true)} + {:ok, put_in(media_message, ["object", "sensitive"], true)} assert SimplePolicy.filter(local_message) == {:ok, local_message} end @@ -113,7 +106,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do describe "when :report_removal" do test "is empty" do - Config.put([:mrf_simple, :report_removal], []) + clear_config([:mrf_simple, :report_removal], []) report_message = build_report_message() local_message = build_local_message() @@ -122,7 +115,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do end test "has a matching host" do - Config.put([:mrf_simple, :report_removal], ["remote.instance"]) + clear_config([:mrf_simple, :report_removal], [{"remote.instance", "muh"}]) report_message = build_report_message() local_message = build_local_message() @@ -131,7 +124,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do end test "match with wildcard domain" do - Config.put([:mrf_simple, :report_removal], ["*.remote.instance"]) + clear_config([:mrf_simple, :report_removal], [{"*.remote.instance", "suya"}]) report_message = build_report_message() local_message = build_local_message() @@ -149,7 +142,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do describe "when :federated_timeline_removal" do test "is empty" do - Config.put([:mrf_simple, :federated_timeline_removal], []) + clear_config([:mrf_simple, :federated_timeline_removal], []) {_, ftl_message} = build_ftl_actor_and_message() local_message = build_local_message() @@ -166,7 +159,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do |> URI.parse() |> Map.fetch!(:host) - Config.put([:mrf_simple, :federated_timeline_removal], [ftl_message_actor_host]) + clear_config([:mrf_simple, :federated_timeline_removal], [{ftl_message_actor_host, "uwu"}]) local_message = build_local_message() assert {:ok, ftl_message} = SimplePolicy.filter(ftl_message) @@ -187,7 +180,10 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do |> URI.parse() |> Map.fetch!(:host) - Config.put([:mrf_simple, :federated_timeline_removal], ["*." <> ftl_message_actor_host]) + clear_config([:mrf_simple, :federated_timeline_removal], [ + {"*." <> ftl_message_actor_host, "owo"} + ]) + local_message = build_local_message() assert {:ok, ftl_message} = SimplePolicy.filter(ftl_message) @@ -210,7 +206,9 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do ftl_message = Map.put(ftl_message, "cc", []) - Config.put([:mrf_simple, :federated_timeline_removal], [ftl_message_actor_host]) + clear_config([:mrf_simple, :federated_timeline_removal], [ + {ftl_message_actor_host, "spiderwaifu goes 88w88"} + ]) assert {:ok, ftl_message} = SimplePolicy.filter(ftl_message) refute "https://www.w3.org/ns/activitystreams#Public" in ftl_message["to"] @@ -231,7 +229,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do describe "when :reject" do test "is empty" do - Config.put([:mrf_simple, :reject], []) + clear_config([:mrf_simple, :reject], []) remote_message = build_remote_message() @@ -239,7 +237,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do end test "activity has a matching host" do - Config.put([:mrf_simple, :reject], ["remote.instance"]) + clear_config([:mrf_simple, :reject], [{"remote.instance", ""}]) remote_message = build_remote_message() @@ -247,7 +245,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do end test "activity matches with wildcard domain" do - Config.put([:mrf_simple, :reject], ["*.remote.instance"]) + clear_config([:mrf_simple, :reject], [{"*.remote.instance", ""}]) remote_message = build_remote_message() @@ -255,17 +253,41 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do end test "actor has a matching host" do - Config.put([:mrf_simple, :reject], ["remote.instance"]) + clear_config([:mrf_simple, :reject], [{"remote.instance", ""}]) remote_user = build_remote_user() assert {:reject, _} = SimplePolicy.filter(remote_user) end + + test "reject Announce when object would be rejected" do + clear_config([:mrf_simple, :reject], [{"blocked.tld", ""}]) + + announce = %{ + "type" => "Announce", + "actor" => "https://okay.tld/users/alice", + "object" => %{"type" => "Note", "actor" => "https://blocked.tld/users/bob"} + } + + assert {:reject, _} = SimplePolicy.filter(announce) + end + + test "reject by URI object" do + clear_config([:mrf_simple, :reject], [{"blocked.tld", ""}]) + + announce = %{ + "type" => "Announce", + "actor" => "https://okay.tld/users/alice", + "object" => "https://blocked.tld/activities/1" + } + + assert {:reject, _} = SimplePolicy.filter(announce) + end end describe "when :followers_only" do test "is empty" do - Config.put([:mrf_simple, :followers_only], []) + clear_config([:mrf_simple, :followers_only], []) {_, ftl_message} = build_ftl_actor_and_message() local_message = build_local_message() @@ -305,7 +327,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do |> URI.parse() |> Map.fetch!(:host) - Config.put([:mrf_simple, :followers_only], [actor_domain]) + clear_config([:mrf_simple, :followers_only], [{actor_domain, ""}]) assert {:ok, new_activity} = SimplePolicy.filter(activity) assert actor.follower_address in new_activity["cc"] @@ -323,7 +345,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do describe "when :accept" do test "is empty" do - Config.put([:mrf_simple, :accept], []) + clear_config([:mrf_simple, :accept], []) local_message = build_local_message() remote_message = build_remote_message() @@ -333,7 +355,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do end test "is not empty but activity doesn't have a matching host" do - Config.put([:mrf_simple, :accept], ["non.matching.remote"]) + clear_config([:mrf_simple, :accept], [{"non.matching.remote", ""}]) local_message = build_local_message() remote_message = build_remote_message() @@ -343,7 +365,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do end test "activity has a matching host" do - Config.put([:mrf_simple, :accept], ["remote.instance"]) + clear_config([:mrf_simple, :accept], [{"remote.instance", ""}]) local_message = build_local_message() remote_message = build_remote_message() @@ -353,7 +375,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do end test "activity matches with wildcard domain" do - Config.put([:mrf_simple, :accept], ["*.remote.instance"]) + clear_config([:mrf_simple, :accept], [{"*.remote.instance", ""}]) local_message = build_local_message() remote_message = build_remote_message() @@ -363,7 +385,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do end test "actor has a matching host" do - Config.put([:mrf_simple, :accept], ["remote.instance"]) + clear_config([:mrf_simple, :accept], [{"remote.instance", ""}]) remote_user = build_remote_user() @@ -373,7 +395,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do describe "when :avatar_removal" do test "is empty" do - Config.put([:mrf_simple, :avatar_removal], []) + clear_config([:mrf_simple, :avatar_removal], []) remote_user = build_remote_user() @@ -381,7 +403,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do end test "is not empty but it doesn't have a matching host" do - Config.put([:mrf_simple, :avatar_removal], ["non.matching.remote"]) + clear_config([:mrf_simple, :avatar_removal], [{"non.matching.remote", ""}]) remote_user = build_remote_user() @@ -389,7 +411,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do end test "has a matching host" do - Config.put([:mrf_simple, :avatar_removal], ["remote.instance"]) + clear_config([:mrf_simple, :avatar_removal], [{"remote.instance", ""}]) remote_user = build_remote_user() {:ok, filtered} = SimplePolicy.filter(remote_user) @@ -398,7 +420,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do end test "match with wildcard domain" do - Config.put([:mrf_simple, :avatar_removal], ["*.remote.instance"]) + clear_config([:mrf_simple, :avatar_removal], [{"*.remote.instance", ""}]) remote_user = build_remote_user() {:ok, filtered} = SimplePolicy.filter(remote_user) @@ -409,7 +431,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do describe "when :banner_removal" do test "is empty" do - Config.put([:mrf_simple, :banner_removal], []) + clear_config([:mrf_simple, :banner_removal], []) remote_user = build_remote_user() @@ -417,7 +439,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do end test "is not empty but it doesn't have a matching host" do - Config.put([:mrf_simple, :banner_removal], ["non.matching.remote"]) + clear_config([:mrf_simple, :banner_removal], [{"non.matching.remote", ""}]) remote_user = build_remote_user() @@ -425,7 +447,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do end test "has a matching host" do - Config.put([:mrf_simple, :banner_removal], ["remote.instance"]) + clear_config([:mrf_simple, :banner_removal], [{"remote.instance", ""}]) remote_user = build_remote_user() {:ok, filtered} = SimplePolicy.filter(remote_user) @@ -434,7 +456,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do end test "match with wildcard domain" do - Config.put([:mrf_simple, :banner_removal], ["*.remote.instance"]) + clear_config([:mrf_simple, :banner_removal], [{"*.remote.instance", ""}]) remote_user = build_remote_user() {:ok, filtered} = SimplePolicy.filter(remote_user) @@ -444,10 +466,10 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do end describe "when :reject_deletes is empty" do - setup do: Config.put([:mrf_simple, :reject_deletes], []) + setup do: clear_config([:mrf_simple, :reject_deletes], []) test "it accepts deletions even from rejected servers" do - Config.put([:mrf_simple, :reject], ["remote.instance"]) + clear_config([:mrf_simple, :reject], [{"remote.instance", ""}]) deletion_message = build_remote_deletion_message() @@ -455,7 +477,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do end test "it accepts deletions even from non-whitelisted servers" do - Config.put([:mrf_simple, :accept], ["non.matching.remote"]) + clear_config([:mrf_simple, :accept], [{"non.matching.remote", ""}]) deletion_message = build_remote_deletion_message() @@ -464,10 +486,10 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do end describe "when :reject_deletes is not empty but it doesn't have a matching host" do - setup do: Config.put([:mrf_simple, :reject_deletes], ["non.matching.remote"]) + setup do: clear_config([:mrf_simple, :reject_deletes], [{"non.matching.remote", ""}]) test "it accepts deletions even from rejected servers" do - Config.put([:mrf_simple, :reject], ["remote.instance"]) + clear_config([:mrf_simple, :reject], [{"remote.instance", ""}]) deletion_message = build_remote_deletion_message() @@ -475,7 +497,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do end test "it accepts deletions even from non-whitelisted servers" do - Config.put([:mrf_simple, :accept], ["non.matching.remote"]) + clear_config([:mrf_simple, :accept], [{"non.matching.remote", ""}]) deletion_message = build_remote_deletion_message() @@ -484,7 +506,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do end describe "when :reject_deletes has a matching host" do - setup do: Config.put([:mrf_simple, :reject_deletes], ["remote.instance"]) + setup do: clear_config([:mrf_simple, :reject_deletes], [{"remote.instance", ""}]) test "it rejects the deletion" do deletion_message = build_remote_deletion_message() @@ -494,7 +516,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do end describe "when :reject_deletes match with wildcard domain" do - setup do: Config.put([:mrf_simple, :reject_deletes], ["*.remote.instance"]) + setup do: clear_config([:mrf_simple, :reject_deletes], [{"*.remote.instance", ""}]) test "it rejects the deletion" do deletion_message = build_remote_deletion_message() @@ -505,7 +527,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do defp build_local_message do %{ - "actor" => "#{Pleroma.Web.base_url()}/users/alice", + "actor" => "#{Pleroma.Web.Endpoint.url()}/users/alice", "to" => [], "cc" => [] } diff --git a/test/pleroma/web/activity_pub/mrf/steal_emoji_policy_test.exs b/test/pleroma/web/activity_pub/mrf/steal_emoji_policy_test.exs new file mode 100644 index 000000000..1b37e4c26 --- /dev/null +++ b/test/pleroma/web/activity_pub/mrf/steal_emoji_policy_test.exs @@ -0,0 +1,108 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ActivityPub.MRF.StealEmojiPolicyTest do + use Pleroma.DataCase + + alias Pleroma.Config + alias Pleroma.Emoji + alias Pleroma.Web.ActivityPub.MRF.StealEmojiPolicy + + setup do + emoji_path = [:instance, :static_dir] |> Config.get() |> Path.join("emoji/stolen") + + Emoji.reload() + + message = %{ + "type" => "Create", + "object" => %{ + "emoji" => [{"firedfox", "https://example.org/emoji/firedfox.png"}], + "actor" => "https://example.org/users/admin" + } + } + + on_exit(fn -> + File.rm_rf!(emoji_path) + end) + + [message: message, path: emoji_path] + end + + test "does nothing by default", %{message: message} do + refute "firedfox" in installed() + + assert {:ok, _message} = StealEmojiPolicy.filter(message) + + refute "firedfox" in installed() + end + + test "Steals emoji on unknown shortcode from allowed remote host", %{ + message: message, + path: path + } do + refute "firedfox" in installed() + refute File.exists?(path) + + Tesla.Mock.mock(fn %{method: :get, url: "https://example.org/emoji/firedfox.png"} -> + %Tesla.Env{status: 200, body: File.read!("test/fixtures/image.jpg")} + end) + + clear_config(:mrf_steal_emoji, hosts: ["example.org"], size_limit: 284_468) + + assert {:ok, _message} = StealEmojiPolicy.filter(message) + + assert "firedfox" in installed() + assert File.exists?(path) + + assert path + |> Path.join("firedfox.png") + |> File.exists?() + end + + test "reject shortcode", %{message: message} do + refute "firedfox" in installed() + + clear_config(:mrf_steal_emoji, + hosts: ["example.org"], + size_limit: 284_468, + rejected_shortcodes: [~r/firedfox/] + ) + + assert {:ok, _message} = StealEmojiPolicy.filter(message) + + refute "firedfox" in installed() + end + + test "reject if size is above the limit", %{message: message} do + refute "firedfox" in installed() + + Tesla.Mock.mock(fn %{method: :get, url: "https://example.org/emoji/firedfox.png"} -> + %Tesla.Env{status: 200, body: File.read!("test/fixtures/image.jpg")} + end) + + clear_config(:mrf_steal_emoji, hosts: ["example.org"], size_limit: 50_000) + + assert {:ok, _message} = StealEmojiPolicy.filter(message) + + refute "firedfox" in installed() + end + + test "reject if host returns error", %{message: message} do + refute "firedfox" in installed() + + Tesla.Mock.mock(fn %{method: :get, url: "https://example.org/emoji/firedfox.png"} -> + {:ok, %Tesla.Env{status: 404, body: "Not found"}} + end) + + clear_config(:mrf_steal_emoji, hosts: ["example.org"], size_limit: 284_468) + + ExUnit.CaptureLog.capture_log(fn -> + assert {:ok, _message} = StealEmojiPolicy.filter(message) + end) =~ "MRF.StealEmojiPolicy: Failed to fetch https://example.org/emoji/firedfox.png" + + refute "firedfox" in installed() + end + + defp installed, do: Emoji.get_all() |> Enum.map(fn {k, _} -> k end) +end diff --git a/test/web/activity_pub/mrf/subchain_policy_test.exs b/test/pleroma/web/activity_pub/mrf/subchain_policy_test.exs index fff66cb7e..4f5cc466c 100644 --- a/test/web/activity_pub/mrf/subchain_policy_test.exs +++ b/test/pleroma/web/activity_pub/mrf/subchain_policy_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.MRF.SubchainPolicyTest do @@ -16,7 +16,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SubchainPolicyTest do setup do: clear_config([:mrf_subchain, :match_actor]) test "it matches and processes subchains when the actor matches a configured target" do - Pleroma.Config.put([:mrf_subchain, :match_actor], %{ + clear_config([:mrf_subchain, :match_actor], %{ ~r/^https:\/\/banned.com/s => [DropPolicy] }) @@ -24,7 +24,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SubchainPolicyTest do end test "it doesn't match and process subchains when the actor doesn't match a configured target" do - Pleroma.Config.put([:mrf_subchain, :match_actor], %{ + clear_config([:mrf_subchain, :match_actor], %{ ~r/^https:\/\/borked.com/s => [DropPolicy] }) diff --git a/test/web/activity_pub/mrf/tag_policy_test.exs b/test/pleroma/web/activity_pub/mrf/tag_policy_test.exs index 6ff71d640..faaadff79 100644 --- a/test/web/activity_pub/mrf/tag_policy_test.exs +++ b/test/pleroma/web/activity_pub/mrf/tag_policy_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.MRF.TagPolicyTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true import Pleroma.Factory alias Pleroma.Web.ActivityPub.MRF.TagPolicy @@ -29,7 +29,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.TagPolicyTest do actor = insert(:user, tags: ["mrf_tag:disable-remote-subscription"]) follower = insert(:user, tags: ["mrf_tag:disable-remote-subscription"], local: true) message = %{"object" => actor.ap_id, "type" => "Follow", "actor" => follower.ap_id} - assert {:ok, message} = TagPolicy.filter(message) + assert {:ok, _message} = TagPolicy.filter(message) end end @@ -114,7 +114,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.TagPolicyTest do except_message = %{ "actor" => actor.ap_id, "type" => "Create", - "object" => %{"tag" => ["test", "nsfw"], "attachment" => ["file1"], "sensitive" => true} + "object" => %{"tag" => ["test"], "attachment" => ["file1"], "sensitive" => true} } assert TagPolicy.filter(message) == {:ok, except_message} diff --git a/test/web/activity_pub/mrf/user_allowlist_policy_test.exs b/test/pleroma/web/activity_pub/mrf/user_allow_list_policy_test.exs index 8e1ad5bc8..f0432ea42 100644 --- a/test/web/activity_pub/mrf/user_allowlist_policy_test.exs +++ b/test/pleroma/web/activity_pub/mrf/user_allow_list_policy_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.MRF.UserAllowListPolicyTest do use Pleroma.DataCase @@ -17,14 +17,14 @@ defmodule Pleroma.Web.ActivityPub.MRF.UserAllowListPolicyTest do test "pass filter if allow list isn't empty and user in allow list" do actor = insert(:user) - Pleroma.Config.put([:mrf_user_allowlist], %{"localhost" => [actor.ap_id, "test-ap-id"]}) + clear_config([:mrf_user_allowlist], %{"localhost" => [actor.ap_id, "test-ap-id"]}) message = %{"actor" => actor.ap_id} assert UserAllowListPolicy.filter(message) == {:ok, message} end test "rejected if allow list isn't empty and user not in allow list" do actor = insert(:user) - Pleroma.Config.put([:mrf_user_allowlist], %{"localhost" => ["test-ap-id"]}) + clear_config([:mrf_user_allowlist], %{"localhost" => ["test-ap-id"]}) message = %{"actor" => actor.ap_id} assert {:reject, _} = UserAllowListPolicy.filter(message) end diff --git a/test/web/activity_pub/mrf/vocabulary_policy_test.exs b/test/pleroma/web/activity_pub/mrf/vocabulary_policy_test.exs index 2bceb67ee..87d1d79b5 100644 --- a/test/web/activity_pub/mrf/vocabulary_policy_test.exs +++ b/test/pleroma/web/activity_pub/mrf/vocabulary_policy_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.MRF.VocabularyPolicyTest do @@ -11,7 +11,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.VocabularyPolicyTest do setup do: clear_config([:mrf_vocabulary, :accept]) test "it accepts based on parent activity type" do - Pleroma.Config.put([:mrf_vocabulary, :accept], ["Like"]) + clear_config([:mrf_vocabulary, :accept], ["Like"]) message = %{ "type" => "Like", @@ -22,7 +22,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.VocabularyPolicyTest do end test "it accepts based on child object type" do - Pleroma.Config.put([:mrf_vocabulary, :accept], ["Create", "Note"]) + clear_config([:mrf_vocabulary, :accept], ["Create", "Note"]) message = %{ "type" => "Create", @@ -36,7 +36,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.VocabularyPolicyTest do end test "it does not accept disallowed child objects" do - Pleroma.Config.put([:mrf_vocabulary, :accept], ["Create", "Note"]) + clear_config([:mrf_vocabulary, :accept], ["Create", "Note"]) message = %{ "type" => "Create", @@ -50,7 +50,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.VocabularyPolicyTest do end test "it does not accept disallowed parent types" do - Pleroma.Config.put([:mrf_vocabulary, :accept], ["Announce", "Note"]) + clear_config([:mrf_vocabulary, :accept], ["Announce", "Note"]) message = %{ "type" => "Create", @@ -68,7 +68,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.VocabularyPolicyTest do setup do: clear_config([:mrf_vocabulary, :reject]) test "it rejects based on parent activity type" do - Pleroma.Config.put([:mrf_vocabulary, :reject], ["Like"]) + clear_config([:mrf_vocabulary, :reject], ["Like"]) message = %{ "type" => "Like", @@ -79,7 +79,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.VocabularyPolicyTest do end test "it rejects based on child object type" do - Pleroma.Config.put([:mrf_vocabulary, :reject], ["Note"]) + clear_config([:mrf_vocabulary, :reject], ["Note"]) message = %{ "type" => "Create", @@ -93,7 +93,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.VocabularyPolicyTest do end test "it passes through objects that aren't disallowed" do - Pleroma.Config.put([:mrf_vocabulary, :reject], ["Like"]) + clear_config([:mrf_vocabulary, :reject], ["Like"]) message = %{ "type" => "Announce", diff --git a/test/web/activity_pub/mrf/mrf_test.exs b/test/pleroma/web/activity_pub/mrf_test.exs index a63b25423..6ab27bc86 100644 --- a/test/web/activity_pub/mrf/mrf_test.exs +++ b/test/pleroma/web/activity_pub/mrf_test.exs @@ -1,3 +1,7 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + defmodule Pleroma.Web.ActivityPub.MRFTest do use ExUnit.Case, async: true use Pleroma.Tests.Helpers @@ -59,10 +63,26 @@ defmodule Pleroma.Web.ActivityPub.MRFTest do end end + describe "instance_list_from_tuples/1" do + test "returns a list of instances from a list of {instance, reason} tuples" do + list = [{"some.tld", "a reason"}, {"other.tld", "another reason"}] + expected = ["some.tld", "other.tld"] + + assert MRF.instance_list_from_tuples(list) == expected + end + end + describe "describe/0" do test "it works as expected with noop policy" do + clear_config([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.NoOpPolicy]) + expected = %{ - mrf_policies: ["NoOpPolicy"], + mrf_policies: ["NoOpPolicy", "HashtagPolicy"], + mrf_hashtag: %{ + federated_timeline_removal: [], + reject: [], + sensitive: ["nsfw"] + }, exclusions: false } @@ -73,12 +93,33 @@ defmodule Pleroma.Web.ActivityPub.MRFTest do clear_config([:mrf, :policies], [MRFModuleMock]) expected = %{ - mrf_policies: ["MRFModuleMock"], + mrf_policies: ["MRFModuleMock", "HashtagPolicy"], mrf_module_mock: "some config data", + mrf_hashtag: %{ + federated_timeline_removal: [], + reject: [], + sensitive: ["nsfw"] + }, exclusions: false } {:ok, ^expected} = MRF.describe() end end + + test "config_descriptions/0" do + descriptions = MRF.config_descriptions() + + good_mrf = Enum.find(descriptions, fn %{key: key} -> key == :good_mrf end) + + assert good_mrf == %{ + key: :good_mrf, + related_policy: "Fixtures.Modules.GoodMRF", + label: "Good MRF", + description: "Some description", + group: :pleroma, + tab: :mrf, + type: :group + } + end end diff --git a/test/web/activity_pub/object_validators/accept_validation_test.exs b/test/pleroma/web/activity_pub/object_validators/accept_validation_test.exs index d6111ba41..ddb302f6e 100644 --- a/test/web/activity_pub/object_validators/accept_validation_test.exs +++ b/test/pleroma/web/activity_pub/object_validators/accept_validation_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.ObjectValidators.AcceptValidationTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true alias Pleroma.Web.ActivityPub.Builder alias Pleroma.Web.ActivityPub.ObjectValidator diff --git a/test/web/activity_pub/object_validators/announce_validation_test.exs b/test/pleroma/web/activity_pub/object_validators/announce_validation_test.exs index 623342f76..20964e855 100644 --- a/test/web/activity_pub/object_validators/announce_validation_test.exs +++ b/test/pleroma/web/activity_pub/object_validators/announce_validation_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.Web.ActivityPub.ObjectValidators.AnnouncValidationTest do - use Pleroma.DataCase +defmodule Pleroma.Web.ActivityPub.ObjectValidators.AnnounceValidationTest do + use Pleroma.DataCase, async: true alias Pleroma.Object alias Pleroma.Web.ActivityPub.Builder @@ -18,7 +18,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AnnouncValidationTest do announcer = insert(:user) {:ok, post_activity} = CommonAPI.post(user, %{status: "uguu"}) - object = Object.normalize(post_activity, false) + object = Object.normalize(post_activity, fetch: false) {:ok, valid_announce, []} = Builder.announce(announcer, object) %{ @@ -33,6 +33,18 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AnnouncValidationTest do assert {:ok, _object, _meta} = ObjectValidator.validate(valid_announce, []) end + test "keeps announced object context", %{valid_announce: valid_announce} do + assert %Object{data: %{"context" => object_context}} = + Object.get_cached_by_ap_id(valid_announce["object"]) + + {:ok, %{"context" => context}, _} = + valid_announce + |> Map.put("context", "https://example.org/invalid_context_id") + |> ObjectValidator.validate([]) + + assert context == object_context + end + test "returns an error if the object can't be found", %{valid_announce: valid_announce} do without_object = valid_announce @@ -51,16 +63,6 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AnnouncValidationTest do assert {:object, {"can't find object", []}} in cng.errors end - test "returns an error if we don't have the actor", %{valid_announce: valid_announce} do - nonexisting_actor = - valid_announce - |> Map.put("actor", "https://gensokyo.2hu/users/raymoo") - - {:error, cng} = ObjectValidator.validate(nonexisting_actor, []) - - assert {:actor, {"can't find user", []}} in cng.errors - end - test "returns an error if the actor already announced the object", %{ valid_announce: valid_announce, announcer: announcer, @@ -81,7 +83,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AnnouncValidationTest do {:ok, post_activity} = CommonAPI.post(user, %{status: "a secret post", visibility: "private"}) - object = Object.normalize(post_activity, false) + object = Object.normalize(post_activity, fetch: false) # Another user can't announce it {:ok, announce, []} = Builder.announce(announcer, object, public: false) diff --git a/test/web/activity_pub/object_validators/note_validator_test.exs b/test/pleroma/web/activity_pub/object_validators/article_note_page_validator_test.exs index 30c481ffb..720c17d8d 100644 --- a/test/web/activity_pub/object_validators/note_validator_test.exs +++ b/test/pleroma/web/activity_pub/object_validators/article_note_page_validator_test.exs @@ -1,11 +1,11 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.Web.ActivityPub.ObjectValidators.NoteValidatorTest do - use Pleroma.DataCase +defmodule Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidatorTest do + use Pleroma.DataCase, async: true - alias Pleroma.Web.ActivityPub.ObjectValidators.NoteValidator + alias Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidator alias Pleroma.Web.ActivityPub.Utils import Pleroma.Factory @@ -29,7 +29,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.NoteValidatorTest do end test "a basic note validates", %{note: note} do - %{valid?: true} = NoteValidator.cast_and_validate(note) + %{valid?: true} = ArticleNotePageValidator.cast_and_validate(note) end end end diff --git a/test/web/activity_pub/object_validators/attachment_validator_test.exs b/test/pleroma/web/activity_pub/object_validators/attachment_validator_test.exs index 558bb3131..9150b8d41 100644 --- a/test/web/activity_pub/object_validators/attachment_validator_test.exs +++ b/test/pleroma/web/activity_pub/object_validators/attachment_validator_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.ObjectValidators.AttachmentValidatorTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.ObjectValidators.AttachmentValidator @@ -33,7 +33,8 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AttachmentValidatorTest do "http://mastodon.example.org/system/media_attachments/files/000/000/002/original/334ce029e7bfb920.jpg", "type" => "Document", "name" => nil, - "mediaType" => "image/jpeg" + "mediaType" => "image/jpeg", + "blurhash" => "UD9jJz~VSbR#xT$~%KtQX9R,WAs9RjWBs:of" } {:ok, attachment} = @@ -50,13 +51,14 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AttachmentValidatorTest do ] = attachment.url assert attachment.mediaType == "image/jpeg" + assert attachment.blurhash == "UD9jJz~VSbR#xT$~%KtQX9R,WAs9RjWBs:of" end test "it handles our own uploads" do user = insert(:user) file = %Plug.Upload{ - content_type: "image/jpg", + content_type: "image/jpeg", path: Path.absname("test/fixtures/image.jpg"), filename: "an_image.jpg" } @@ -70,5 +72,70 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AttachmentValidatorTest do assert attachment.mediaType == "image/jpeg" end + + test "it handles image dimensions" do + attachment = %{ + "url" => [ + %{ + "type" => "Link", + "mediaType" => "image/jpeg", + "href" => "https://example.com/images/1.jpg", + "width" => 200, + "height" => 100 + } + ], + "type" => "Document", + "name" => nil, + "mediaType" => "image/jpeg" + } + + {:ok, attachment} = + AttachmentValidator.cast_and_validate(attachment) + |> Ecto.Changeset.apply_action(:insert) + + assert [ + %{ + href: "https://example.com/images/1.jpg", + type: "Link", + mediaType: "image/jpeg", + width: 200, + height: 100 + } + ] = attachment.url + + assert attachment.mediaType == "image/jpeg" + end + + test "it transforms image dimentions to our internal format" do + attachment = %{ + "type" => "Document", + "name" => "Hello world", + "url" => "https://media.example.tld/1.jpg", + "width" => 880, + "height" => 960, + "mediaType" => "image/jpeg", + "blurhash" => "eTKL26+HDjcEIBVl;ds+K6t301W.t7nit7y1E,R:v}ai4nXSt7V@of" + } + + expected = %AttachmentValidator{ + type: "Document", + name: "Hello world", + mediaType: "image/jpeg", + blurhash: "eTKL26+HDjcEIBVl;ds+K6t301W.t7nit7y1E,R:v}ai4nXSt7V@of", + url: [ + %AttachmentValidator.UrlObjectValidator{ + type: "Link", + mediaType: "image/jpeg", + href: "https://media.example.tld/1.jpg", + width: 880, + height: 960 + } + ] + } + + {:ok, ^expected} = + AttachmentValidator.cast_and_validate(attachment) + |> Ecto.Changeset.apply_action(:insert) + end end end diff --git a/test/web/activity_pub/object_validators/block_validation_test.exs b/test/pleroma/web/activity_pub/object_validators/block_validation_test.exs index c08d4b2e8..ad6190892 100644 --- a/test/web/activity_pub/object_validators/block_validation_test.exs +++ b/test/pleroma/web/activity_pub/object_validators/block_validation_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.ObjectValidators.BlockValidationTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true alias Pleroma.Web.ActivityPub.Builder alias Pleroma.Web.ActivityPub.ObjectValidator diff --git a/test/web/activity_pub/object_validators/chat_validation_test.exs b/test/pleroma/web/activity_pub/object_validators/chat_validation_test.exs index 16e4808e5..def2a10b4 100644 --- a/test/web/activity_pub/object_validators/chat_validation_test.exs +++ b/test/pleroma/web/activity_pub/object_validators/chat_validation_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.ObjectValidators.ChatValidationTest do @@ -17,7 +17,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ChatValidationTest do user = insert(:user) recipient = insert(:user) {:ok, activity} = CommonAPI.post_chat_message(user, recipient, "hey") - object = Object.normalize(activity, false) + object = Object.normalize(activity, fetch: false) {:ok, create_data, _} = Builder.create(user, object.data, [recipient.ap_id]) @@ -68,7 +68,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ChatValidationTest do test "validates for a basic object we build", %{valid_chat_message: valid_chat_message} do assert {:ok, object, _meta} = ObjectValidator.validate(valid_chat_message, []) - assert Map.put(valid_chat_message, "attachment", nil) == object + assert valid_chat_message == object assert match?(%{"firefox" => _}, object["emoji"]) end @@ -77,7 +77,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ChatValidationTest do user: user } do file = %Plug.Upload{ - content_type: "image/jpg", + content_type: "image/jpeg", path: Path.absname("test/fixtures/image.jpg"), filename: "an_image.jpg" } @@ -98,7 +98,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ChatValidationTest do user: user } do file = %Plug.Upload{ - content_type: "image/jpg", + content_type: "image/jpeg", path: Path.absname("test/fixtures/image.jpg"), filename: "an_image.jpg" } @@ -119,7 +119,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ChatValidationTest do user: user } do file = %Plug.Upload{ - content_type: "image/jpg", + content_type: "image/jpeg", path: Path.absname("test/fixtures/image.jpg"), filename: "an_image.jpg" } @@ -149,7 +149,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ChatValidationTest do test "does not validate if the message is longer than the remote_limit", %{ valid_chat_message: valid_chat_message } do - Pleroma.Config.put([:instance, :remote_limit], 2) + clear_config([:instance, :remote_limit], 2) refute match?({:ok, _object, _meta}, ObjectValidator.validate(valid_chat_message, [])) end diff --git a/test/web/activity_pub/object_validators/delete_validation_test.exs b/test/pleroma/web/activity_pub/object_validators/delete_validation_test.exs index 02683b899..7ae4399ed 100644 --- a/test/web/activity_pub/object_validators/delete_validation_test.exs +++ b/test/pleroma/web/activity_pub/object_validators/delete_validation_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.ObjectValidators.DeleteValidationTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true alias Pleroma.Object alias Pleroma.Web.ActivityPub.Builder diff --git a/test/web/activity_pub/object_validators/emoji_react_validation_test.exs b/test/pleroma/web/activity_pub/object_validators/emoji_react_handling_test.exs index 582e6d785..7fd98266a 100644 --- a/test/web/activity_pub/object_validators/emoji_react_validation_test.exs +++ b/test/pleroma/web/activity_pub/object_validators/emoji_react_handling_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactHandlingTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true alias Pleroma.Web.ActivityPub.Builder alias Pleroma.Web.ActivityPub.ObjectValidator diff --git a/test/web/activity_pub/object_validators/follow_validation_test.exs b/test/pleroma/web/activity_pub/object_validators/follow_validation_test.exs index 6e1378be2..d2a9b72a5 100644 --- a/test/web/activity_pub/object_validators/follow_validation_test.exs +++ b/test/pleroma/web/activity_pub/object_validators/follow_validation_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.ObjectValidators.FollowValidationTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true alias Pleroma.Web.ActivityPub.Builder alias Pleroma.Web.ActivityPub.ObjectValidator diff --git a/test/web/activity_pub/object_validators/like_validation_test.exs b/test/pleroma/web/activity_pub/object_validators/like_validation_test.exs index 2c033b7e2..e9ad817f1 100644 --- a/test/web/activity_pub/object_validators/like_validation_test.exs +++ b/test/pleroma/web/activity_pub/object_validators/like_validation_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.ObjectValidators.LikeValidationTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true alias Pleroma.Web.ActivityPub.ObjectValidator alias Pleroma.Web.ActivityPub.ObjectValidators.LikeValidator @@ -40,17 +40,30 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.LikeValidationTest do assert LikeValidator.cast_and_validate(valid_like).valid? end - test "sets the 'to' field to the object actor if no recipients are given", %{ + test "Add object actor from 'to' field if it doesn't owns the like", %{valid_like: valid_like} do + user = insert(:user) + + object_actor = valid_like["actor"] + + valid_like = + valid_like + |> Map.put("actor", user.ap_id) + |> Map.put("to", []) + + {:ok, object, _meta} = ObjectValidator.validate(valid_like, []) + assert object_actor in object["to"] + end + + test "Removes object actor from 'to' field if it owns the like", %{ valid_like: valid_like, user: user } do - without_recipients = + valid_like = valid_like - |> Map.delete("to") + |> Map.put("to", [user.ap_id]) - {:ok, object, _meta} = ObjectValidator.validate(without_recipients, []) - - assert object["to"] == [user.ap_id] + {:ok, object, _meta} = ObjectValidator.validate(valid_like, []) + refute user.ap_id in object["to"] end test "sets the context field to the context of the object if no context is given", %{ @@ -66,16 +79,6 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.LikeValidationTest do assert object["context"] == post_activity.data["context"] end - test "it errors when the actor is missing or not known", %{valid_like: valid_like} do - without_actor = Map.delete(valid_like, "actor") - - refute LikeValidator.cast_and_validate(without_actor).valid? - - with_invalid_actor = Map.put(valid_like, "actor", "invalidactor") - - refute LikeValidator.cast_and_validate(with_invalid_actor).valid? - end - test "it errors when the object is missing or not known", %{valid_like: valid_like} do without_object = Map.delete(valid_like, "object") diff --git a/test/web/activity_pub/object_validators/reject_validation_test.exs b/test/pleroma/web/activity_pub/object_validators/reject_validation_test.exs index 370bb6e5c..562656a5f 100644 --- a/test/web/activity_pub/object_validators/reject_validation_test.exs +++ b/test/pleroma/web/activity_pub/object_validators/reject_validation_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.ObjectValidators.RejectValidationTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true alias Pleroma.Web.ActivityPub.Builder alias Pleroma.Web.ActivityPub.ObjectValidator diff --git a/test/web/activity_pub/object_validators/undo_validation_test.exs b/test/pleroma/web/activity_pub/object_validators/undo_handling_test.exs index 75bbcc4b6..505ca2d2f 100644 --- a/test/web/activity_pub/object_validators/undo_validation_test.exs +++ b/test/pleroma/web/activity_pub/object_validators/undo_handling_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.ObjectValidators.UndoHandlingTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true alias Pleroma.Web.ActivityPub.Builder alias Pleroma.Web.ActivityPub.ObjectValidator diff --git a/test/web/activity_pub/object_validators/update_validation_test.exs b/test/pleroma/web/activity_pub/object_validators/update_handling_test.exs index 5e80cf731..15e4a82cd 100644 --- a/test/web/activity_pub/object_validators/update_validation_test.exs +++ b/test/pleroma/web/activity_pub/object_validators/update_handling_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.ObjectValidators.UpdateHandlingTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true alias Pleroma.Web.ActivityPub.Builder alias Pleroma.Web.ActivityPub.ObjectValidator diff --git a/test/pleroma/web/activity_pub/pipeline_test.exs b/test/pleroma/web/activity_pub/pipeline_test.exs new file mode 100644 index 000000000..e606fa3d1 --- /dev/null +++ b/test/pleroma/web/activity_pub/pipeline_test.exs @@ -0,0 +1,103 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ActivityPub.PipelineTest do + use Pleroma.DataCase, async: true + + import Mox + import Pleroma.Factory + + alias Pleroma.ConfigMock + alias Pleroma.Web.ActivityPub.ActivityPubMock + alias Pleroma.Web.ActivityPub.MRFMock + alias Pleroma.Web.ActivityPub.ObjectValidatorMock + alias Pleroma.Web.ActivityPub.SideEffectsMock + alias Pleroma.Web.FederatorMock + + setup :verify_on_exit! + + describe "common_pipeline/2" do + setup do + ObjectValidatorMock + |> expect(:validate, fn o, m -> {:ok, o, m} end) + + MRFMock + |> expect(:pipeline_filter, fn o, m -> {:ok, o, m} end) + + SideEffectsMock + |> expect(:handle, fn o, m -> {:ok, o, m} end) + |> expect(:handle_after_transaction, fn m -> m end) + + :ok + end + + test "when given an `object_data` in meta, Federation will receive a the original activity with the `object` field set to this embedded object" do + activity = insert(:note_activity) + object = %{"id" => "1", "type" => "Love"} + meta = [local: true, object_data: object] + + activity_with_object = %{activity | data: Map.put(activity.data, "object", object)} + + ActivityPubMock + |> expect(:persist, fn _, m -> {:ok, activity, m} end) + + FederatorMock + |> expect(:publish, fn ^activity_with_object -> :ok end) + + ConfigMock + |> expect(:get, fn [:instance, :federating] -> true end) + + assert {:ok, ^activity, ^meta} = + Pleroma.Web.ActivityPub.Pipeline.common_pipeline( + activity.data, + meta + ) + end + + test "it goes through validation, filtering, persisting, side effects and federation for local activities" do + activity = insert(:note_activity) + meta = [local: true] + + ActivityPubMock + |> expect(:persist, fn _, m -> {:ok, activity, m} end) + + FederatorMock + |> expect(:publish, fn ^activity -> :ok end) + + ConfigMock + |> expect(:get, fn [:instance, :federating] -> true end) + + assert {:ok, ^activity, ^meta} = + Pleroma.Web.ActivityPub.Pipeline.common_pipeline(activity.data, meta) + end + + test "it goes through validation, filtering, persisting, side effects without federation for remote activities" do + activity = insert(:note_activity) + meta = [local: false] + + ActivityPubMock + |> expect(:persist, fn _, m -> {:ok, activity, m} end) + + ConfigMock + |> expect(:get, fn [:instance, :federating] -> true end) + + assert {:ok, ^activity, ^meta} = + Pleroma.Web.ActivityPub.Pipeline.common_pipeline(activity.data, meta) + end + + test "it goes through validation, filtering, persisting, side effects without federation for local activities if federation is deactivated" do + activity = insert(:note_activity) + meta = [local: true] + + ActivityPubMock + |> expect(:persist, fn _, m -> {:ok, activity, m} end) + + ConfigMock + |> expect(:get, fn [:instance, :federating] -> false end) + + assert {:ok, ^activity, ^meta} = + Pleroma.Web.ActivityPub.Pipeline.common_pipeline(activity.data, meta) + end + end +end diff --git a/test/web/activity_pub/publisher_test.exs b/test/pleroma/web/activity_pub/publisher_test.exs index b9388b966..b50e22bbe 100644 --- a/test/web/activity_pub/publisher_test.exs +++ b/test/pleroma/web/activity_pub/publisher_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.PublisherTest do @@ -38,7 +38,7 @@ defmodule Pleroma.Web.ActivityPub.PublisherTest do }, %{ "rel" => "http://ostatus.org/schema/1.0/subscribe", - "template" => "#{Pleroma.Web.base_url()}/ostatus_subscribe?acct={uri}" + "template" => "#{Pleroma.Web.Endpoint.url()}/ostatus_subscribe?acct={uri}" } ] @@ -267,6 +267,80 @@ defmodule Pleroma.Web.ActivityPub.PublisherTest do end describe "publish/2" do + test_with_mock "doesn't publish a non-public activity to quarantined instances.", + Pleroma.Web.Federator.Publisher, + [:passthrough], + [] do + Config.put([:instance, :quarantined_instances], [{"domain.com", "some reason"}]) + + follower = + insert(:user, %{ + local: false, + inbox: "https://domain.com/users/nick1/inbox", + ap_enabled: true + }) + + actor = insert(:user, follower_address: follower.ap_id) + + {:ok, follower, actor} = Pleroma.User.follow(follower, actor) + actor = refresh_record(actor) + + note_activity = + insert(:followers_only_note_activity, + user: actor, + recipients: [follower.ap_id] + ) + + res = Publisher.publish(actor, note_activity) + + assert res == :ok + + assert not called( + Pleroma.Web.Federator.Publisher.enqueue_one(Publisher, %{ + inbox: "https://domain.com/users/nick1/inbox", + actor_id: actor.id, + id: note_activity.data["id"] + }) + ) + end + + test_with_mock "Publishes a non-public activity to non-quarantined instances.", + Pleroma.Web.Federator.Publisher, + [:passthrough], + [] do + Config.put([:instance, :quarantined_instances], [{"somedomain.com", "some reason"}]) + + follower = + insert(:user, %{ + local: false, + inbox: "https://domain.com/users/nick1/inbox", + ap_enabled: true + }) + + actor = insert(:user, follower_address: follower.ap_id) + + {:ok, follower, actor} = Pleroma.User.follow(follower, actor) + actor = refresh_record(actor) + + note_activity = + insert(:followers_only_note_activity, + user: actor, + recipients: [follower.ap_id] + ) + + res = Publisher.publish(actor, note_activity) + + assert res == :ok + + assert called( + Pleroma.Web.Federator.Publisher.enqueue_one(Publisher, %{ + inbox: "https://domain.com/users/nick1/inbox", + actor_id: actor.id, + id: note_activity.data["id"] + }) + ) + end + test_with_mock "publishes an activity with BCC to all relevant peers.", Pleroma.Web.Federator.Publisher, [:passthrough], @@ -281,8 +355,7 @@ defmodule Pleroma.Web.ActivityPub.PublisherTest do actor = insert(:user, follower_address: follower.ap_id) user = insert(:user) - {:ok, _follower_one} = Pleroma.User.follow(follower, actor) - actor = refresh_record(actor) + {:ok, follower, actor} = Pleroma.User.follow(follower, actor) note_activity = insert(:note_activity, @@ -323,7 +396,7 @@ defmodule Pleroma.Web.ActivityPub.PublisherTest do actor = insert(:user) note_activity = insert(:note_activity, user: actor) - object = Object.normalize(note_activity) + object = Object.normalize(note_activity, fetch: false) activity_path = String.trim_leading(note_activity.data["id"], Pleroma.Web.Endpoint.url()) object_path = String.trim_leading(object.data["id"], Pleroma.Web.Endpoint.url()) diff --git a/test/web/activity_pub/relay_test.exs b/test/pleroma/web/activity_pub/relay_test.exs index 9d657ac4f..d6de7d61e 100644 --- a/test/web/activity_pub/relay_test.exs +++ b/test/pleroma/web/activity_pub/relay_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.RelayTest do @@ -63,6 +63,46 @@ defmodule Pleroma.Web.ActivityPub.RelayTest do assert activity.data["to"] == [user.ap_id] refute "#{user.ap_id}/followers" in User.following(service_actor) end + + test "force unfollow when target service is dead" do + user = insert(:user) + user_ap_id = user.ap_id + user_id = user.id + + Tesla.Mock.mock(fn %{method: :get, url: ^user_ap_id} -> + %Tesla.Env{status: 404} + end) + + service_actor = Relay.get_actor() + CommonAPI.follow(service_actor, user) + assert "#{user.ap_id}/followers" in User.following(service_actor) + + assert Pleroma.Repo.get_by( + Pleroma.FollowingRelationship, + follower_id: service_actor.id, + following_id: user_id + ) + + Pleroma.Repo.delete(user) + User.invalidate_cache(user) + + assert {:ok, %Activity{} = activity} = Relay.unfollow(user_ap_id, %{force: true}) + + assert refresh_record(service_actor).following_count == 0 + + refute Pleroma.Repo.get_by( + Pleroma.FollowingRelationship, + follower_id: service_actor.id, + following_id: user_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] + refute "#{user.ap_id}/followers" in User.following(service_actor) + end end describe "publish/1" do @@ -108,7 +148,7 @@ defmodule Pleroma.Web.ActivityPub.RelayTest do assert {:ok, %Activity{} = activity} = Relay.publish(note) assert activity.data["type"] == "Announce" assert activity.data["actor"] == service_actor.ap_id - assert activity.data["to"] == [service_actor.follower_address] + assert service_actor.follower_address in activity.data["to"] assert called(Pleroma.Web.Federator.publish(activity)) end diff --git a/test/pleroma/web/activity_pub/side_effects/delete_test.exs b/test/pleroma/web/activity_pub/side_effects/delete_test.exs new file mode 100644 index 000000000..20f0d4b70 --- /dev/null +++ b/test/pleroma/web/activity_pub/side_effects/delete_test.exs @@ -0,0 +1,147 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ActivityPub.SideEffects.DeleteTest do + use Oban.Testing, repo: Pleroma.Repo + use Pleroma.DataCase, async: true + + alias Pleroma.Activity + alias Pleroma.Object + alias Pleroma.Repo + alias Pleroma.Tests.ObanHelpers + alias Pleroma.User + alias Pleroma.Web.ActivityPub.ActivityPub + alias Pleroma.Web.ActivityPub.Builder + alias Pleroma.Web.ActivityPub.SideEffects + alias Pleroma.Web.CommonAPI + + alias Pleroma.LoggerMock + alias Pleroma.Web.ActivityPub.ActivityPubMock + + import Mox + import Pleroma.Factory + + describe "user deletion" do + setup do + user = insert(:user) + + {:ok, delete_user_data, _meta} = Builder.delete(user, user.ap_id) + {:ok, delete_user, _meta} = ActivityPub.persist(delete_user_data, local: true) + + %{ + user: user, + delete_user: delete_user + } + end + + test "it handles user deletions", %{delete_user: delete, user: user} do + {:ok, _delete, _} = SideEffects.handle(delete) + ObanHelpers.perform_all() + + refute User.get_cached_by_ap_id(user.ap_id).is_active + end + end + + describe "object deletion" do + setup do + user = insert(:user) + other_user = insert(:user) + + {:ok, op} = CommonAPI.post(other_user, %{status: "big oof"}) + {:ok, post} = CommonAPI.post(user, %{status: "hey", in_reply_to_id: op}) + {:ok, favorite} = CommonAPI.favorite(user, post.id) + object = Object.normalize(post, fetch: false) + {:ok, delete_data, _meta} = Builder.delete(user, object.data["id"]) + {:ok, delete, _meta} = ActivityPub.persist(delete_data, local: true) + + %{ + user: user, + delete: delete, + post: post, + object: object, + op: op, + favorite: favorite + } + end + + test "it handles object deletions", %{ + delete: delete, + post: post, + object: object, + user: user, + op: op, + favorite: favorite + } do + object_id = object.id + user_id = user.id + + ActivityPubMock + |> expect(:stream_out, fn ^delete -> nil end) + |> expect(:stream_out_participations, fn %Object{id: ^object_id}, %User{id: ^user_id} -> + nil + end) + + {:ok, _delete, _} = SideEffects.handle(delete) + user = User.get_cached_by_ap_id(object.data["actor"]) + + object = Object.get_by_id(object.id) + assert object.data["type"] == "Tombstone" + refute Activity.get_by_id(post.id) + refute Activity.get_by_id(favorite.id) + + user = User.get_by_id(user.id) + assert user.note_count == 0 + + object = Object.normalize(op.data["object"], fetch: false) + + assert object.data["repliesCount"] == 0 + end + + test "it handles object deletions when the object itself has been pruned", %{ + delete: delete, + post: post, + object: object, + user: user, + op: op + } do + object_id = object.id + user_id = user.id + + ActivityPubMock + |> expect(:stream_out, fn ^delete -> nil end) + |> expect(:stream_out_participations, fn %Object{id: ^object_id}, %User{id: ^user_id} -> + nil + end) + + {:ok, _delete, _} = SideEffects.handle(delete) + user = User.get_cached_by_ap_id(object.data["actor"]) + + object = Object.get_by_id(object.id) + assert object.data["type"] == "Tombstone" + refute Activity.get_by_id(post.id) + + user = User.get_by_id(user.id) + assert user.note_count == 0 + + object = Object.normalize(op.data["object"], fetch: false) + + assert object.data["repliesCount"] == 0 + end + + test "it logs issues with objects deletion", %{ + delete: delete, + object: object + } do + {:ok, _object} = + object + |> Object.change(%{data: Map.delete(object.data, "actor")}) + |> Repo.update() + + LoggerMock + |> expect(:error, fn str -> assert str =~ "The object doesn't have an actor" end) + + {:error, :no_object_actor} = SideEffects.handle(delete) + end + end +end diff --git a/test/web/activity_pub/side_effects_test.exs b/test/pleroma/web/activity_pub/side_effects_test.exs index 9efbaad04..c6155ed18 100644 --- a/test/web/activity_pub/side_effects_test.exs +++ b/test/pleroma/web/activity_pub/side_effects_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.SideEffectsTest do @@ -19,7 +19,6 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do alias Pleroma.Web.ActivityPub.SideEffects alias Pleroma.Web.CommonAPI - import ExUnit.CaptureLog import Mock import Pleroma.Factory @@ -89,6 +88,16 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do assert User.blocks?(user, blocked) end + test "it updates following relationship", %{user: user, blocked: blocked, block: block} do + {:ok, _, _} = SideEffects.handle(block) + + refute Pleroma.FollowingRelationship.get(user, blocked) + assert User.get_follow_state(user, blocked) == nil + assert User.get_follow_state(blocked, user) == nil + assert User.get_follow_state(user, blocked, nil) == nil + assert User.get_follow_state(blocked, user, nil) == nil + end + test "it blocks but does not unfollow if the relevant setting is set", %{ user: user, blocked: blocked, @@ -108,7 +117,7 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do describe "update users" do setup do - user = insert(:user) + user = insert(:user, local: false) {:ok, update_data, []} = Builder.update(user, %{"id" => user.ap_id, "name" => "new name!"}) {:ok, update, _meta} = ActivityPub.persist(update_data, local: true) @@ -131,115 +140,6 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do end end - describe "delete objects" do - setup do - user = insert(:user) - other_user = insert(:user) - - {:ok, op} = CommonAPI.post(other_user, %{status: "big oof"}) - {:ok, post} = CommonAPI.post(user, %{status: "hey", in_reply_to_id: op}) - {:ok, favorite} = CommonAPI.favorite(user, post.id) - object = Object.normalize(post) - {:ok, delete_data, _meta} = Builder.delete(user, object.data["id"]) - {:ok, delete_user_data, _meta} = Builder.delete(user, user.ap_id) - {:ok, delete, _meta} = ActivityPub.persist(delete_data, local: true) - {:ok, delete_user, _meta} = ActivityPub.persist(delete_user_data, local: true) - - %{ - user: user, - delete: delete, - post: post, - object: object, - delete_user: delete_user, - op: op, - favorite: favorite - } - end - - test "it handles object deletions", %{ - delete: delete, - post: post, - object: object, - user: user, - op: op, - favorite: favorite - } do - with_mock Pleroma.Web.ActivityPub.ActivityPub, [:passthrough], - stream_out: fn _ -> nil end, - stream_out_participations: fn _, _ -> nil end do - {:ok, delete, _} = SideEffects.handle(delete) - user = User.get_cached_by_ap_id(object.data["actor"]) - - assert called(Pleroma.Web.ActivityPub.ActivityPub.stream_out(delete)) - assert called(Pleroma.Web.ActivityPub.ActivityPub.stream_out_participations(object, user)) - end - - object = Object.get_by_id(object.id) - assert object.data["type"] == "Tombstone" - refute Activity.get_by_id(post.id) - refute Activity.get_by_id(favorite.id) - - user = User.get_by_id(user.id) - assert user.note_count == 0 - - object = Object.normalize(op.data["object"], false) - - assert object.data["repliesCount"] == 0 - end - - test "it handles object deletions when the object itself has been pruned", %{ - delete: delete, - post: post, - object: object, - user: user, - op: op - } do - with_mock Pleroma.Web.ActivityPub.ActivityPub, [:passthrough], - stream_out: fn _ -> nil end, - stream_out_participations: fn _, _ -> nil end do - {:ok, delete, _} = SideEffects.handle(delete) - user = User.get_cached_by_ap_id(object.data["actor"]) - - assert called(Pleroma.Web.ActivityPub.ActivityPub.stream_out(delete)) - assert called(Pleroma.Web.ActivityPub.ActivityPub.stream_out_participations(object, user)) - end - - object = Object.get_by_id(object.id) - assert object.data["type"] == "Tombstone" - refute Activity.get_by_id(post.id) - - user = User.get_by_id(user.id) - assert user.note_count == 0 - - object = Object.normalize(op.data["object"], false) - - assert object.data["repliesCount"] == 0 - end - - test "it handles user deletions", %{delete_user: delete, user: user} do - {:ok, _delete, _} = SideEffects.handle(delete) - ObanHelpers.perform_all() - - assert User.get_cached_by_ap_id(user.ap_id).deactivated - end - - test "it logs issues with objects deletion", %{ - delete: delete, - object: object - } do - {:ok, object} = - object - |> Object.change(%{data: Map.delete(object.data, "actor")}) - |> Repo.update() - - Object.invalid_object_cache(object) - - assert capture_log(fn -> - {:error, :no_object_actor} = SideEffects.handle(delete) - end) =~ "object doesn't have an actor" - end - end - describe "EmojiReact objects" do setup do poster = insert(:user) @@ -267,22 +167,38 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do end end + describe "Question objects" do + setup do + user = insert(:user) + question = build(:question, user: user) + question_activity = build(:question_activity, question: question) + activity_data = Map.put(question_activity.data, "object", question.data["id"]) + meta = [object_data: question.data, local: false] + + {:ok, activity, meta} = ActivityPub.persist(activity_data, meta) + + %{activity: activity, meta: meta} + end + + test "enqueues the poll end", %{activity: activity, meta: meta} do + {:ok, activity, meta} = SideEffects.handle(activity, meta) + + assert_enqueued( + worker: Pleroma.Workers.PollWorker, + args: %{op: "poll_end", activity_id: activity.id}, + scheduled_at: NaiveDateTime.from_iso8601!(meta[:object_data]["closed"]) + ) + end + end + describe "delete users with confirmation pending" do setup do - user = insert(:user, confirmation_pending: true) + user = insert(:user, is_confirmed: false) {:ok, delete_user_data, _meta} = Builder.delete(user, user.ap_id) {:ok, delete_user, _meta} = ActivityPub.persist(delete_user_data, local: true) {:ok, delete: delete_user, user: user} end - test "when activation is not required", %{delete: delete, user: user} do - clear_config([:instance, :account_activation_required], false) - {:ok, _, _} = SideEffects.handle(delete) - ObanHelpers.perform_all() - - assert User.get_cached_by_id(user.id).deactivated - end - test "when activation is required", %{delete: delete, user: user} do clear_config([:instance, :account_activation_required], true) {:ok, _, _} = SideEffects.handle(delete) @@ -636,4 +552,74 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do end end end + + describe "removing a follower" do + setup do + user = insert(:user) + followed = insert(:user) + + {:ok, _, _, follow_activity} = CommonAPI.follow(user, followed) + + {:ok, reject_data, []} = Builder.reject(followed, follow_activity) + {:ok, reject, _meta} = ActivityPub.persist(reject_data, local: true) + + %{user: user, followed: followed, reject: reject} + end + + test "", %{user: user, followed: followed, reject: reject} do + assert User.following?(user, followed) + assert Pleroma.FollowingRelationship.get(user, followed) + + {:ok, _, _} = SideEffects.handle(reject) + + refute User.following?(user, followed) + refute Pleroma.FollowingRelationship.get(user, followed) + assert User.get_follow_state(user, followed) == nil + assert User.get_follow_state(user, followed, nil) == nil + end + end + + describe "removing a follower from remote" do + setup do + user = insert(:user) + followed = insert(:user, local: false) + + # Mock a local-to-remote follow + {:ok, follow_data, []} = Builder.follow(user, followed) + + follow_data = + follow_data + |> Map.put("state", "accept") + + {:ok, follow, _meta} = ActivityPub.persist(follow_data, local: true) + {:ok, _, _} = SideEffects.handle(follow) + + # Mock a remote-to-local accept + {:ok, accept_data, _} = Builder.accept(followed, follow) + {:ok, accept, _} = ActivityPub.persist(accept_data, local: false) + {:ok, _, _} = SideEffects.handle(accept) + + # Mock a remote-to-local reject + {:ok, reject_data, []} = Builder.reject(followed, follow) + {:ok, reject, _meta} = ActivityPub.persist(reject_data, local: false) + + %{user: user, followed: followed, reject: reject} + end + + test "", %{user: user, followed: followed, reject: reject} do + assert User.following?(user, followed) + assert Pleroma.FollowingRelationship.get(user, followed) + + {:ok, _, _} = SideEffects.handle(reject) + + refute User.following?(user, followed) + refute Pleroma.FollowingRelationship.get(user, followed) + + assert Pleroma.Web.ActivityPub.Utils.fetch_latest_follow(user, followed).data["state"] == + "reject" + + assert User.get_follow_state(user, followed) == nil + assert User.get_follow_state(user, followed, nil) == nil + end + end end diff --git a/test/web/activity_pub/transmogrifier/accept_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/accept_handling_test.exs index 77d468f5c..58490076d 100644 --- a/test/web/activity_pub/transmogrifier/accept_handling_test.exs +++ b/test/pleroma/web/activity_pub/transmogrifier/accept_handling_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.Transmogrifier.AcceptHandlingTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true alias Pleroma.User alias Pleroma.Web.ActivityPub.Transmogrifier @@ -15,14 +15,14 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.AcceptHandlingTest do follower = insert(:user) followed = insert(:user) - {:ok, follower} = User.follow(follower, followed) + {:ok, follower, followed} = User.follow(follower, followed) assert User.following?(follower, followed) == true {:ok, _, _, follow_activity} = CommonAPI.follow(follower, followed) accept_data = File.read!("test/fixtures/mastodon-accept-activity.json") - |> Poison.decode!() + |> Jason.decode!() |> Map.put("actor", followed.ap_id) object = @@ -46,13 +46,13 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.AcceptHandlingTest do test "it works for incoming accepts which are referenced by IRI only" do follower = insert(:user) - followed = insert(:user, locked: true) + followed = insert(:user, is_locked: true) {:ok, _, _, follow_activity} = CommonAPI.follow(follower, followed) accept_data = File.read!("test/fixtures/mastodon-accept-activity.json") - |> Poison.decode!() + |> Jason.decode!() |> Map.put("actor", followed.ap_id) |> Map.put("object", follow_activity.data["id"]) @@ -72,11 +72,11 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.AcceptHandlingTest do test "it fails for incoming accepts which cannot be correlated" do follower = insert(:user) - followed = insert(:user, locked: true) + followed = insert(:user, is_locked: true) accept_data = File.read!("test/fixtures/mastodon-accept-activity.json") - |> Poison.decode!() + |> Jason.decode!() |> Map.put("actor", followed.ap_id) accept_data = diff --git a/test/pleroma/web/activity_pub/transmogrifier/add_remove_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/add_remove_handling_test.exs new file mode 100644 index 000000000..b17c0e7bf --- /dev/null +++ b/test/pleroma/web/activity_pub/transmogrifier/add_remove_handling_test.exs @@ -0,0 +1,178 @@ +defmodule Pleroma.Web.ActivityPub.Transmogrifier.AddRemoveHandlingTest do + use Oban.Testing, repo: Pleroma.Repo + use Pleroma.DataCase, async: true + + require Pleroma.Constants + + import Pleroma.Factory + + alias Pleroma.User + alias Pleroma.Web.ActivityPub.Transmogrifier + + test "it accepts Add/Remove activities" do + user = + "test/fixtures/users_mock/user.json" + |> File.read!() + |> String.replace("{{nickname}}", "lain") + + object_id = "c61d6733-e256-4fe1-ab13-1e369789423f" + + object = + "test/fixtures/statuses/note.json" + |> File.read!() + |> String.replace("{{nickname}}", "lain") + |> String.replace("{{object_id}}", object_id) + + object_url = "https://example.com/objects/#{object_id}" + + actor = "https://example.com/users/lain" + + Tesla.Mock.mock(fn + %{ + method: :get, + url: ^actor + } -> + %Tesla.Env{ + status: 200, + body: user, + headers: [{"content-type", "application/activity+json"}] + } + + %{ + method: :get, + url: ^object_url + } -> + %Tesla.Env{ + status: 200, + body: object, + headers: [{"content-type", "application/activity+json"}] + } + + %{method: :get, url: "https://example.com/users/lain/collections/featured"} -> + %Tesla.Env{ + status: 200, + body: + "test/fixtures/users_mock/masto_featured.json" + |> File.read!() + |> String.replace("{{domain}}", "example.com") + |> String.replace("{{nickname}}", "lain"), + headers: [{"content-type", "application/activity+json"}] + } + end) + + message = %{ + "id" => "https://example.com/objects/d61d6733-e256-4fe1-ab13-1e369789423f", + "actor" => actor, + "object" => object_url, + "target" => "https://example.com/users/lain/collections/featured", + "type" => "Add", + "to" => [Pleroma.Constants.as_public()], + "cc" => ["https://example.com/users/lain/followers"], + "bcc" => [], + "bto" => [] + } + + assert {:ok, activity} = Transmogrifier.handle_incoming(message) + assert activity.data == message + user = User.get_cached_by_ap_id(actor) + assert user.pinned_objects[object_url] + + remove = %{ + "id" => "http://localhost:400/objects/d61d6733-e256-4fe1-ab13-1e369789423d", + "actor" => actor, + "object" => object_url, + "target" => "https://example.com/users/lain/collections/featured", + "type" => "Remove", + "to" => [Pleroma.Constants.as_public()], + "cc" => ["https://example.com/users/lain/followers"], + "bcc" => [], + "bto" => [] + } + + assert {:ok, activity} = Transmogrifier.handle_incoming(remove) + assert activity.data == remove + + user = refresh_record(user) + refute user.pinned_objects[object_url] + end + + test "Add/Remove activities for remote users without featured address" do + user = insert(:user, local: false, domain: "example.com") + + user = + user + |> Ecto.Changeset.change(featured_address: nil) + |> Repo.update!() + + %{host: host} = URI.parse(user.ap_id) + + user_data = + "test/fixtures/users_mock/user.json" + |> File.read!() + |> String.replace("{{nickname}}", user.nickname) + + object_id = "c61d6733-e256-4fe1-ab13-1e369789423f" + + object = + "test/fixtures/statuses/note.json" + |> File.read!() + |> String.replace("{{nickname}}", user.nickname) + |> String.replace("{{object_id}}", object_id) + + object_url = "https://#{host}/objects/#{object_id}" + + actor = "https://#{host}/users/#{user.nickname}" + + featured = "https://#{host}/users/#{user.nickname}/collections/featured" + + Tesla.Mock.mock(fn + %{ + method: :get, + url: ^actor + } -> + %Tesla.Env{ + status: 200, + body: user_data, + headers: [{"content-type", "application/activity+json"}] + } + + %{ + method: :get, + url: ^object_url + } -> + %Tesla.Env{ + status: 200, + body: object, + headers: [{"content-type", "application/activity+json"}] + } + + %{method: :get, url: ^featured} -> + %Tesla.Env{ + status: 200, + body: + "test/fixtures/users_mock/masto_featured.json" + |> File.read!() + |> String.replace("{{domain}}", "#{host}") + |> String.replace("{{nickname}}", user.nickname), + headers: [{"content-type", "application/activity+json"}] + } + end) + + message = %{ + "id" => "https://#{host}/objects/d61d6733-e256-4fe1-ab13-1e369789423f", + "actor" => actor, + "object" => object_url, + "target" => "https://#{host}/users/#{user.nickname}/collections/featured", + "type" => "Add", + "to" => [Pleroma.Constants.as_public()], + "cc" => ["https://#{host}/users/#{user.nickname}/followers"], + "bcc" => [], + "bto" => [] + } + + assert {:ok, activity} = Transmogrifier.handle_incoming(message) + assert activity.data == message + user = User.get_cached_by_ap_id(actor) + assert user.pinned_objects[object_url] + end +end diff --git a/test/web/activity_pub/transmogrifier/announce_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/announce_handling_test.exs index e895636b5..524acddaf 100644 --- a/test/web/activity_pub/transmogrifier/announce_handling_test.exs +++ b/test/pleroma/web/activity_pub/transmogrifier/announce_handling_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.Transmogrifier.AnnounceHandlingTest do @@ -36,7 +36,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.AnnounceHandlingTest do end test "it works for incoming announces with actor being inlined (kroeg)" do - data = File.read!("test/fixtures/kroeg-announce-with-inline-actor.json") |> Poison.decode!() + data = File.read!("test/fixtures/kroeg-announce-with-inline-actor.json") |> Jason.decode!() _user = insert(:user, local: false, ap_id: data["actor"]["id"]) other_user = insert(:user) @@ -55,12 +55,16 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.AnnounceHandlingTest do test "it works for incoming announces, fetching the announced object" do data = File.read!("test/fixtures/mastodon-announce.json") - |> Poison.decode!() + |> Jason.decode!() |> Map.put("object", "http://mastodon.example.org/users/admin/statuses/99541947525187367") Tesla.Mock.mock(fn %{method: :get} -> - %Tesla.Env{status: 200, body: File.read!("test/fixtures/mastodon-note-object.json")} + %Tesla.Env{ + status: 200, + body: File.read!("test/fixtures/mastodon-note-object.json"), + headers: HttpRequestMock.activitypub_object_headers() + } end) _user = insert(:user, local: false, ap_id: data["actor"]) @@ -86,7 +90,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.AnnounceHandlingTest do data = File.read!("test/fixtures/mastodon-announce.json") - |> Poison.decode!() + |> Jason.decode!() |> Map.put("object", activity.data["object"]) _user = insert(:user, local: false, ap_id: data["actor"]) @@ -109,7 +113,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.AnnounceHandlingTest do test "it works for incoming announces with an inlined activity" do data = File.read!("test/fixtures/mastodon-announce-private.json") - |> Poison.decode!() + |> Jason.decode!() _user = insert(:user, @@ -126,7 +130,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.AnnounceHandlingTest do assert data["id"] == "http://mastodon.example.org/users/admin/statuses/99542391527669785/activity" - object = Object.normalize(data["object"]) + object = Object.normalize(data["object"], fetch: false) assert object.data["id"] == "http://mastodon.example.org/@admin/99541947525187368" assert object.data["content"] == "this is a private toot" @@ -140,33 +144,10 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.AnnounceHandlingTest do data = File.read!("test/fixtures/bogus-mastodon-announce.json") - |> Poison.decode!() + |> Jason.decode!() _user = insert(:user, local: false, ap_id: data["actor"]) - assert {:error, e} = Transmogrifier.handle_incoming(data) - end - - test "it does not clobber the addressing on announce activities" do - user = insert(:user) - {:ok, activity} = CommonAPI.post(user, %{status: "hey"}) - - data = - File.read!("test/fixtures/mastodon-announce.json") - |> Poison.decode!() - |> Map.put("object", Object.normalize(activity).data["id"]) - |> Map.put("to", ["http://mastodon.example.org/users/admin/followers"]) - |> Map.put("cc", []) - - _user = - insert(:user, - local: false, - ap_id: data["actor"], - follower_address: "http://mastodon.example.org/users/admin/followers" - ) - - {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) - - assert data["to"] == ["http://mastodon.example.org/users/admin/followers"] + assert {:error, _e} = Transmogrifier.handle_incoming(data) end end diff --git a/test/web/activity_pub/transmogrifier/answer_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/answer_handling_test.exs index 0f6605c3f..9c2ef547b 100644 --- a/test/web/activity_pub/transmogrifier/answer_handling_test.exs +++ b/test/pleroma/web/activity_pub/transmogrifier/answer_handling_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.Transmogrifier.AnswerHandlingTest do @@ -26,22 +26,23 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.AnswerHandlingTest do poll: %{options: ["suya", "suya.", "suya.."], expires_in: 10} }) - object = Object.normalize(activity) + object = Object.normalize(activity, fetch: false) + assert object.data["repliesCount"] == nil data = File.read!("test/fixtures/mastodon-vote.json") - |> Poison.decode!() + |> Jason.decode!() |> Kernel.put_in(["to"], user.ap_id) |> Kernel.put_in(["object", "inReplyTo"], object.data["id"]) |> Kernel.put_in(["object", "to"], user.ap_id) {:ok, %Activity{local: false} = activity} = Transmogrifier.handle_incoming(data) - answer_object = Object.normalize(activity) + answer_object = Object.normalize(activity, fetch: false) assert answer_object.data["type"] == "Answer" assert answer_object.data["inReplyTo"] == object.data["id"] new_object = Object.get_by_ap_id(object.data["id"]) - assert new_object.data["replies_count"] == object.data["replies_count"] + assert new_object.data["repliesCount"] == nil assert Enum.any?( new_object.data["oneOf"], @@ -61,11 +62,11 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.AnswerHandlingTest do poll: %{options: ["suya", "suya.", "suya.."], expires_in: 10} }) - poll_object = Object.normalize(poll_activity) + poll_object = Object.normalize(poll_activity, fetch: false) # TODO: Replace with CommonAPI vote creation when implemented data = File.read!("test/fixtures/mastodon-vote.json") - |> Poison.decode!() + |> Jason.decode!() |> Kernel.put_in(["to"], user.ap_id) |> Kernel.put_in(["object", "inReplyTo"], poll_object.data["id"]) |> Kernel.put_in(["object", "to"], user.ap_id) diff --git a/test/pleroma/web/activity_pub/transmogrifier/article_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/article_handling_test.exs new file mode 100644 index 000000000..5dbc5eb95 --- /dev/null +++ b/test/pleroma/web/activity_pub/transmogrifier/article_handling_test.exs @@ -0,0 +1,82 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ActivityPub.Transmogrifier.ArticleHandlingTest do + use Oban.Testing, repo: Pleroma.Repo + use Pleroma.DataCase + + alias Pleroma.Activity + alias Pleroma.Object + alias Pleroma.Object.Fetcher + alias Pleroma.Web.ActivityPub.Transmogrifier + + test "Pterotype (Wordpress Plugin) Article" do + Tesla.Mock.mock(fn %{url: "https://wedistribute.org/wp-json/pterotype/v1/actor/-blog"} -> + %Tesla.Env{ + status: 200, + body: File.read!("test/fixtures/tesla_mock/wedistribute-user.json"), + headers: HttpRequestMock.activitypub_object_headers() + } + end) + + data = + File.read!("test/fixtures/tesla_mock/wedistribute-create-article.json") |> Jason.decode!() + + {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) + + object = Object.normalize(data["object"], fetch: false) + + assert object.data["name"] == "The end is near: Mastodon plans to drop OStatus support" + + assert object.data["summary"] == + "One of the largest platforms in the federated social web is dropping the protocol that it started with." + + assert object.data["url"] == "https://wedistribute.org/2019/07/mastodon-drops-ostatus/" + end + + test "Plume Article" do + Tesla.Mock.mock(fn + %{url: "https://baptiste.gelez.xyz/~/PlumeDevelopment/this-month-in-plume-june-2018/"} -> + %Tesla.Env{ + status: 200, + body: File.read!("test/fixtures/tesla_mock/baptiste.gelex.xyz-article.json"), + headers: HttpRequestMock.activitypub_object_headers() + } + + %{url: "https://baptiste.gelez.xyz/@/BaptisteGelez"} -> + %Tesla.Env{ + status: 200, + body: File.read!("test/fixtures/tesla_mock/baptiste.gelex.xyz-user.json"), + headers: HttpRequestMock.activitypub_object_headers() + } + end) + + {:ok, object} = + Fetcher.fetch_object_from_id( + "https://baptiste.gelez.xyz/~/PlumeDevelopment/this-month-in-plume-june-2018/" + ) + + assert object.data["name"] == "This Month in Plume: June 2018" + + assert object.data["url"] == + "https://baptiste.gelez.xyz/~/PlumeDevelopment/this-month-in-plume-june-2018/" + end + + test "Prismo Article" do + Tesla.Mock.mock(fn %{url: "https://prismo.news/@mxb"} -> + %Tesla.Env{ + status: 200, + body: File.read!("test/fixtures/tesla_mock/https___prismo.news__mxb.json"), + headers: HttpRequestMock.activitypub_object_headers() + } + end) + + data = File.read!("test/fixtures/prismo-url-map.json") |> Jason.decode!() + + {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) + object = Object.normalize(data["object"], fetch: false) + + assert object.data["url"] == "https://prismo.news/posts/83" + end +end diff --git a/test/web/activity_pub/transmogrifier/audio_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/audio_handling_test.exs index 0636d00c5..a0942ce8b 100644 --- a/test/web/activity_pub/transmogrifier/audio_handling_test.exs +++ b/test/pleroma/web/activity_pub/transmogrifier/audio_handling_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.Transmogrifier.AudioHandlingTest do @@ -24,6 +24,8 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.AudioHandlingTest do "actor" => "http://mastodon.example.org/users/admin", "object" => %{ "type" => "Audio", + "to" => ["https://www.w3.org/ns/activitystreams#Public"], + "cc" => [], "id" => "http://mastodon.example.org/users/admin/listens/1234", "attributedTo" => "http://mastodon.example.org/users/admin", "title" => "lain radio episode 1", @@ -35,7 +37,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.AudioHandlingTest do {:ok, %Activity{local: false} = activity} = Transmogrifier.handle_incoming(data) - object = Object.normalize(activity) + object = Object.normalize(activity, fetch: false) assert object.data["title"] == "lain radio episode 1" assert object.data["artist"] == "lain" @@ -48,19 +50,22 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.AudioHandlingTest do %{url: "https://channels.tests.funkwhale.audio/federation/actors/compositions"} -> %Tesla.Env{ status: 200, - body: File.read!("test/fixtures/tesla_mock/funkwhale_channel.json") + body: File.read!("test/fixtures/tesla_mock/funkwhale_channel.json"), + headers: HttpRequestMock.activitypub_object_headers() } end) - data = File.read!("test/fixtures/tesla_mock/funkwhale_create_audio.json") |> Poison.decode!() + data = File.read!("test/fixtures/tesla_mock/funkwhale_create_audio.json") |> Jason.decode!() {:ok, %Activity{local: false} = activity} = Transmogrifier.handle_incoming(data) - assert object = Object.normalize(activity, false) + assert object = Object.normalize(activity, fetch: false) assert object.data["to"] == ["https://www.w3.org/ns/activitystreams#Public"] - assert object.data["cc"] == [] + assert object.data["cc"] == [ + "https://channels.tests.funkwhale.audio/federation/actors/compositions/followers" + ] assert object.data["url"] == "https://channels.tests.funkwhale.audio/library/tracks/74" @@ -68,7 +73,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.AudioHandlingTest do %{ "mediaType" => "audio/ogg", "type" => "Link", - "name" => nil, "url" => [ %{ "href" => diff --git a/test/web/activity_pub/transmogrifier/block_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/block_handling_test.exs index 71f1a0ed5..70da06d2e 100644 --- a/test/web/activity_pub/transmogrifier/block_handling_test.exs +++ b/test/pleroma/web/activity_pub/transmogrifier/block_handling_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.Transmogrifier.BlockHandlingTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true alias Pleroma.Activity alias Pleroma.User @@ -16,7 +16,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.BlockHandlingTest do data = File.read!("test/fixtures/mastodon-block-activity.json") - |> Poison.decode!() + |> Jason.decode!() |> Map.put("object", user.ap_id) blocker = insert(:user, ap_id: data["actor"]) @@ -36,12 +36,12 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.BlockHandlingTest do data = File.read!("test/fixtures/mastodon-block-activity.json") - |> Poison.decode!() + |> Jason.decode!() |> Map.put("object", blocked.ap_id) |> Map.put("actor", blocker.ap_id) - {:ok, blocker} = User.follow(blocker, blocked) - {:ok, blocked} = User.follow(blocked, blocker) + {:ok, blocker, blocked} = User.follow(blocker, blocked) + {:ok, blocked, blocker} = User.follow(blocked, blocker) assert User.following?(blocker, blocked) assert User.following?(blocked, blocker) diff --git a/test/web/activity_pub/transmogrifier/chat_message_test.exs b/test/pleroma/web/activity_pub/transmogrifier/chat_message_test.exs index 31274c067..958675835 100644 --- a/test/web/activity_pub/transmogrifier/chat_message_test.exs +++ b/test/pleroma/web/activity_pub/transmogrifier/chat_message_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.Transmogrifier.ChatMessageTest do @@ -53,7 +53,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.ChatMessageTest do test "it rejects messages that don't contain content" do data = File.read!("test/fixtures/create-chat-message.json") - |> Poison.decode!() + |> Jason.decode!() object = data["object"] @@ -79,7 +79,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.ChatMessageTest do test "it rejects messages that don't concern local users" do data = File.read!("test/fixtures/create-chat-message.json") - |> Poison.decode!() + |> Jason.decode!() _author = insert(:user, ap_id: data["actor"], local: false, last_refreshed_at: DateTime.utc_now()) @@ -97,7 +97,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.ChatMessageTest do test "it rejects messages where the `to` field of activity and object don't match" do data = File.read!("test/fixtures/create-chat-message.json") - |> Poison.decode!() + |> Jason.decode!() author = insert(:user, ap_id: data["actor"]) _recipient = insert(:user, ap_id: List.first(data["to"])) @@ -115,7 +115,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.ChatMessageTest do data = File.read!("test/fixtures/create-chat-message.json") - |> Poison.decode!() + |> Jason.decode!() |> Map.put("actor", "http://mastodon.example.org/users/admin") |> put_in(["object", "actor"], "http://mastodon.example.org/users/admin") @@ -127,14 +127,14 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.ChatMessageTest do test "it doesn't work for deactivated users" do data = File.read!("test/fixtures/create-chat-message.json") - |> Poison.decode!() + |> Jason.decode!() _author = insert(:user, ap_id: data["actor"], local: false, last_refreshed_at: DateTime.utc_now(), - deactivated: true + is_active: false ) _recipient = insert(:user, ap_id: List.first(data["to"]), local: true) @@ -145,7 +145,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.ChatMessageTest do test "it inserts it and creates a chat" do data = File.read!("test/fixtures/create-chat-message.json") - |> Poison.decode!() + |> Jason.decode!() author = insert(:user, ap_id: data["actor"], local: false, last_refreshed_at: DateTime.utc_now()) diff --git a/test/web/activity_pub/transmogrifier/delete_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/delete_handling_test.exs index c9a53918c..b7160bf58 100644 --- a/test/web/activity_pub/transmogrifier/delete_handling_test.exs +++ b/test/pleroma/web/activity_pub/transmogrifier/delete_handling_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.Transmogrifier.DeleteHandlingTest do @@ -25,7 +25,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.DeleteHandlingTest do data = File.read!("test/fixtures/mastodon-delete.json") - |> Poison.decode!() + |> Jason.decode!() |> Map.put("actor", deleting_user.ap_id) |> put_in(["object", "id"], activity.data["object"]) @@ -40,7 +40,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.DeleteHandlingTest do assert actor == deleting_user.ap_id # Objects are replaced by a tombstone object. - object = Object.normalize(activity.data["object"]) + object = Object.normalize(activity.data["object"], fetch: false) assert object.data["type"] == "Tombstone" end @@ -48,16 +48,17 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.DeleteHandlingTest do activity = insert(:note_activity) {:ok, object} = - Object.normalize(activity.data["object"]) + Object.normalize(activity.data["object"], fetch: false) |> Repo.delete() + # TODO: mock cachex Cachex.del(:object_cache, "object:#{object.data["id"]}") deleting_user = insert(:user) data = File.read!("test/fixtures/mastodon-delete.json") - |> Poison.decode!() + |> Jason.decode!() |> Map.put("actor", deleting_user.ap_id) |> put_in(["object", "id"], activity.data["object"]) @@ -78,7 +79,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.DeleteHandlingTest do data = File.read!("test/fixtures/mastodon-delete.json") - |> Poison.decode!() + |> Jason.decode!() |> Map.put("actor", ap_id) |> put_in(["object", "id"], activity.data["object"]) @@ -91,12 +92,12 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.DeleteHandlingTest do data = File.read!("test/fixtures/mastodon-delete-user.json") - |> Poison.decode!() + |> Jason.decode!() {:ok, _} = Transmogrifier.handle_incoming(data) ObanHelpers.perform_all() - assert User.get_cached_by_ap_id(ap_id).deactivated + refute User.get_cached_by_ap_id(ap_id).is_active end test "it fails for incoming user deletes with spoofed origin" do @@ -104,7 +105,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.DeleteHandlingTest do data = File.read!("test/fixtures/mastodon-delete-user.json") - |> Poison.decode!() + |> Jason.decode!() |> Map.put("actor", ap_id) assert match?({:error, _}, Transmogrifier.handle_incoming(data)) diff --git a/test/web/activity_pub/transmogrifier/emoji_react_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/emoji_react_handling_test.exs index 0fb056b50..20424ee82 100644 --- a/test/web/activity_pub/transmogrifier/emoji_react_handling_test.exs +++ b/test/pleroma/web/activity_pub/transmogrifier/emoji_react_handling_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.Transmogrifier.EmojiReactHandlingTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true alias Pleroma.Activity alias Pleroma.Object @@ -19,7 +19,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.EmojiReactHandlingTest do data = File.read!("test/fixtures/emoji-reaction.json") - |> Poison.decode!() + |> Jason.decode!() |> Map.put("object", activity.data["object"]) |> Map.put("actor", other_user.ap_id) @@ -44,7 +44,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.EmojiReactHandlingTest do data = File.read!("test/fixtures/emoji-reaction-too-long.json") - |> Poison.decode!() + |> Jason.decode!() |> Map.put("object", activity.data["object"]) |> Map.put("actor", other_user.ap_id) @@ -52,7 +52,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.EmojiReactHandlingTest do data = File.read!("test/fixtures/emoji-reaction-no-emoji.json") - |> Poison.decode!() + |> Jason.decode!() |> Map.put("object", activity.data["object"]) |> Map.put("actor", other_user.ap_id) diff --git a/test/web/activity_pub/transmogrifier/event_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/event_handling_test.exs index 7f1ef2cbd..14f5f704a 100644 --- a/test/web/activity_pub/transmogrifier/event_handling_test.exs +++ b/test/pleroma/web/activity_pub/transmogrifier/event_handling_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.Transmogrifier.EventHandlingTest do @@ -13,13 +13,15 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.EventHandlingTest do %{url: "https://mobilizon.org/events/252d5816-00a3-4a89-a66f-15bf65c33e39"} -> %Tesla.Env{ status: 200, - body: File.read!("test/fixtures/tesla_mock/mobilizon.org-event.json") + body: File.read!("test/fixtures/tesla_mock/mobilizon.org-event.json"), + headers: HttpRequestMock.activitypub_object_headers() } %{url: "https://mobilizon.org/@tcit"} -> %Tesla.Env{ status: 200, - body: File.read!("test/fixtures/tesla_mock/mobilizon.org-user.json") + body: File.read!("test/fixtures/tesla_mock/mobilizon.org-user.json"), + headers: HttpRequestMock.activitypub_object_headers() } end) @@ -29,7 +31,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.EventHandlingTest do ) assert object.data["to"] == ["https://www.w3.org/ns/activitystreams#Public"] - assert object.data["cc"] == [] + assert object.data["cc"] == ["https://mobilizon.org/@tcit/followers"] assert object.data["url"] == "https://mobilizon.org/events/252d5816-00a3-4a89-a66f-15bf65c33e39" diff --git a/test/web/activity_pub/transmogrifier/follow_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/follow_handling_test.exs index 757d90941..604444a4c 100644 --- a/test/web/activity_pub/transmogrifier/follow_handling_test.exs +++ b/test/pleroma/web/activity_pub/transmogrifier/follow_handling_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.Transmogrifier.FollowHandlingTest do @@ -28,7 +28,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.FollowHandlingTest do data = File.read!("test/fixtures/osada-follow-activity.json") - |> Poison.decode!() + |> Jason.decode!() |> Map.put("object", user.ap_id) {:ok, %Activity{data: data, local: false} = activity} = Transmogrifier.handle_incoming(data) @@ -47,7 +47,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.FollowHandlingTest do data = File.read!("test/fixtures/mastodon-follow-activity.json") - |> Poison.decode!() + |> Jason.decode!() |> Map.put("object", user.ap_id) {:ok, %Activity{data: data, local: false} = activity} = Transmogrifier.handle_incoming(data) @@ -65,11 +65,11 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.FollowHandlingTest do end test "with locked accounts, it does create a Follow, but not an Accept" do - user = insert(:user, locked: true) + user = insert(:user, is_locked: true) data = File.read!("test/fixtures/mastodon-follow-activity.json") - |> Poison.decode!() + |> Jason.decode!() |> Map.put("object", user.ap_id) {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) @@ -100,7 +100,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.FollowHandlingTest do data = File.read!("test/fixtures/mastodon-follow-activity.json") - |> Poison.decode!() + |> Jason.decode!() |> Map.put("object", user.ap_id) {:ok, %Activity{local: false}} = Transmogrifier.handle_incoming(data) @@ -116,7 +116,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.FollowHandlingTest do data = File.read!("test/fixtures/mastodon-follow-activity.json") - |> Poison.decode!() + |> Jason.decode!() |> Map.put("id", String.replace(data["id"], "2", "3")) |> Map.put("object", user.ap_id) @@ -133,7 +133,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.FollowHandlingTest do end test "it rejects incoming follow requests from blocked users when deny_follow_blocked is enabled" do - Pleroma.Config.put([:user, :deny_follow_blocked], true) + clear_config([:user, :deny_follow_blocked], true) user = insert(:user) {:ok, target} = User.get_or_fetch("http://mastodon.example.org/users/admin") @@ -142,7 +142,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.FollowHandlingTest do data = File.read!("test/fixtures/mastodon-follow-activity.json") - |> Poison.decode!() + |> Jason.decode!() |> Map.put("object", user.ap_id) {:ok, %Activity{data: %{"id" => id}}} = Transmogrifier.handle_incoming(data) @@ -157,7 +157,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.FollowHandlingTest do data = File.read!("test/fixtures/mastodon-follow-activity.json") - |> Poison.decode!() + |> Jason.decode!() |> Map.put("object", user.ap_id) with_mock Pleroma.User, [:passthrough], follow: fn _, _, _ -> {:error, :testing} end do @@ -174,7 +174,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.FollowHandlingTest do data = File.read!("test/fixtures/hubzilla-follow-activity.json") - |> Poison.decode!() + |> Jason.decode!() |> Map.put("object", user.ap_id) |> Utils.normalize_params() @@ -188,11 +188,11 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.FollowHandlingTest do test "it works for incoming follows to locked account" do pending_follower = insert(:user, ap_id: "http://mastodon.example.org/users/admin") - user = insert(:user, locked: true) + user = insert(:user, is_locked: true) data = File.read!("test/fixtures/mastodon-follow-activity.json") - |> Poison.decode!() + |> Jason.decode!() |> Map.put("object", user.ap_id) {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) diff --git a/test/web/activity_pub/transmogrifier/like_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/like_handling_test.exs index 53fe1d550..57d74349a 100644 --- a/test/web/activity_pub/transmogrifier/like_handling_test.exs +++ b/test/pleroma/web/activity_pub/transmogrifier/like_handling_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.Transmogrifier.LikeHandlingTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true alias Pleroma.Activity alias Pleroma.Web.ActivityPub.Transmogrifier @@ -18,7 +18,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.LikeHandlingTest do data = File.read!("test/fixtures/mastodon-like.json") - |> Poison.decode!() + |> Jason.decode!() |> Map.put("object", activity.data["object"]) _actor = insert(:user, ap_id: data["actor"], local: false) @@ -40,7 +40,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.LikeHandlingTest do data = File.read!("test/fixtures/misskey-like.json") - |> Poison.decode!() + |> Jason.decode!() |> Map.put("object", activity.data["object"]) _actor = insert(:user, ap_id: data["actor"], local: false) @@ -61,7 +61,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.LikeHandlingTest do data = File.read!("test/fixtures/misskey-like.json") - |> Poison.decode!() + |> Jason.decode!() |> Map.put("object", activity.data["object"]) |> Map.put("_misskey_reaction", "⭐") diff --git a/test/pleroma/web/activity_pub/transmogrifier/note_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/note_handling_test.exs new file mode 100644 index 000000000..1846b2291 --- /dev/null +++ b/test/pleroma/web/activity_pub/transmogrifier/note_handling_test.exs @@ -0,0 +1,710 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ActivityPub.Transmogrifier.NoteHandlingTest do + use Oban.Testing, repo: Pleroma.Repo + use Pleroma.DataCase + + alias Pleroma.Activity + alias Pleroma.Object + alias Pleroma.User + alias Pleroma.Web.ActivityPub.Transmogrifier + alias Pleroma.Web.ActivityPub.Utils + alias Pleroma.Web.CommonAPI + + import Mock + import Pleroma.Factory + + setup_all do + Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) + :ok + end + + setup do: clear_config([:instance, :max_remote_account_fields]) + + describe "handle_incoming" do + test "it works for incoming notices with tag not being an array (kroeg)" do + data = File.read!("test/fixtures/kroeg-array-less-emoji.json") |> Jason.decode!() + + {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) + object = Object.normalize(data["object"], fetch: false) + + assert object.data["emoji"] == %{ + "icon_e_smile" => "https://puckipedia.com/forum/images/smilies/icon_e_smile.png" + } + + data = File.read!("test/fixtures/kroeg-array-less-hashtag.json") |> Jason.decode!() + + {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) + object = Object.normalize(data["object"], fetch: false) + + assert "test" in Object.tags(object) + assert Object.hashtags(object) == ["test"] + end + + test "it ignores an incoming notice if we already have it" do + activity = insert(:note_activity) + + data = + File.read!("test/fixtures/mastodon-post-activity.json") + |> Jason.decode!() + |> Map.put("object", Object.normalize(activity, fetch: false).data) + + {:ok, returned_activity} = Transmogrifier.handle_incoming(data) + + assert activity == returned_activity + end + + @tag capture_log: true + test "it fetches reply-to activities if we don't have them" do + data = + File.read!("test/fixtures/mastodon-post-activity.json") + |> Jason.decode!() + + object = + data["object"] + |> Map.put("inReplyTo", "https://mstdn.io/users/mayuutann/statuses/99568293732299394") + + data = Map.put(data, "object", object) + {:ok, returned_activity} = Transmogrifier.handle_incoming(data) + returned_object = Object.normalize(returned_activity, fetch: false) + + assert %Activity{} = + Activity.get_create_by_object_ap_id( + "https://mstdn.io/users/mayuutann/statuses/99568293732299394" + ) + + assert returned_object.data["inReplyTo"] == + "https://mstdn.io/users/mayuutann/statuses/99568293732299394" + end + + test "it does not fetch reply-to activities beyond max replies depth limit" do + data = + File.read!("test/fixtures/mastodon-post-activity.json") + |> Jason.decode!() + + object = + data["object"] + |> Map.put("inReplyTo", "https://shitposter.club/notice/2827873") + + data = Map.put(data, "object", object) + + with_mock Pleroma.Web.Federator, + allowed_thread_distance?: fn _ -> false end do + {:ok, returned_activity} = Transmogrifier.handle_incoming(data) + + returned_object = Object.normalize(returned_activity, fetch: false) + + refute Activity.get_create_by_object_ap_id( + "tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment" + ) + + assert returned_object.data["inReplyTo"] == "https://shitposter.club/notice/2827873" + end + end + + test "it does not crash if the object in inReplyTo can't be fetched" do + data = + File.read!("test/fixtures/mastodon-post-activity.json") + |> Jason.decode!() + + object = + data["object"] + |> Map.put("inReplyTo", "https://404.site/whatever") + + data = + data + |> Map.put("object", object) + + assert {:ok, _returned_activity} = Transmogrifier.handle_incoming(data) + end + + test "it does not work for deactivated users" do + data = File.read!("test/fixtures/mastodon-post-activity.json") |> Jason.decode!() + + insert(:user, ap_id: data["actor"], is_active: false) + + assert {:error, _} = Transmogrifier.handle_incoming(data) + end + + test "it works for incoming notices" do + data = File.read!("test/fixtures/mastodon-post-activity.json") |> Jason.decode!() + + {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) + + assert data["id"] == + "http://mastodon.example.org/users/admin/statuses/99512778738411822/activity" + + assert data["context"] == + "tag:mastodon.example.org,2018-02-12:objectId=20:objectType=Conversation" + + assert data["to"] == ["https://www.w3.org/ns/activitystreams#Public"] + + assert data["cc"] == [ + "http://localtesting.pleroma.lol/users/lain", + "http://mastodon.example.org/users/admin/followers" + ] + + assert data["actor"] == "http://mastodon.example.org/users/admin" + + object_data = Object.normalize(data["object"], fetch: false).data + + assert object_data["id"] == + "http://mastodon.example.org/users/admin/statuses/99512778738411822" + + assert object_data["to"] == ["https://www.w3.org/ns/activitystreams#Public"] + + assert object_data["cc"] == [ + "http://localtesting.pleroma.lol/users/lain", + "http://mastodon.example.org/users/admin/followers" + ] + + assert object_data["actor"] == "http://mastodon.example.org/users/admin" + assert object_data["attributedTo"] == "http://mastodon.example.org/users/admin" + + assert object_data["context"] == + "tag:mastodon.example.org,2018-02-12:objectId=20:objectType=Conversation" + + assert object_data["sensitive"] == true + + user = User.get_cached_by_ap_id(object_data["actor"]) + + assert user.note_count == 1 + end + + test "it works for incoming notices without the sensitive property but an nsfw hashtag" do + data = File.read!("test/fixtures/mastodon-post-activity-nsfw.json") |> Jason.decode!() + + {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) + + object_data = Object.normalize(data["object"], fetch: false).data + + assert object_data["sensitive"] == true + end + + test "it works for incoming notices with hashtags" do + data = File.read!("test/fixtures/mastodon-post-activity-hashtag.json") |> Jason.decode!() + + {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) + object = Object.normalize(data["object"], fetch: false) + + assert match?( + %{ + "href" => "http://localtesting.pleroma.lol/users/lain", + "name" => "@lain@localtesting.pleroma.lol", + "type" => "Mention" + }, + Enum.at(object.data["tag"], 0) + ) + + assert match?( + %{ + "href" => "http://mastodon.example.org/tags/moo", + "name" => "#moo", + "type" => "Hashtag" + }, + Enum.at(object.data["tag"], 1) + ) + + assert "moo" == Enum.at(object.data["tag"], 2) + end + + test "it works for incoming notices with contentMap" do + data = File.read!("test/fixtures/mastodon-post-activity-contentmap.json") |> Jason.decode!() + + {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) + object = Object.normalize(data["object"], fetch: false) + + assert object.data["content"] == + "<p><span class=\"h-card\"><a href=\"http://localtesting.pleroma.lol/users/lain\" class=\"u-url mention\">@<span>lain</span></a></span></p>" + end + + test "it works for incoming notices with to/cc not being an array (kroeg)" do + data = File.read!("test/fixtures/kroeg-post-activity.json") |> Jason.decode!() + + {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) + object = Object.normalize(data["object"], fetch: false) + + assert object.data["content"] == + "<p>henlo from my Psion netBook</p><p>message sent from my Psion netBook</p>" + end + + test "it ensures that as:Public activities make it to their followers collection" do + user = insert(:user) + + data = + File.read!("test/fixtures/mastodon-post-activity.json") + |> Jason.decode!() + |> Map.put("actor", user.ap_id) + |> Map.put("to", ["https://www.w3.org/ns/activitystreams#Public"]) + |> Map.put("cc", []) + + object = + data["object"] + |> Map.put("attributedTo", user.ap_id) + |> Map.put("to", ["https://www.w3.org/ns/activitystreams#Public"]) + |> Map.put("cc", []) + |> Map.put("id", user.ap_id <> "/activities/12345678") + + data = Map.put(data, "object", object) + + {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) + + assert data["cc"] == [User.ap_followers(user)] + end + + test "it ensures that address fields become lists" do + user = insert(:user) + + data = + File.read!("test/fixtures/mastodon-post-activity.json") + |> Jason.decode!() + |> Map.put("actor", user.ap_id) + |> Map.put("cc", nil) + + object = + data["object"] + |> Map.put("attributedTo", user.ap_id) + |> Map.put("cc", nil) + |> Map.put("id", user.ap_id <> "/activities/12345678") + + data = Map.put(data, "object", object) + + {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) + + refute is_nil(data["cc"]) + end + + test "it strips internal likes" do + data = + File.read!("test/fixtures/mastodon-post-activity.json") + |> Jason.decode!() + + likes = %{ + "first" => + "http://mastodon.example.org/objects/dbdbc507-52c8-490d-9b7c-1e1d52e5c132/likes?page=1", + "id" => "http://mastodon.example.org/objects/dbdbc507-52c8-490d-9b7c-1e1d52e5c132/likes", + "totalItems" => 3, + "type" => "OrderedCollection" + } + + object = Map.put(data["object"], "likes", likes) + data = Map.put(data, "object", object) + + {:ok, %Activity{} = activity} = Transmogrifier.handle_incoming(data) + + object = Object.normalize(activity) + + assert object.data["likes"] == [] + end + + test "it strips internal reactions" do + user = insert(:user) + {:ok, activity} = CommonAPI.post(user, %{status: "#cofe"}) + {:ok, _} = CommonAPI.react_with_emoji(activity.id, user, "📢") + + %{object: object} = Activity.get_by_id_with_object(activity.id) + assert Map.has_key?(object.data, "reactions") + assert Map.has_key?(object.data, "reaction_count") + + object_data = Transmogrifier.strip_internal_fields(object.data) + refute Map.has_key?(object_data, "reactions") + refute Map.has_key?(object_data, "reaction_count") + end + + test "it correctly processes messages with non-array to field" do + data = + File.read!("test/fixtures/mastodon-post-activity.json") + |> Poison.decode!() + |> Map.put("to", "https://www.w3.org/ns/activitystreams#Public") + |> put_in(["object", "to"], "https://www.w3.org/ns/activitystreams#Public") + + assert {:ok, activity} = Transmogrifier.handle_incoming(data) + + assert [ + "http://localtesting.pleroma.lol/users/lain", + "http://mastodon.example.org/users/admin/followers" + ] == activity.data["cc"] + + assert ["https://www.w3.org/ns/activitystreams#Public"] == activity.data["to"] + end + + test "it correctly processes messages with non-array cc field" do + data = + File.read!("test/fixtures/mastodon-post-activity.json") + |> Poison.decode!() + |> Map.put("cc", "http://mastodon.example.org/users/admin/followers") + |> put_in(["object", "cc"], "http://mastodon.example.org/users/admin/followers") + + assert {:ok, activity} = Transmogrifier.handle_incoming(data) + + assert ["http://mastodon.example.org/users/admin/followers"] == activity.data["cc"] + assert ["https://www.w3.org/ns/activitystreams#Public"] == activity.data["to"] + end + + test "it correctly processes messages with weirdness in address fields" do + data = + File.read!("test/fixtures/mastodon-post-activity.json") + |> Poison.decode!() + |> Map.put("cc", ["http://mastodon.example.org/users/admin/followers", ["¿"]]) + |> put_in(["object", "cc"], ["http://mastodon.example.org/users/admin/followers", ["¿"]]) + + assert {:ok, activity} = Transmogrifier.handle_incoming(data) + + assert ["http://mastodon.example.org/users/admin/followers"] == activity.data["cc"] + assert ["https://www.w3.org/ns/activitystreams#Public"] == activity.data["to"] + end + end + + describe "`handle_incoming/2`, Mastodon format `replies` handling" do + setup do: clear_config([:activitypub, :note_replies_output_limit], 5) + setup do: clear_config([:instance, :federation_incoming_replies_max_depth]) + + setup do + data = + "test/fixtures/mastodon-post-activity.json" + |> File.read!() + |> Jason.decode!() + + items = get_in(data, ["object", "replies", "first", "items"]) + assert length(items) > 0 + + %{data: data, items: items} + end + + test "schedules background fetching of `replies` items if max thread depth limit allows", %{ + data: data, + items: items + } do + clear_config([:instance, :federation_incoming_replies_max_depth], 10) + + {:ok, activity} = Transmogrifier.handle_incoming(data) + + object = Object.normalize(activity.data["object"]) + + assert object.data["replies"] == items + + for id <- items do + job_args = %{"op" => "fetch_remote", "id" => id, "depth" => 1} + assert_enqueued(worker: Pleroma.Workers.RemoteFetcherWorker, args: job_args) + end + end + + test "does NOT schedule background fetching of `replies` beyond max thread depth limit allows", + %{data: data} do + clear_config([:instance, :federation_incoming_replies_max_depth], 0) + + {:ok, _activity} = Transmogrifier.handle_incoming(data) + + assert all_enqueued(worker: Pleroma.Workers.RemoteFetcherWorker) == [] + end + end + + describe "`handle_incoming/2`, Pleroma format `replies` handling" do + setup do: clear_config([:activitypub, :note_replies_output_limit], 5) + setup do: clear_config([:instance, :federation_incoming_replies_max_depth]) + + setup do + replies = %{ + "type" => "Collection", + "items" => [Utils.generate_object_id(), Utils.generate_object_id()] + } + + activity = + File.read!("test/fixtures/mastodon-post-activity.json") + |> Poison.decode!() + |> Kernel.put_in(["object", "replies"], replies) + + %{activity: activity} + end + + test "schedules background fetching of `replies` items if max thread depth limit allows", %{ + activity: activity + } do + clear_config([:instance, :federation_incoming_replies_max_depth], 1) + + assert {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(activity) + object = Object.normalize(data["object"]) + + for id <- object.data["replies"] do + job_args = %{"op" => "fetch_remote", "id" => id, "depth" => 1} + assert_enqueued(worker: Pleroma.Workers.RemoteFetcherWorker, args: job_args) + end + end + + test "does NOT schedule background fetching of `replies` beyond max thread depth limit allows", + %{activity: activity} do + clear_config([:instance, :federation_incoming_replies_max_depth], 0) + + {:ok, _activity} = Transmogrifier.handle_incoming(activity) + + assert all_enqueued(worker: Pleroma.Workers.RemoteFetcherWorker) == [] + end + end + + describe "reserialization" do + test "successfully reserializes a message with inReplyTo == nil" do + user = insert(:user) + + message = %{ + "@context" => "https://www.w3.org/ns/activitystreams", + "to" => ["https://www.w3.org/ns/activitystreams#Public"], + "cc" => [], + "type" => "Create", + "object" => %{ + "to" => ["https://www.w3.org/ns/activitystreams#Public"], + "cc" => [], + "id" => Utils.generate_object_id(), + "type" => "Note", + "content" => "Hi", + "inReplyTo" => nil, + "attributedTo" => user.ap_id + }, + "actor" => user.ap_id + } + + {:ok, activity} = Transmogrifier.handle_incoming(message) + + {:ok, _} = Transmogrifier.prepare_outgoing(activity.data) + end + + test "successfully reserializes a message with AS2 objects in IR" do + user = insert(:user) + + message = %{ + "@context" => "https://www.w3.org/ns/activitystreams", + "to" => ["https://www.w3.org/ns/activitystreams#Public"], + "cc" => [], + "type" => "Create", + "object" => %{ + "to" => ["https://www.w3.org/ns/activitystreams#Public"], + "cc" => [], + "id" => Utils.generate_object_id(), + "type" => "Note", + "content" => "Hi", + "inReplyTo" => nil, + "attributedTo" => user.ap_id, + "tag" => [ + %{"name" => "#2hu", "href" => "http://example.com/2hu", "type" => "Hashtag"}, + %{"name" => "Bob", "href" => "http://example.com/bob", "type" => "Mention"} + ] + }, + "actor" => user.ap_id + } + + {:ok, activity} = Transmogrifier.handle_incoming(message) + + {:ok, _} = Transmogrifier.prepare_outgoing(activity.data) + end + end + + describe "fix_in_reply_to/2" do + setup do: clear_config([:instance, :federation_incoming_replies_max_depth]) + + setup do + data = Jason.decode!(File.read!("test/fixtures/mastodon-post-activity.json")) + [data: data] + end + + test "returns not modified object when hasn't containts inReplyTo field", %{data: data} do + assert Transmogrifier.fix_in_reply_to(data) == data + end + + test "returns object with inReplyTo when denied incoming reply", %{data: data} do + clear_config([:instance, :federation_incoming_replies_max_depth], 0) + + object_with_reply = + Map.put(data["object"], "inReplyTo", "https://shitposter.club/notice/2827873") + + modified_object = Transmogrifier.fix_in_reply_to(object_with_reply) + assert modified_object["inReplyTo"] == "https://shitposter.club/notice/2827873" + + object_with_reply = + Map.put(data["object"], "inReplyTo", %{"id" => "https://shitposter.club/notice/2827873"}) + + modified_object = Transmogrifier.fix_in_reply_to(object_with_reply) + assert modified_object["inReplyTo"] == %{"id" => "https://shitposter.club/notice/2827873"} + + object_with_reply = + Map.put(data["object"], "inReplyTo", ["https://shitposter.club/notice/2827873"]) + + modified_object = Transmogrifier.fix_in_reply_to(object_with_reply) + assert modified_object["inReplyTo"] == ["https://shitposter.club/notice/2827873"] + + object_with_reply = Map.put(data["object"], "inReplyTo", []) + modified_object = Transmogrifier.fix_in_reply_to(object_with_reply) + assert modified_object["inReplyTo"] == [] + end + + @tag capture_log: true + test "returns modified object when allowed incoming reply", %{data: data} do + object_with_reply = + Map.put( + data["object"], + "inReplyTo", + "https://mstdn.io/users/mayuutann/statuses/99568293732299394" + ) + + clear_config([:instance, :federation_incoming_replies_max_depth], 5) + modified_object = Transmogrifier.fix_in_reply_to(object_with_reply) + + assert modified_object["inReplyTo"] == + "https://mstdn.io/users/mayuutann/statuses/99568293732299394" + + assert modified_object["context"] == + "tag:shitposter.club,2018-02-22:objectType=thread:nonce=e5a7c72d60a9c0e4" + end + end + + describe "fix_attachments/1" do + test "returns not modified object" do + data = Jason.decode!(File.read!("test/fixtures/mastodon-post-activity.json")) + assert Transmogrifier.fix_attachments(data) == data + end + + test "returns modified object when attachment is map" do + assert Transmogrifier.fix_attachments(%{ + "attachment" => %{ + "mediaType" => "video/mp4", + "url" => "https://peertube.moe/stat-480.mp4" + } + }) == %{ + "attachment" => [ + %{ + "mediaType" => "video/mp4", + "type" => "Document", + "url" => [ + %{ + "href" => "https://peertube.moe/stat-480.mp4", + "mediaType" => "video/mp4", + "type" => "Link" + } + ] + } + ] + } + end + + test "returns modified object when attachment is list" do + assert Transmogrifier.fix_attachments(%{ + "attachment" => [ + %{"mediaType" => "video/mp4", "url" => "https://pe.er/stat-480.mp4"}, + %{"mimeType" => "video/mp4", "href" => "https://pe.er/stat-480.mp4"} + ] + }) == %{ + "attachment" => [ + %{ + "mediaType" => "video/mp4", + "type" => "Document", + "url" => [ + %{ + "href" => "https://pe.er/stat-480.mp4", + "mediaType" => "video/mp4", + "type" => "Link" + } + ] + }, + %{ + "mediaType" => "video/mp4", + "type" => "Document", + "url" => [ + %{ + "href" => "https://pe.er/stat-480.mp4", + "mediaType" => "video/mp4", + "type" => "Link" + } + ] + } + ] + } + end + end + + describe "fix_emoji/1" do + test "returns not modified object when object not contains tags" do + data = Jason.decode!(File.read!("test/fixtures/mastodon-post-activity.json")) + assert Transmogrifier.fix_emoji(data) == data + end + + test "returns object with emoji when object contains list tags" do + assert Transmogrifier.fix_emoji(%{ + "tag" => [ + %{"type" => "Emoji", "name" => ":bib:", "icon" => %{"url" => "/test"}}, + %{"type" => "Hashtag"} + ] + }) == %{ + "emoji" => %{"bib" => "/test"}, + "tag" => [ + %{"icon" => %{"url" => "/test"}, "name" => ":bib:", "type" => "Emoji"}, + %{"type" => "Hashtag"} + ] + } + end + + test "returns object with emoji when object contains map tag" do + assert Transmogrifier.fix_emoji(%{ + "tag" => %{"type" => "Emoji", "name" => ":bib:", "icon" => %{"url" => "/test"}} + }) == %{ + "emoji" => %{"bib" => "/test"}, + "tag" => %{"icon" => %{"url" => "/test"}, "name" => ":bib:", "type" => "Emoji"} + } + end + end + + describe "set_replies/1" do + setup do: clear_config([:activitypub, :note_replies_output_limit], 2) + + test "returns unmodified object if activity doesn't have self-replies" do + data = Jason.decode!(File.read!("test/fixtures/mastodon-post-activity.json")) + assert Transmogrifier.set_replies(data) == data + end + + test "sets `replies` collection with a limited number of self-replies" do + [user, another_user] = insert_list(2, :user) + + {:ok, %{id: id1} = activity} = CommonAPI.post(user, %{status: "1"}) + + {:ok, %{id: id2} = self_reply1} = + CommonAPI.post(user, %{status: "self-reply 1", in_reply_to_status_id: id1}) + + {:ok, self_reply2} = + CommonAPI.post(user, %{status: "self-reply 2", in_reply_to_status_id: id1}) + + # Assuming to _not_ be present in `replies` due to :note_replies_output_limit is set to 2 + {:ok, _} = CommonAPI.post(user, %{status: "self-reply 3", in_reply_to_status_id: id1}) + + {:ok, _} = + CommonAPI.post(user, %{ + status: "self-reply to self-reply", + in_reply_to_status_id: id2 + }) + + {:ok, _} = + CommonAPI.post(another_user, %{ + status: "another user's reply", + in_reply_to_status_id: id1 + }) + + object = Object.normalize(activity, fetch: false) + replies_uris = Enum.map([self_reply1, self_reply2], fn a -> a.object.data["id"] end) + + assert %{"type" => "Collection", "items" => ^replies_uris} = + Transmogrifier.set_replies(object.data)["replies"] + end + end + + test "take_emoji_tags/1" do + user = insert(:user, %{emoji: %{"firefox" => "https://example.org/firefox.png"}}) + + assert Transmogrifier.take_emoji_tags(user) == [ + %{ + "icon" => %{"type" => "Image", "url" => "https://example.org/firefox.png"}, + "id" => "https://example.org/firefox.png", + "name" => ":firefox:", + "type" => "Emoji", + "updated" => "1970-01-01T00:00:00Z" + } + ] + end +end diff --git a/test/pleroma/web/activity_pub/transmogrifier/page_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/page_handling_test.exs new file mode 100644 index 000000000..4ac71e066 --- /dev/null +++ b/test/pleroma/web/activity_pub/transmogrifier/page_handling_test.exs @@ -0,0 +1,36 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ActivityPub.Transmogrifier.PageHandlingTest do + use Oban.Testing, repo: Pleroma.Repo + use Pleroma.DataCase + + alias Pleroma.Object.Fetcher + + test "Lemmy Page" do + Tesla.Mock.mock(fn + %{url: "https://enterprise.lemmy.ml/post/3"} -> + %Tesla.Env{ + status: 200, + headers: [{"content-type", "application/activity+json"}], + body: File.read!("test/fixtures/tesla_mock/lemmy-page.json") + } + + %{url: "https://enterprise.lemmy.ml/u/nutomic"} -> + %Tesla.Env{ + status: 200, + headers: [{"content-type", "application/activity+json"}], + body: File.read!("test/fixtures/tesla_mock/lemmy-user.json") + } + end) + + {:ok, object} = Fetcher.fetch_object_from_id("https://enterprise.lemmy.ml/post/3") + + assert object.data["summary"] == "Hello Federation!" + assert object.data["published"] == "2020-09-14T15:03:11.909105Z" + + # WAT + assert object.data["url"] == "https://enterprise.lemmy.ml/pictrs/image/US52d9DPvf.jpg" + end +end diff --git a/test/web/activity_pub/transmogrifier/question_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/question_handling_test.exs index 74ee79543..32cf51e59 100644 --- a/test/web/activity_pub/transmogrifier/question_handling_test.exs +++ b/test/pleroma/web/activity_pub/transmogrifier/question_handling_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.Transmogrifier.QuestionHandlingTest do @@ -18,11 +18,11 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.QuestionHandlingTest do end test "Mastodon Question activity" do - data = File.read!("test/fixtures/mastodon-question-activity.json") |> Poison.decode!() + data = File.read!("test/fixtures/mastodon-question-activity.json") |> Jason.decode!() {:ok, %Activity{local: false} = activity} = Transmogrifier.handle_incoming(data) - object = Object.normalize(activity, false) + object = Object.normalize(activity, fetch: false) assert object.data["url"] == "https://mastodon.sdf.org/@rinpatch/102070944809637304" @@ -65,7 +65,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.QuestionHandlingTest do {:ok, reply_activity} = CommonAPI.post(user, %{status: "hewwo", in_reply_to_id: activity.id}) - reply_object = Object.normalize(reply_activity, false) + reply_object = Object.normalize(reply_activity, fetch: false) assert reply_object.data["context"] == object.data["context"] assert reply_object.data["context_id"] == object.data["context_id"] @@ -97,11 +97,11 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.QuestionHandlingTest do data = File.read!("test/fixtures/mastodon-question-activity.json") - |> Poison.decode!() + |> Jason.decode!() |> Kernel.put_in(["object", "oneOf"], options) {:ok, %Activity{local: false} = activity} = Transmogrifier.handle_incoming(data) - object = Object.normalize(activity, false) + object = Object.normalize(activity, fetch: false) assert Enum.sort(object.data["oneOf"]) == Enum.sort(options) end @@ -142,12 +142,12 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.QuestionHandlingTest do data = File.read!("test/fixtures/mastodon-question-activity.json") - |> Poison.decode!() + |> Jason.decode!() |> Kernel.put_in(["object", "oneOf"], options) |> Kernel.put_in(["object", "tag"], tag) {:ok, %Activity{local: false} = activity} = Transmogrifier.handle_incoming(data) - object = Object.normalize(activity, false) + object = Object.normalize(activity, fetch: false) assert object.data["oneOf"] == options @@ -157,18 +157,18 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.QuestionHandlingTest do } end - test "returns an error if received a second time" do - data = File.read!("test/fixtures/mastodon-question-activity.json") |> Poison.decode!() + test "returns same activity if received a second time" do + data = File.read!("test/fixtures/mastodon-question-activity.json") |> Jason.decode!() assert {:ok, %Activity{local: false} = activity} = Transmogrifier.handle_incoming(data) - assert {:error, {:validate_object, {:error, _}}} = Transmogrifier.handle_incoming(data) + assert {:ok, ^activity} = Transmogrifier.handle_incoming(data) end test "accepts a Question with no content" do data = File.read!("test/fixtures/mastodon-question-activity.json") - |> Poison.decode!() + |> Jason.decode!() |> Kernel.put_in(["object", "content"], "") assert {:ok, %Activity{local: false}} = Transmogrifier.handle_incoming(data) diff --git a/test/web/activity_pub/transmogrifier/reject_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/reject_handling_test.exs index 7592fbe1c..355e664d4 100644 --- a/test/web/activity_pub/transmogrifier/reject_handling_test.exs +++ b/test/pleroma/web/activity_pub/transmogrifier/reject_handling_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.Transmogrifier.RejectHandlingTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true alias Pleroma.Activity alias Pleroma.User @@ -14,11 +14,11 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.RejectHandlingTest do test "it fails for incoming rejects which cannot be correlated" do follower = insert(:user) - followed = insert(:user, locked: true) + followed = insert(:user, is_locked: true) accept_data = File.read!("test/fixtures/mastodon-reject-activity.json") - |> Poison.decode!() + |> Jason.decode!() |> Map.put("actor", followed.ap_id) accept_data = @@ -33,16 +33,16 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.RejectHandlingTest do test "it works for incoming rejects which are referenced by IRI only" do follower = insert(:user) - followed = insert(:user, locked: true) + followed = insert(:user, is_locked: true) - {:ok, follower} = User.follow(follower, followed) + {:ok, follower, followed} = User.follow(follower, followed) {:ok, _, _, follow_activity} = CommonAPI.follow(follower, followed) assert User.following?(follower, followed) == true reject_data = File.read!("test/fixtures/mastodon-reject-activity.json") - |> Poison.decode!() + |> Jason.decode!() |> Map.put("actor", followed.ap_id) |> Map.put("object", follow_activity.data["id"]) @@ -58,7 +58,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.RejectHandlingTest do data = File.read!("test/fixtures/mastodon-follow-activity.json") - |> Poison.decode!() + |> Jason.decode!() |> Map.put("object", user.ap_id) |> Map.put("id", "") diff --git a/test/web/activity_pub/transmogrifier/undo_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/undo_handling_test.exs index 8683f7135..f6e40722c 100644 --- a/test/web/activity_pub/transmogrifier/undo_handling_test.exs +++ b/test/pleroma/web/activity_pub/transmogrifier/undo_handling_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.Transmogrifier.UndoHandlingTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true alias Pleroma.Activity alias Pleroma.Object @@ -21,7 +21,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.UndoHandlingTest do data = File.read!("test/fixtures/mastodon-undo-like.json") - |> Poison.decode!() + |> Jason.decode!() |> Map.put("object", reaction_activity.data["id"]) |> Map.put("actor", user.ap_id) @@ -38,7 +38,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.UndoHandlingTest do data = File.read!("test/fixtures/mastodon-undo-like.json") - |> Poison.decode!() + |> Jason.decode!() |> Map.put("object", activity.data["object"]) assert Transmogrifier.handle_incoming(data) == :error @@ -50,7 +50,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.UndoHandlingTest do like_data = File.read!("test/fixtures/mastodon-like.json") - |> Poison.decode!() + |> Jason.decode!() |> Map.put("object", activity.data["object"]) _liker = insert(:user, ap_id: like_data["actor"], local: false) @@ -59,7 +59,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.UndoHandlingTest do data = File.read!("test/fixtures/mastodon-undo-like.json") - |> Poison.decode!() + |> Jason.decode!() |> Map.put("object", like_data) |> Map.put("actor", like_data["actor"]) @@ -81,7 +81,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.UndoHandlingTest do like_data = File.read!("test/fixtures/mastodon-like.json") - |> Poison.decode!() + |> Jason.decode!() |> Map.put("object", activity.data["object"]) _liker = insert(:user, ap_id: like_data["actor"], local: false) @@ -90,7 +90,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.UndoHandlingTest do data = File.read!("test/fixtures/mastodon-undo-like.json") - |> Poison.decode!() + |> Jason.decode!() |> Map.put("object", like_data["id"]) |> Map.put("actor", like_data["actor"]) @@ -108,7 +108,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.UndoHandlingTest do announce_data = File.read!("test/fixtures/mastodon-announce.json") - |> Poison.decode!() + |> Jason.decode!() |> Map.put("object", activity.data["object"]) _announcer = insert(:user, ap_id: announce_data["actor"], local: false) @@ -118,7 +118,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.UndoHandlingTest do data = File.read!("test/fixtures/mastodon-undo-announce.json") - |> Poison.decode!() + |> Jason.decode!() |> Map.put("object", announce_data) |> Map.put("actor", announce_data["actor"]) @@ -135,7 +135,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.UndoHandlingTest do follow_data = File.read!("test/fixtures/mastodon-follow-activity.json") - |> Poison.decode!() + |> Jason.decode!() |> Map.put("object", user.ap_id) _follower = insert(:user, ap_id: follow_data["actor"], local: false) @@ -144,7 +144,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.UndoHandlingTest do data = File.read!("test/fixtures/mastodon-unfollow-activity.json") - |> Poison.decode!() + |> Jason.decode!() |> Map.put("object", follow_data) {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) @@ -162,7 +162,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.UndoHandlingTest do block_data = File.read!("test/fixtures/mastodon-block-activity.json") - |> Poison.decode!() + |> Jason.decode!() |> Map.put("object", user.ap_id) _blocker = insert(:user, ap_id: block_data["actor"], local: false) @@ -171,7 +171,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.UndoHandlingTest do data = File.read!("test/fixtures/mastodon-unblock-activity.json") - |> Poison.decode!() + |> Jason.decode!() |> Map.put("object", block_data) {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) diff --git a/test/web/activity_pub/transmogrifier/user_update_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/user_update_handling_test.exs index 64636656c..b1a064772 100644 --- a/test/web/activity_pub/transmogrifier/user_update_handling_test.exs +++ b/test/pleroma/web/activity_pub/transmogrifier/user_update_handling_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.Transmogrifier.UserUpdateHandlingTest do @@ -14,7 +14,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.UserUpdateHandlingTest do test "it works for incoming update activities" do user = insert(:user, local: false) - update_data = File.read!("test/fixtures/mastodon-update.json") |> Poison.decode!() + update_data = File.read!("test/fixtures/mastodon-update.json") |> Jason.decode!() object = update_data["object"] @@ -58,7 +58,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.UserUpdateHandlingTest do {:ok, _activity} = "test/fixtures/mastodon-update.json" |> File.read!() - |> Poison.decode!() + |> Jason.decode!() |> Map.put("actor", actor) |> Map.update!("object", fn object -> object @@ -82,7 +82,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.UserUpdateHandlingTest do assert user.fields == [] - update_data = File.read!("test/fixtures/mastodon-update.json") |> Poison.decode!() + update_data = File.read!("test/fixtures/mastodon-update.json") |> Jason.decode!() object = update_data["object"] @@ -103,7 +103,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.UserUpdateHandlingTest do %{"name" => "foo1", "value" => "updated"} ] - Pleroma.Config.put([:instance, :max_remote_account_fields], 2) + clear_config([:instance, :max_remote_account_fields], 2) update_data = update_data @@ -138,7 +138,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.UserUpdateHandlingTest do test "it works for incoming update activities which lock the account" do user = insert(:user, local: false) - update_data = File.read!("test/fixtures/mastodon-update.json") |> Poison.decode!() + update_data = File.read!("test/fixtures/mastodon-update.json") |> Jason.decode!() object = update_data["object"] @@ -154,6 +154,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.UserUpdateHandlingTest do {:ok, %Activity{local: false}} = Transmogrifier.handle_incoming(update_data) user = User.get_cached_by_ap_id(user.ap_id) - assert user.locked == true + assert user.is_locked == true end end diff --git a/test/pleroma/web/activity_pub/transmogrifier/video_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/video_handling_test.exs new file mode 100644 index 000000000..87c53ebf4 --- /dev/null +++ b/test/pleroma/web/activity_pub/transmogrifier/video_handling_test.exs @@ -0,0 +1,122 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ActivityPub.Transmogrifier.VideoHandlingTest do + use Oban.Testing, repo: Pleroma.Repo + use Pleroma.DataCase + + alias Pleroma.Activity + alias Pleroma.Object + alias Pleroma.Object.Fetcher + alias Pleroma.Web.ActivityPub.Transmogrifier + + setup_all do + Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) + :ok + end + + test "skip converting the content when it is nil" do + data = + File.read!("test/fixtures/tesla_mock/framatube.org-video.json") + |> Jason.decode!() + |> Kernel.put_in(["object", "content"], nil) + + {:ok, %Activity{local: false} = activity} = Transmogrifier.handle_incoming(data) + + assert object = Object.normalize(activity, fetch: false) + + assert object.data["content"] == nil + end + + test "it converts content of object to html" do + data = File.read!("test/fixtures/tesla_mock/framatube.org-video.json") |> Jason.decode!() + + {:ok, %Activity{local: false} = activity} = Transmogrifier.handle_incoming(data) + + assert object = Object.normalize(activity, fetch: false) + + assert object.data["content"] == + "<p>Après avoir mené avec un certain succès la campagne « Dégooglisons Internet » en 2014, l’association Framasoft annonce fin 2019 arrêter progressivement un certain nombre de ses services alternatifs aux GAFAM. Pourquoi ?</p><p>Transcription par @aprilorg ici : <a href=\"https://www.april.org/deframasoftisons-internet-pierre-yves-gosset-framasoft\">https://www.april.org/deframasoftisons-internet-pierre-yves-gosset-framasoft</a></p>" + end + + test "it remaps video URLs as attachments if necessary" do + {:ok, object} = + Fetcher.fetch_object_from_id( + "https://peertube.moe/videos/watch/df5f464b-be8d-46fb-ad81-2d4c2d1630e3" + ) + + assert object.data["url"] == + "https://peertube.moe/videos/watch/df5f464b-be8d-46fb-ad81-2d4c2d1630e3" + + assert object.data["attachment"] == [ + %{ + "type" => "Link", + "mediaType" => "video/mp4", + "url" => [ + %{ + "href" => + "https://peertube.moe/static/webseed/df5f464b-be8d-46fb-ad81-2d4c2d1630e3-480.mp4", + "mediaType" => "video/mp4", + "type" => "Link", + "width" => 480 + } + ] + } + ] + + data = File.read!("test/fixtures/tesla_mock/framatube.org-video.json") |> Jason.decode!() + + {:ok, %Activity{local: false} = activity} = Transmogrifier.handle_incoming(data) + + assert object = Object.normalize(activity, fetch: false) + + assert object.data["attachment"] == [ + %{ + "type" => "Link", + "mediaType" => "video/mp4", + "url" => [ + %{ + "href" => + "https://framatube.org/static/webseed/6050732a-8a7a-43d4-a6cd-809525a1d206-1080.mp4", + "mediaType" => "video/mp4", + "type" => "Link", + "height" => 1080 + } + ] + } + ] + + assert object.data["url"] == + "https://framatube.org/videos/watch/6050732a-8a7a-43d4-a6cd-809525a1d206" + end + + test "it works for peertube videos with only their mpegURL map" do + data = + File.read!("test/fixtures/peertube/video-object-mpegURL-only.json") + |> Jason.decode!() + + {:ok, %Activity{local: false} = activity} = Transmogrifier.handle_incoming(data) + + assert object = Object.normalize(activity, fetch: false) + + assert object.data["attachment"] == [ + %{ + "type" => "Link", + "mediaType" => "video/mp4", + "url" => [ + %{ + "href" => + "https://peertube.stream/static/streaming-playlists/hls/abece3c3-b9c6-47f4-8040-f3eed8c602e6/abece3c3-b9c6-47f4-8040-f3eed8c602e6-1080-fragmented.mp4", + "mediaType" => "video/mp4", + "type" => "Link", + "height" => 1080 + } + ] + } + ] + + assert object.data["url"] == + "https://peertube.stream/videos/watch/abece3c3-b9c6-47f4-8040-f3eed8c602e6" + end +end diff --git a/test/pleroma/web/activity_pub/transmogrifier_test.exs b/test/pleroma/web/activity_pub/transmogrifier_test.exs new file mode 100644 index 000000000..06daf6a9f --- /dev/null +++ b/test/pleroma/web/activity_pub/transmogrifier_test.exs @@ -0,0 +1,567 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do + use Oban.Testing, repo: Pleroma.Repo + use Pleroma.DataCase + + alias Pleroma.Activity + alias Pleroma.Object + alias Pleroma.Tests.ObanHelpers + alias Pleroma.User + alias Pleroma.Web.ActivityPub.Transmogrifier + alias Pleroma.Web.ActivityPub.Utils + alias Pleroma.Web.AdminAPI.AccountView + alias Pleroma.Web.CommonAPI + + import Mock + import Pleroma.Factory + import ExUnit.CaptureLog + + setup_all do + Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) + :ok + end + + setup do: clear_config([:instance, :max_remote_account_fields]) + + describe "handle_incoming" do + test "it works for incoming unfollows with an existing follow" do + user = insert(:user) + + follow_data = + File.read!("test/fixtures/mastodon-follow-activity.json") + |> Jason.decode!() + |> Map.put("object", user.ap_id) + + {:ok, %Activity{data: _, local: false}} = Transmogrifier.handle_incoming(follow_data) + + data = + File.read!("test/fixtures/mastodon-unfollow-activity.json") + |> Jason.decode!() + |> Map.put("object", follow_data) + + {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) + + assert data["type"] == "Undo" + assert data["object"]["type"] == "Follow" + assert data["object"]["object"] == user.ap_id + assert data["actor"] == "http://mastodon.example.org/users/admin" + + refute User.following?(User.get_cached_by_ap_id(data["actor"]), user) + end + + test "it accepts Flag activities" do + user = insert(:user) + other_user = insert(:user) + + {:ok, activity} = CommonAPI.post(user, %{status: "test post"}) + object = Object.normalize(activity, fetch: false) + + note_obj = %{ + "type" => "Note", + "id" => activity.data["id"], + "content" => "test post", + "published" => object.data["published"], + "actor" => AccountView.render("show.json", %{user: user, skip_visibility_check: true}) + } + + message = %{ + "@context" => "https://www.w3.org/ns/activitystreams", + "cc" => [user.ap_id], + "object" => [user.ap_id, activity.data["id"]], + "type" => "Flag", + "content" => "blocked AND reported!!!", + "actor" => other_user.ap_id + } + + assert {:ok, activity} = Transmogrifier.handle_incoming(message) + + assert activity.data["object"] == [user.ap_id, note_obj] + assert activity.data["content"] == "blocked AND reported!!!" + assert activity.data["actor"] == other_user.ap_id + assert activity.data["cc"] == [user.ap_id] + end + + test "it accepts Move activities" do + old_user = insert(:user) + new_user = insert(:user) + + message = %{ + "@context" => "https://www.w3.org/ns/activitystreams", + "type" => "Move", + "actor" => old_user.ap_id, + "object" => old_user.ap_id, + "target" => new_user.ap_id + } + + assert :error = Transmogrifier.handle_incoming(message) + + {:ok, _new_user} = User.update_and_set_cache(new_user, %{also_known_as: [old_user.ap_id]}) + + assert {:ok, %Activity{} = activity} = Transmogrifier.handle_incoming(message) + assert activity.actor == old_user.ap_id + assert activity.data["actor"] == old_user.ap_id + assert activity.data["object"] == old_user.ap_id + assert activity.data["target"] == new_user.ap_id + assert activity.data["type"] == "Move" + end + end + + describe "prepare outgoing" do + test "it inlines private announced objects" do + user = insert(:user) + + {:ok, activity} = CommonAPI.post(user, %{status: "hey", visibility: "private"}) + + {:ok, announce_activity} = CommonAPI.repeat(activity.id, user) + + {:ok, modified} = Transmogrifier.prepare_outgoing(announce_activity.data) + + assert modified["object"]["content"] == "hey" + assert modified["object"]["actor"] == modified["object"]["attributedTo"] + end + + test "it turns mentions into tags" do + user = insert(:user) + other_user = insert(:user) + + {:ok, activity} = + CommonAPI.post(user, %{status: "hey, @#{other_user.nickname}, how are ya? #2hu"}) + + with_mock Pleroma.Notification, + get_notified_from_activity: fn _, _ -> [] end do + {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) + + object = modified["object"] + + expected_mention = %{ + "href" => other_user.ap_id, + "name" => "@#{other_user.nickname}", + "type" => "Mention" + } + + expected_tag = %{ + "href" => Pleroma.Web.Endpoint.url() <> "/tags/2hu", + "type" => "Hashtag", + "name" => "#2hu" + } + + refute called(Pleroma.Notification.get_notified_from_activity(:_, :_)) + assert Enum.member?(object["tag"], expected_tag) + assert Enum.member?(object["tag"], expected_mention) + end + end + + test "it adds the json-ld context and the conversation property" do + user = insert(:user) + + {:ok, activity} = CommonAPI.post(user, %{status: "hey"}) + {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) + + assert modified["@context"] == Utils.make_json_ld_header()["@context"] + + assert modified["object"]["conversation"] == modified["context"] + end + + test "it sets the 'attributedTo' property to the actor of the object if it doesn't have one" do + user = insert(:user) + + {:ok, activity} = CommonAPI.post(user, %{status: "hey"}) + {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) + + assert modified["object"]["actor"] == modified["object"]["attributedTo"] + end + + test "it strips internal hashtag data" do + user = insert(:user) + + {:ok, activity} = CommonAPI.post(user, %{status: "#2hu"}) + + expected_tag = %{ + "href" => Pleroma.Web.Endpoint.url() <> "/tags/2hu", + "type" => "Hashtag", + "name" => "#2hu" + } + + {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) + + assert modified["object"]["tag"] == [expected_tag] + end + + test "it strips internal fields" do + user = insert(:user) + + {:ok, activity} = + CommonAPI.post(user, %{ + status: "#2hu :firefox:", + generator: %{type: "Application", name: "TestClient", url: "https://pleroma.social"} + }) + + # Ensure injected application data made it into the activity + # as we don't have a Token to derive it from, otherwise it will + # be nil and the test will pass + assert %{ + type: "Application", + name: "TestClient", + url: "https://pleroma.social" + } == activity.object.data["generator"] + + {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) + + assert length(modified["object"]["tag"]) == 2 + + assert is_nil(modified["object"]["emoji"]) + assert is_nil(modified["object"]["like_count"]) + assert is_nil(modified["object"]["announcements"]) + assert is_nil(modified["object"]["announcement_count"]) + assert is_nil(modified["object"]["context_id"]) + assert is_nil(modified["object"]["generator"]) + end + + test "it strips internal fields of article" do + activity = insert(:article_activity) + + {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) + + assert length(modified["object"]["tag"]) == 2 + + assert is_nil(modified["object"]["emoji"]) + assert is_nil(modified["object"]["like_count"]) + assert is_nil(modified["object"]["announcements"]) + assert is_nil(modified["object"]["announcement_count"]) + assert is_nil(modified["object"]["context_id"]) + assert is_nil(modified["object"]["likes"]) + end + + test "the directMessage flag is present" do + user = insert(:user) + other_user = insert(:user) + + {:ok, activity} = CommonAPI.post(user, %{status: "2hu :moominmamma:"}) + + {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) + + assert modified["directMessage"] == false + + {:ok, activity} = CommonAPI.post(user, %{status: "@#{other_user.nickname} :moominmamma:"}) + + {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) + + assert modified["directMessage"] == false + + {:ok, activity} = + CommonAPI.post(user, %{ + status: "@#{other_user.nickname} :moominmamma:", + visibility: "direct" + }) + + {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) + + assert modified["directMessage"] == true + end + + test "it strips BCC field" do + user = insert(:user) + {:ok, list} = Pleroma.List.create("foo", user) + + {:ok, activity} = CommonAPI.post(user, %{status: "foobar", visibility: "list:#{list.id}"}) + + {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) + + assert is_nil(modified["bcc"]) + end + + test "it can handle Listen activities" do + listen_activity = insert(:listen) + + {:ok, modified} = Transmogrifier.prepare_outgoing(listen_activity.data) + + assert modified["type"] == "Listen" + + user = insert(:user) + + {:ok, activity} = CommonAPI.listen(user, %{"title" => "lain radio episode 1"}) + + {:ok, _modified} = Transmogrifier.prepare_outgoing(activity.data) + end + + test "custom emoji urls are URI encoded" do + # :dinosaur: filename has a space -> dino walking.gif + user = insert(:user) + + {:ok, activity} = CommonAPI.post(user, %{status: "everybody do the dinosaur :dinosaur:"}) + + {:ok, prepared} = Transmogrifier.prepare_outgoing(activity.data) + + assert length(prepared["object"]["tag"]) == 1 + + url = prepared["object"]["tag"] |> List.first() |> Map.get("icon") |> Map.get("url") + + assert url == "http://localhost:4001/emoji/dino%20walking.gif" + end + end + + describe "user upgrade" do + test "it upgrades a user to activitypub" do + user = + insert(:user, %{ + nickname: "rye@niu.moe", + local: false, + ap_id: "https://niu.moe/users/rye", + follower_address: User.ap_followers(%User{nickname: "rye@niu.moe"}) + }) + + user_two = insert(:user) + Pleroma.FollowingRelationship.follow(user_two, user, :follow_accept) + + {:ok, activity} = CommonAPI.post(user, %{status: "test"}) + {:ok, unrelated_activity} = CommonAPI.post(user_two, %{status: "test"}) + assert "http://localhost:4001/users/rye@niu.moe/followers" in activity.recipients + + user = User.get_cached_by_id(user.id) + assert user.note_count == 1 + + {:ok, user} = Transmogrifier.upgrade_user_from_ap_id("https://niu.moe/users/rye") + ObanHelpers.perform_all() + + assert user.ap_enabled + assert user.note_count == 1 + assert user.follower_address == "https://niu.moe/users/rye/followers" + assert user.following_address == "https://niu.moe/users/rye/following" + + user = User.get_cached_by_id(user.id) + assert user.note_count == 1 + + activity = Activity.get_by_id(activity.id) + assert user.follower_address in activity.recipients + + assert %{ + "url" => [ + %{ + "href" => + "https://cdn.niu.moe/accounts/avatars/000/033/323/original/fd7f8ae0b3ffedc9.jpeg" + } + ] + } = user.avatar + + assert %{ + "url" => [ + %{ + "href" => + "https://cdn.niu.moe/accounts/headers/000/033/323/original/850b3448fa5fd477.png" + } + ] + } = user.banner + + refute "..." in activity.recipients + + unrelated_activity = Activity.get_by_id(unrelated_activity.id) + refute user.follower_address in unrelated_activity.recipients + + user_two = User.get_cached_by_id(user_two.id) + assert User.following?(user_two, user) + refute "..." in User.following(user_two) + end + end + + describe "actor rewriting" do + test "it fixes the actor URL property to be a proper URI" do + data = %{ + "url" => %{"href" => "http://example.com"} + } + + rewritten = Transmogrifier.maybe_fix_user_object(data) + assert rewritten["url"] == "http://example.com" + end + end + + describe "actor origin containment" do + test "it rejects activities which reference objects with bogus origins" do + data = %{ + "@context" => "https://www.w3.org/ns/activitystreams", + "id" => "http://mastodon.example.org/users/admin/activities/1234", + "actor" => "http://mastodon.example.org/users/admin", + "to" => ["https://www.w3.org/ns/activitystreams#Public"], + "object" => "https://info.pleroma.site/activity.json", + "type" => "Announce" + } + + assert capture_log(fn -> + {:error, _} = Transmogrifier.handle_incoming(data) + end) =~ "Object containment failed" + end + + test "it rejects activities which reference objects that have an incorrect attribution (variant 1)" do + data = %{ + "@context" => "https://www.w3.org/ns/activitystreams", + "id" => "http://mastodon.example.org/users/admin/activities/1234", + "actor" => "http://mastodon.example.org/users/admin", + "to" => ["https://www.w3.org/ns/activitystreams#Public"], + "object" => "https://info.pleroma.site/activity2.json", + "type" => "Announce" + } + + assert capture_log(fn -> + {:error, _} = Transmogrifier.handle_incoming(data) + end) =~ "Object containment failed" + end + + test "it rejects activities which reference objects that have an incorrect attribution (variant 2)" do + data = %{ + "@context" => "https://www.w3.org/ns/activitystreams", + "id" => "http://mastodon.example.org/users/admin/activities/1234", + "actor" => "http://mastodon.example.org/users/admin", + "to" => ["https://www.w3.org/ns/activitystreams#Public"], + "object" => "https://info.pleroma.site/activity3.json", + "type" => "Announce" + } + + assert capture_log(fn -> + {:error, _} = Transmogrifier.handle_incoming(data) + end) =~ "Object containment failed" + end + end + + describe "fix_explicit_addressing" do + setup do + user = insert(:user) + [user: user] + end + + test "moves non-explicitly mentioned actors to cc", %{user: user} do + explicitly_mentioned_actors = [ + "https://pleroma.gold/users/user1", + "https://pleroma.gold/user2" + ] + + object = %{ + "actor" => user.ap_id, + "to" => explicitly_mentioned_actors ++ ["https://social.beepboop.ga/users/dirb"], + "cc" => [], + "tag" => + Enum.map(explicitly_mentioned_actors, fn href -> + %{"type" => "Mention", "href" => href} + end) + } + + fixed_object = Transmogrifier.fix_explicit_addressing(object, user.follower_address) + assert Enum.all?(explicitly_mentioned_actors, &(&1 in fixed_object["to"])) + refute "https://social.beepboop.ga/users/dirb" in fixed_object["to"] + assert "https://social.beepboop.ga/users/dirb" in fixed_object["cc"] + end + + test "does not move actor's follower collection to cc", %{user: user} do + object = %{ + "actor" => user.ap_id, + "to" => [user.follower_address], + "cc" => [] + } + + fixed_object = Transmogrifier.fix_explicit_addressing(object, user.follower_address) + assert user.follower_address in fixed_object["to"] + refute user.follower_address in fixed_object["cc"] + end + + test "removes recipient's follower collection from cc", %{user: user} do + recipient = insert(:user) + + object = %{ + "actor" => user.ap_id, + "to" => [recipient.ap_id, "https://www.w3.org/ns/activitystreams#Public"], + "cc" => [user.follower_address, recipient.follower_address] + } + + fixed_object = Transmogrifier.fix_explicit_addressing(object, user.follower_address) + + assert user.follower_address in fixed_object["cc"] + refute recipient.follower_address in fixed_object["cc"] + refute recipient.follower_address in fixed_object["to"] + end + end + + describe "fix_summary/1" do + test "returns fixed object" do + assert Transmogrifier.fix_summary(%{"summary" => nil}) == %{"summary" => ""} + assert Transmogrifier.fix_summary(%{"summary" => "ok"}) == %{"summary" => "ok"} + assert Transmogrifier.fix_summary(%{}) == %{"summary" => ""} + end + end + + describe "fix_url/1" do + test "fixes data for object when url is map" do + object = %{ + "url" => %{ + "type" => "Link", + "mimeType" => "video/mp4", + "href" => "https://peede8d-46fb-ad81-2d4c2d1630e3-480.mp4" + } + } + + assert Transmogrifier.fix_url(object) == %{ + "url" => "https://peede8d-46fb-ad81-2d4c2d1630e3-480.mp4" + } + end + + test "returns non-modified object" do + assert Transmogrifier.fix_url(%{"type" => "Text"}) == %{"type" => "Text"} + end + end + + describe "get_obj_helper/2" do + test "returns nil when cannot normalize object" do + assert capture_log(fn -> + refute Transmogrifier.get_obj_helper("test-obj-id") + end) =~ "Unsupported URI scheme" + end + + @tag capture_log: true + test "returns {:ok, %Object{}} for success case" do + assert {:ok, %Object{}} = + Transmogrifier.get_obj_helper( + "https://mstdn.io/users/mayuutann/statuses/99568293732299394" + ) + end + end + + describe "fix_attachments/1" do + test "puts dimensions into attachment url field" do + object = %{ + "attachment" => [ + %{ + "type" => "Document", + "name" => "Hello world", + "url" => "https://media.example.tld/1.jpg", + "width" => 880, + "height" => 960, + "mediaType" => "image/jpeg", + "blurhash" => "eTKL26+HDjcEIBVl;ds+K6t301W.t7nit7y1E,R:v}ai4nXSt7V@of" + } + ] + } + + expected = %{ + "attachment" => [ + %{ + "type" => "Document", + "name" => "Hello world", + "url" => [ + %{ + "type" => "Link", + "mediaType" => "image/jpeg", + "href" => "https://media.example.tld/1.jpg", + "width" => 880, + "height" => 960 + } + ], + "mediaType" => "image/jpeg", + "blurhash" => "eTKL26+HDjcEIBVl;ds+K6t301W.t7nit7y1E,R:v}ai4nXSt7V@of" + } + ] + } + + assert Transmogrifier.fix_attachments(object) == expected + end + end +end diff --git a/test/web/activity_pub/utils_test.exs b/test/pleroma/web/activity_pub/utils_test.exs index d50213545..62dc02f61 100644 --- a/test/web/activity_pub/utils_test.exs +++ b/test/pleroma/web/activity_pub/utils_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.UtilsTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true alias Pleroma.Activity alias Pleroma.Object alias Pleroma.Repo @@ -165,7 +165,7 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do } }) - object = Object.normalize(activity) + object = Object.normalize(activity, fetch: false) {:ok, votes, object} = CommonAPI.vote(other_user, object, [0, 1]) assert Enum.sort(Utils.get_existing_votes(other_user.ap_id, object)) == Enum.sort(votes) end @@ -183,7 +183,7 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do } }) - object = Object.normalize(activity) + object = Object.normalize(activity, fetch: false) {:ok, [vote], object} = CommonAPI.vote(other_user, object, [0]) {:ok, _activity} = CommonAPI.favorite(user, activity.id) [fetched_vote] = Utils.get_existing_votes(other_user.ap_id, object) @@ -193,7 +193,7 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do describe "update_follow_state_for_all/2" do test "updates the state of all Follow activities with the same actor and object" do - user = insert(:user, locked: true) + user = insert(:user, is_locked: true) follower = insert(:user) {:ok, _, _, follow_activity} = CommonAPI.follow(follower, user) @@ -213,11 +213,25 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do assert refresh_record(follow_activity).data["state"] == "accept" assert refresh_record(follow_activity_two).data["state"] == "accept" end + + test "also updates the state of accepted follows" do + user = insert(:user) + follower = insert(:user) + + {:ok, _, _, follow_activity} = CommonAPI.follow(follower, user) + {:ok, _, _, follow_activity_two} = CommonAPI.follow(follower, user) + + {:ok, follow_activity_two} = + Utils.update_follow_state_for_all(follow_activity_two, "reject") + + assert refresh_record(follow_activity).data["state"] == "reject" + assert refresh_record(follow_activity_two).data["state"] == "reject" + end end describe "update_follow_state/2" do test "updates the state of the given follow activity" do - user = insert(:user, locked: true) + user = insert(:user, is_locked: true) follower = insert(:user) {:ok, _, _, follow_activity} = CommonAPI.follow(follower, user) @@ -242,7 +256,7 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do test "updates likes" do user = insert(:user) activity = insert(:note_activity) - object = Object.normalize(activity) + object = Object.normalize(activity, fetch: false) assert {:ok, updated_object} = Utils.update_element_in_object( @@ -302,7 +316,7 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do describe "get_existing_like/2" do test "fetches existing like" do note_activity = insert(:note_activity) - assert object = Object.normalize(note_activity) + assert object = Object.normalize(note_activity, fetch: false) user = insert(:user) refute Utils.get_existing_like(user.ap_id, object) @@ -320,7 +334,7 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do test "fetches existing announce" do note_activity = insert(:note_activity) - assert object = Object.normalize(note_activity) + assert object = Object.normalize(note_activity, fetch: false) actor = insert(:user) {:ok, announce} = CommonAPI.repeat(note_activity.id, actor) @@ -412,7 +426,7 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do describe "lazy_put_activity_defaults/2" do test "returns map with id and published data" do note_activity = insert(:note_activity) - object = Object.normalize(note_activity) + object = Object.normalize(note_activity, fetch: false) res = Utils.lazy_put_activity_defaults(%{"context" => object.data["id"]}) assert res["context"] == object.data["id"] assert res["context_id"] == object.id @@ -431,7 +445,7 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do test "returns activity data with object" do note_activity = insert(:note_activity) - object = Object.normalize(note_activity) + object = Object.normalize(note_activity, fetch: false) res = Utils.lazy_put_activity_defaults(%{ diff --git a/test/web/activity_pub/views/object_view_test.exs b/test/pleroma/web/activity_pub/views/object_view_test.exs index f0389845d..923515dec 100644 --- a/test/web/activity_pub/views/object_view_test.exs +++ b/test/pleroma/web/activity_pub/views/object_view_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.ObjectViewTest do @@ -24,7 +24,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectViewTest do test "renders a note activity" do note = insert(:note_activity) - object = Object.normalize(note) + object = Object.normalize(note, fetch: false) result = ObjectView.render("object.json", %{object: note}) @@ -56,7 +56,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectViewTest do test "renders a like activity" do note = insert(:note_activity) - object = Object.normalize(note) + object = Object.normalize(note, fetch: false) user = insert(:user) {:ok, like_activity} = CommonAPI.favorite(user, note.id) @@ -70,7 +70,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectViewTest do test "renders an announce activity" do note = insert(:note_activity) - object = Object.normalize(note) + object = Object.normalize(note, fetch: false) user = insert(:user) {:ok, announce_activity} = CommonAPI.repeat(note.id, user) diff --git a/test/web/activity_pub/views/user_view_test.exs b/test/pleroma/web/activity_pub/views/user_view_test.exs index 98c7c9d09..f2de4d332 100644 --- a/test/web/activity_pub/views/user_view_test.exs +++ b/test/pleroma/web/activity_pub/views/user_view_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.UserViewTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true import Pleroma.Factory alias Pleroma.User @@ -80,6 +80,12 @@ defmodule Pleroma.Web.ActivityPub.UserViewTest do assert %{"invisible" => true} = UserView.render("service.json", %{user: user}) end + test "renders AKAs" do + akas = ["https://i.tusooa.xyz/users/test-pleroma"] + user = insert(:user, also_known_as: akas) + assert %{"alsoKnownAs" => ^akas} = UserView.render("user.json", %{user: user}) + end + describe "endpoints" do test "local users have a usable endpoints structure" do user = insert(:user) diff --git a/test/web/activity_pub/visibilty_test.exs b/test/pleroma/web/activity_pub/visibility_test.exs index 8e9354c65..23485225d 100644 --- a/test/web/activity_pub/visibilty_test.exs +++ b/test/pleroma/web/activity_pub/visibility_test.exs @@ -1,11 +1,12 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.VisibilityTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true alias Pleroma.Activity + alias Pleroma.Object alias Pleroma.Web.ActivityPub.Visibility alias Pleroma.Web.CommonAPI import Pleroma.Factory @@ -15,7 +16,7 @@ defmodule Pleroma.Web.ActivityPub.VisibilityTest do mentioned = insert(:user) following = insert(:user) unrelated = insert(:user) - {:ok, following} = Pleroma.User.follow(following, user) + {:ok, following, user} = Pleroma.User.follow(following, user) {:ok, list} = Pleroma.List.create("foo", user) Pleroma.List.follow(list, unrelated) @@ -107,7 +108,7 @@ defmodule Pleroma.Web.ActivityPub.VisibilityTest do assert Visibility.is_list?(list) end - test "visible_for_user?", %{ + test "visible_for_user? Activity", %{ public: public, private: private, direct: direct, @@ -149,17 +150,83 @@ defmodule Pleroma.Web.ActivityPub.VisibilityTest do refute Visibility.visible_for_user?(private, unrelated) refute Visibility.visible_for_user?(direct, unrelated) + # Public and unlisted visible for unauthenticated + + assert Visibility.visible_for_user?(public, nil) + assert Visibility.visible_for_user?(unlisted, nil) + refute Visibility.visible_for_user?(private, nil) + refute Visibility.visible_for_user?(direct, nil) + # Visible for a list member assert Visibility.visible_for_user?(list, unrelated) end + test "visible_for_user? Object", %{ + public: public, + private: private, + direct: direct, + unlisted: unlisted, + user: user, + mentioned: mentioned, + following: following, + unrelated: unrelated, + list: list + } do + public = Object.normalize(public) + private = Object.normalize(private) + unlisted = Object.normalize(unlisted) + direct = Object.normalize(direct) + list = Object.normalize(list) + + # All visible to author + + assert Visibility.visible_for_user?(public, user) + assert Visibility.visible_for_user?(private, user) + assert Visibility.visible_for_user?(unlisted, user) + assert Visibility.visible_for_user?(direct, user) + assert Visibility.visible_for_user?(list, user) + + # All visible to a mentioned user + + assert Visibility.visible_for_user?(public, mentioned) + assert Visibility.visible_for_user?(private, mentioned) + assert Visibility.visible_for_user?(unlisted, mentioned) + assert Visibility.visible_for_user?(direct, mentioned) + assert Visibility.visible_for_user?(list, mentioned) + + # DM not visible for just follower + + assert Visibility.visible_for_user?(public, following) + assert Visibility.visible_for_user?(private, following) + assert Visibility.visible_for_user?(unlisted, following) + refute Visibility.visible_for_user?(direct, following) + refute Visibility.visible_for_user?(list, following) + + # Public and unlisted visible for unrelated user + + assert Visibility.visible_for_user?(public, unrelated) + assert Visibility.visible_for_user?(unlisted, unrelated) + refute Visibility.visible_for_user?(private, unrelated) + refute Visibility.visible_for_user?(direct, unrelated) + + # Public and unlisted visible for unauthenticated + + assert Visibility.visible_for_user?(public, nil) + assert Visibility.visible_for_user?(unlisted, nil) + refute Visibility.visible_for_user?(private, nil) + refute Visibility.visible_for_user?(direct, nil) + + # Visible for a list member + # assert Visibility.visible_for_user?(list, unrelated) + end + test "doesn't die when the user doesn't exist", %{ direct: direct, user: user } do Repo.delete(user) - Cachex.clear(:user_cache) + Pleroma.User.invalidate_cache(user) refute Visibility.is_private?(direct) end diff --git a/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs b/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs new file mode 100644 index 000000000..f8cd103c6 --- /dev/null +++ b/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs @@ -0,0 +1,968 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do + use Pleroma.Web.ConnCase + use Oban.Testing, repo: Pleroma.Repo + + import ExUnit.CaptureLog + import Pleroma.Factory + import Swoosh.TestAssertions + + alias Pleroma.Activity + alias Pleroma.MFA + alias Pleroma.ModerationLog + alias Pleroma.Repo + alias Pleroma.Tests.ObanHelpers + alias Pleroma.User + alias Pleroma.Web.CommonAPI + + setup_all do + Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) + + :ok + end + + setup do + admin = insert(:user, is_admin: true) + token = insert(:oauth_admin_token, user: admin) + + conn = + build_conn() + |> assign(:user, admin) + |> assign(:token, token) + + {:ok, %{admin: admin, token: token, conn: conn}} + end + + test "with valid `admin_token` query parameter, skips OAuth scopes check" do + clear_config([:admin_token], "password123") + + user = insert(:user) + + conn = get(build_conn(), "/api/pleroma/admin/users/#{user.nickname}?admin_token=password123") + + assert json_response(conn, 200) + end + + test "GET /api/pleroma/admin/users/:nickname requires admin:read:accounts or broader scope", + %{admin: admin} do + user = insert(:user) + url = "/api/pleroma/admin/users/#{user.nickname}" + + good_token1 = insert(:oauth_token, user: admin, scopes: ["admin"]) + good_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read"]) + good_token3 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts"]) + + bad_token1 = insert(:oauth_token, user: admin, scopes: ["read:accounts"]) + bad_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts:partial"]) + bad_token3 = nil + + for good_token <- [good_token1, good_token2, good_token3] do + conn = + build_conn() + |> assign(:user, admin) + |> assign(:token, good_token) + |> get(url) + + assert json_response(conn, 200) + end + + for good_token <- [good_token1, good_token2, good_token3] do + conn = + build_conn() + |> assign(:user, nil) + |> assign(:token, good_token) + |> get(url) + + assert json_response(conn, :forbidden) + end + + for bad_token <- [bad_token1, bad_token2, bad_token3] do + conn = + build_conn() + |> assign(:user, admin) + |> assign(:token, bad_token) + |> get(url) + + assert json_response(conn, :forbidden) + end + end + + describe "PUT /api/pleroma/admin/users/tag" do + setup %{conn: conn} do + user1 = insert(:user, %{tags: ["x"]}) + user2 = insert(:user, %{tags: ["y"]}) + user3 = insert(:user, %{tags: ["unchanged"]}) + + conn = + conn + |> put_req_header("accept", "application/json") + |> put( + "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <> + "#{user2.nickname}&tags[]=foo&tags[]=bar" + ) + + %{conn: conn, user1: user1, user2: user2, user3: user3} + end + + test "it appends specified tags to users with specified nicknames", %{ + conn: conn, + admin: admin, + user1: user1, + user2: user2 + } do + assert empty_json_response(conn) + assert User.get_cached_by_id(user1.id).tags == ["x", "foo", "bar"] + assert User.get_cached_by_id(user2.id).tags == ["y", "foo", "bar"] + + log_entry = Repo.one(ModerationLog) + + users = + [user1.nickname, user2.nickname] + |> Enum.map(&"@#{&1}") + |> Enum.join(", ") + + tags = ["foo", "bar"] |> Enum.join(", ") + + assert ModerationLog.get_log_entry_message(log_entry) == + "@#{admin.nickname} added tags: #{tags} to users: #{users}" + end + + test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do + assert empty_json_response(conn) + assert User.get_cached_by_id(user3.id).tags == ["unchanged"] + end + end + + describe "DELETE /api/pleroma/admin/users/tag" do + setup %{conn: conn} do + user1 = insert(:user, %{tags: ["x"]}) + user2 = insert(:user, %{tags: ["y", "z"]}) + user3 = insert(:user, %{tags: ["unchanged"]}) + + conn = + conn + |> put_req_header("accept", "application/json") + |> delete( + "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <> + "#{user2.nickname}&tags[]=x&tags[]=z" + ) + + %{conn: conn, user1: user1, user2: user2, user3: user3} + end + + test "it removes specified tags from users with specified nicknames", %{ + conn: conn, + admin: admin, + user1: user1, + user2: user2 + } do + assert empty_json_response(conn) + assert User.get_cached_by_id(user1.id).tags == [] + assert User.get_cached_by_id(user2.id).tags == ["y"] + + log_entry = Repo.one(ModerationLog) + + users = + [user1.nickname, user2.nickname] + |> Enum.map(&"@#{&1}") + |> Enum.join(", ") + + tags = ["x", "z"] |> Enum.join(", ") + + assert ModerationLog.get_log_entry_message(log_entry) == + "@#{admin.nickname} removed tags: #{tags} from users: #{users}" + end + + test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do + assert empty_json_response(conn) + assert User.get_cached_by_id(user3.id).tags == ["unchanged"] + end + end + + describe "/api/pleroma/admin/users/:nickname/permission_group" do + test "GET is giving user_info", %{admin: admin, conn: conn} do + conn = + conn + |> put_req_header("accept", "application/json") + |> get("/api/pleroma/admin/users/#{admin.nickname}/permission_group/") + + assert json_response(conn, 200) == %{ + "is_admin" => true, + "is_moderator" => false + } + end + + test "/:right POST, can add to a permission group", %{admin: admin, conn: conn} do + user = insert(:user) + + conn = + conn + |> put_req_header("accept", "application/json") + |> post("/api/pleroma/admin/users/#{user.nickname}/permission_group/admin") + + assert json_response(conn, 200) == %{ + "is_admin" => true + } + + log_entry = Repo.one(ModerationLog) + + assert ModerationLog.get_log_entry_message(log_entry) == + "@#{admin.nickname} made @#{user.nickname} admin" + end + + test "/:right POST, can add to a permission group (multiple)", %{admin: admin, conn: conn} do + user_one = insert(:user) + user_two = insert(:user) + + conn = + conn + |> put_req_header("accept", "application/json") + |> post("/api/pleroma/admin/users/permission_group/admin", %{ + nicknames: [user_one.nickname, user_two.nickname] + }) + + assert json_response(conn, 200) == %{"is_admin" => true} + + log_entry = Repo.one(ModerationLog) + + assert ModerationLog.get_log_entry_message(log_entry) == + "@#{admin.nickname} made @#{user_one.nickname}, @#{user_two.nickname} admin" + end + + test "/:right DELETE, can remove from a permission group", %{admin: admin, conn: conn} do + user = insert(:user, is_admin: true) + + conn = + conn + |> put_req_header("accept", "application/json") + |> delete("/api/pleroma/admin/users/#{user.nickname}/permission_group/admin") + + assert json_response(conn, 200) == %{"is_admin" => false} + + log_entry = Repo.one(ModerationLog) + + assert ModerationLog.get_log_entry_message(log_entry) == + "@#{admin.nickname} revoked admin role from @#{user.nickname}" + end + + test "/:right DELETE, can remove from a permission group (multiple)", %{ + admin: admin, + conn: conn + } do + user_one = insert(:user, is_admin: true) + user_two = insert(:user, is_admin: true) + + conn = + conn + |> put_req_header("accept", "application/json") + |> delete("/api/pleroma/admin/users/permission_group/admin", %{ + nicknames: [user_one.nickname, user_two.nickname] + }) + + assert json_response(conn, 200) == %{"is_admin" => false} + + log_entry = Repo.one(ModerationLog) + + assert ModerationLog.get_log_entry_message(log_entry) == + "@#{admin.nickname} revoked admin role from @#{user_one.nickname}, @#{user_two.nickname}" + end + end + + test "/api/pleroma/admin/users/:nickname/password_reset", %{conn: conn} do + user = insert(:user) + + conn = + conn + |> put_req_header("accept", "application/json") + |> get("/api/pleroma/admin/users/#{user.nickname}/password_reset") + + resp = json_response(conn, 200) + + assert Regex.match?(~r/(http:\/\/|https:\/\/)/, resp["link"]) + end + + describe "PUT disable_mfa" do + test "returns 200 and disable 2fa", %{conn: conn} do + user = + insert(:user, + multi_factor_authentication_settings: %MFA.Settings{ + enabled: true, + totp: %MFA.Settings.TOTP{secret: "otp_secret", confirmed: true} + } + ) + + response = + conn + |> put("/api/pleroma/admin/users/disable_mfa", %{nickname: user.nickname}) + |> json_response(200) + + assert response == user.nickname + mfa_settings = refresh_record(user).multi_factor_authentication_settings + + refute mfa_settings.enabled + refute mfa_settings.totp.confirmed + end + + test "returns 404 if user not found", %{conn: conn} do + response = + conn + |> put("/api/pleroma/admin/users/disable_mfa", %{nickname: "nickname"}) + |> json_response(404) + + assert response == %{"error" => "Not found"} + end + end + + describe "GET /api/pleroma/admin/restart" do + setup do: clear_config(:configurable_from_database, true) + + test "pleroma restarts", %{conn: conn} do + capture_log(fn -> + assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{} + end) =~ "pleroma restarted" + + refute Restarter.Pleroma.need_reboot?() + end + end + + test "need_reboot flag", %{conn: conn} do + assert conn + |> get("/api/pleroma/admin/need_reboot") + |> json_response(200) == %{"need_reboot" => false} + + Restarter.Pleroma.need_reboot() + + assert conn + |> get("/api/pleroma/admin/need_reboot") + |> json_response(200) == %{"need_reboot" => true} + + on_exit(fn -> Restarter.Pleroma.refresh() end) + end + + describe "GET /api/pleroma/admin/users/:nickname/statuses" do + setup do + user = insert(:user) + + insert(:note_activity, user: user) + insert(:note_activity, user: user) + insert(:note_activity, user: user) + + %{user: user} + end + + test "renders user's statuses", %{conn: conn, user: user} do + conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses") + + assert %{"total" => 3, "activities" => activities} = json_response(conn, 200) + assert length(activities) == 3 + end + + test "renders user's statuses with pagination", %{conn: conn, user: user} do + %{"total" => 3, "activities" => [activity1]} = + conn + |> get("/api/pleroma/admin/users/#{user.nickname}/statuses?page_size=1&page=1") + |> json_response(200) + + %{"total" => 3, "activities" => [activity2]} = + conn + |> get("/api/pleroma/admin/users/#{user.nickname}/statuses?page_size=1&page=2") + |> json_response(200) + + refute activity1 == activity2 + end + + test "doesn't return private statuses by default", %{conn: conn, user: user} do + {:ok, _private_status} = CommonAPI.post(user, %{status: "private", visibility: "private"}) + + {:ok, _public_status} = CommonAPI.post(user, %{status: "public", visibility: "public"}) + + %{"total" => 4, "activities" => activities} = + conn + |> get("/api/pleroma/admin/users/#{user.nickname}/statuses") + |> json_response(200) + + assert length(activities) == 4 + end + + test "returns private statuses with godmode on", %{conn: conn, user: user} do + {:ok, _private_status} = CommonAPI.post(user, %{status: "private", visibility: "private"}) + + {:ok, _public_status} = CommonAPI.post(user, %{status: "public", visibility: "public"}) + + %{"total" => 5, "activities" => activities} = + conn + |> get("/api/pleroma/admin/users/#{user.nickname}/statuses?godmode=true") + |> json_response(200) + + assert length(activities) == 5 + end + + test "excludes reblogs by default", %{conn: conn, user: user} do + other_user = insert(:user) + {:ok, activity} = CommonAPI.post(user, %{status: "."}) + {:ok, %Activity{}} = CommonAPI.repeat(activity.id, other_user) + + assert %{"total" => 0, "activities" => []} == + conn + |> get("/api/pleroma/admin/users/#{other_user.nickname}/statuses") + |> json_response(200) + + assert %{"total" => 1, "activities" => [_]} = + conn + |> get( + "/api/pleroma/admin/users/#{other_user.nickname}/statuses?with_reblogs=true" + ) + |> json_response(200) + end + end + + describe "GET /api/pleroma/admin/users/:nickname/chats" do + setup do + user = insert(:user) + recipients = insert_list(3, :user) + + Enum.each(recipients, fn recipient -> + CommonAPI.post_chat_message(user, recipient, "yo") + end) + + %{user: user} + end + + test "renders user's chats", %{conn: conn, user: user} do + conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/chats") + + assert json_response(conn, 200) |> length() == 3 + end + end + + describe "GET /api/pleroma/admin/users/:nickname/chats unauthorized" do + setup do + user = insert(:user) + recipient = insert(:user) + CommonAPI.post_chat_message(user, recipient, "yo") + %{conn: conn} = oauth_access(["read:chats"]) + %{conn: conn, user: user} + end + + test "returns 403", %{conn: conn, user: user} do + conn + |> get("/api/pleroma/admin/users/#{user.nickname}/chats") + |> json_response(403) + end + end + + describe "GET /api/pleroma/admin/users/:nickname/chats unauthenticated" do + setup do + user = insert(:user) + recipient = insert(:user) + CommonAPI.post_chat_message(user, recipient, "yo") + %{conn: build_conn(), user: user} + end + + test "returns 403", %{conn: conn, user: user} do + conn + |> get("/api/pleroma/admin/users/#{user.nickname}/chats") + |> json_response(403) + end + end + + describe "GET /api/pleroma/admin/moderation_log" do + setup do + moderator = insert(:user, is_moderator: true) + + %{moderator: moderator} + end + + test "returns the log", %{conn: conn, admin: admin} do + Repo.insert(%ModerationLog{ + data: %{ + actor: %{ + "id" => admin.id, + "nickname" => admin.nickname, + "type" => "user" + }, + action: "relay_follow", + target: "https://example.org/relay" + }, + inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second) + }) + + Repo.insert(%ModerationLog{ + data: %{ + actor: %{ + "id" => admin.id, + "nickname" => admin.nickname, + "type" => "user" + }, + action: "relay_unfollow", + target: "https://example.org/relay" + }, + inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second) + }) + + conn = get(conn, "/api/pleroma/admin/moderation_log") + + response = json_response(conn, 200) + [first_entry, second_entry] = response["items"] + + assert response["total"] == 2 + assert first_entry["data"]["action"] == "relay_unfollow" + + assert first_entry["message"] == + "@#{admin.nickname} unfollowed relay: https://example.org/relay" + + assert second_entry["data"]["action"] == "relay_follow" + + assert second_entry["message"] == + "@#{admin.nickname} followed relay: https://example.org/relay" + end + + test "returns the log with pagination", %{conn: conn, admin: admin} do + Repo.insert(%ModerationLog{ + data: %{ + actor: %{ + "id" => admin.id, + "nickname" => admin.nickname, + "type" => "user" + }, + action: "relay_follow", + target: "https://example.org/relay" + }, + inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second) + }) + + Repo.insert(%ModerationLog{ + data: %{ + actor: %{ + "id" => admin.id, + "nickname" => admin.nickname, + "type" => "user" + }, + action: "relay_unfollow", + target: "https://example.org/relay" + }, + inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second) + }) + + conn1 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=1") + + response1 = json_response(conn1, 200) + [first_entry] = response1["items"] + + assert response1["total"] == 2 + assert response1["items"] |> length() == 1 + assert first_entry["data"]["action"] == "relay_unfollow" + + assert first_entry["message"] == + "@#{admin.nickname} unfollowed relay: https://example.org/relay" + + conn2 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=2") + + response2 = json_response(conn2, 200) + [second_entry] = response2["items"] + + assert response2["total"] == 2 + assert response2["items"] |> length() == 1 + assert second_entry["data"]["action"] == "relay_follow" + + assert second_entry["message"] == + "@#{admin.nickname} followed relay: https://example.org/relay" + end + + test "filters log by date", %{conn: conn, admin: admin} do + first_date = "2017-08-15T15:47:06Z" + second_date = "2017-08-20T15:47:06Z" + + Repo.insert(%ModerationLog{ + data: %{ + actor: %{ + "id" => admin.id, + "nickname" => admin.nickname, + "type" => "user" + }, + action: "relay_follow", + target: "https://example.org/relay" + }, + inserted_at: NaiveDateTime.from_iso8601!(first_date) + }) + + Repo.insert(%ModerationLog{ + data: %{ + actor: %{ + "id" => admin.id, + "nickname" => admin.nickname, + "type" => "user" + }, + action: "relay_unfollow", + target: "https://example.org/relay" + }, + inserted_at: NaiveDateTime.from_iso8601!(second_date) + }) + + conn1 = + get( + conn, + "/api/pleroma/admin/moderation_log?start_date=#{second_date}" + ) + + response1 = json_response(conn1, 200) + [first_entry] = response1["items"] + + assert response1["total"] == 1 + assert first_entry["data"]["action"] == "relay_unfollow" + + assert first_entry["message"] == + "@#{admin.nickname} unfollowed relay: https://example.org/relay" + end + + test "returns log filtered by user", %{conn: conn, admin: admin, moderator: moderator} do + Repo.insert(%ModerationLog{ + data: %{ + actor: %{ + "id" => admin.id, + "nickname" => admin.nickname, + "type" => "user" + }, + action: "relay_follow", + target: "https://example.org/relay" + } + }) + + Repo.insert(%ModerationLog{ + data: %{ + actor: %{ + "id" => moderator.id, + "nickname" => moderator.nickname, + "type" => "user" + }, + action: "relay_unfollow", + target: "https://example.org/relay" + } + }) + + conn1 = get(conn, "/api/pleroma/admin/moderation_log?user_id=#{moderator.id}") + + response1 = json_response(conn1, 200) + [first_entry] = response1["items"] + + assert response1["total"] == 1 + assert get_in(first_entry, ["data", "actor", "id"]) == moderator.id + end + + test "returns log filtered by search", %{conn: conn, moderator: moderator} do + ModerationLog.insert_log(%{ + actor: moderator, + action: "relay_follow", + target: "https://example.org/relay" + }) + + ModerationLog.insert_log(%{ + actor: moderator, + action: "relay_unfollow", + target: "https://example.org/relay" + }) + + conn1 = get(conn, "/api/pleroma/admin/moderation_log?search=unfo") + + response1 = json_response(conn1, 200) + [first_entry] = response1["items"] + + assert response1["total"] == 1 + + assert get_in(first_entry, ["data", "message"]) == + "@#{moderator.nickname} unfollowed relay: https://example.org/relay" + end + end + + test "gets a remote users when [:instance, :limit_to_local_content] is set to :unauthenticated", + %{conn: conn} do + clear_config(Pleroma.Config.get([:instance, :limit_to_local_content]), :unauthenticated) + user = insert(:user, %{local: false, nickname: "u@peer1.com"}) + conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials") + + assert json_response(conn, 200) + end + + describe "GET /users/:nickname/credentials" do + test "gets the user credentials", %{conn: conn} do + user = insert(:user) + conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials") + + response = assert json_response(conn, 200) + assert response["email"] == user.email + end + + test "returns 403 if requested by a non-admin" do + user = insert(:user) + + conn = + build_conn() + |> assign(:user, user) + |> get("/api/pleroma/admin/users/#{user.nickname}/credentials") + + assert json_response(conn, :forbidden) + end + end + + describe "PATCH /users/:nickname/credentials" do + setup do + user = insert(:user) + [user: user] + end + + test "changes password and email", %{conn: conn, admin: admin, user: user} do + assert user.password_reset_pending == false + + conn = + patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{ + "password" => "new_password", + "email" => "new_email@example.com", + "name" => "new_name" + }) + + assert json_response(conn, 200) == %{"status" => "success"} + + ObanHelpers.perform_all() + + updated_user = User.get_by_id(user.id) + + assert updated_user.email == "new_email@example.com" + assert updated_user.name == "new_name" + assert updated_user.password_hash != user.password_hash + assert updated_user.password_reset_pending == true + + [log_entry2, log_entry1] = ModerationLog |> Repo.all() |> Enum.sort() + + assert ModerationLog.get_log_entry_message(log_entry1) == + "@#{admin.nickname} updated users: @#{user.nickname}" + + assert ModerationLog.get_log_entry_message(log_entry2) == + "@#{admin.nickname} forced password reset for users: @#{user.nickname}" + end + + test "returns 403 if requested by a non-admin", %{user: user} do + conn = + build_conn() + |> assign(:user, user) + |> patch("/api/pleroma/admin/users/#{user.nickname}/credentials", %{ + "password" => "new_password", + "email" => "new_email@example.com", + "name" => "new_name" + }) + + assert json_response(conn, :forbidden) + end + + test "changes actor type from permitted list", %{conn: conn, user: user} do + assert user.actor_type == "Person" + + assert patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{ + "actor_type" => "Service" + }) + |> json_response(200) == %{"status" => "success"} + + updated_user = User.get_by_id(user.id) + + assert updated_user.actor_type == "Service" + + assert patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{ + "actor_type" => "Application" + }) + |> json_response(400) == %{"errors" => %{"actor_type" => "is invalid"}} + end + + test "update non existing user", %{conn: conn} do + assert patch(conn, "/api/pleroma/admin/users/non-existing/credentials", %{ + "password" => "new_password" + }) + |> json_response(404) == %{"error" => "Not found"} + end + end + + describe "PATCH /users/:nickname/force_password_reset" do + test "sets password_reset_pending to true", %{conn: conn} do + user = insert(:user) + assert user.password_reset_pending == false + + conn = + patch(conn, "/api/pleroma/admin/users/force_password_reset", %{nicknames: [user.nickname]}) + + assert empty_json_response(conn) == "" + + ObanHelpers.perform_all() + + assert User.get_by_id(user.id).password_reset_pending == true + end + end + + describe "PATCH /confirm_email" do + test "it confirms emails of two users", %{conn: conn, admin: admin} do + [first_user, second_user] = insert_pair(:user, is_confirmed: false) + + refute first_user.is_confirmed + refute second_user.is_confirmed + + ret_conn = + patch(conn, "/api/pleroma/admin/users/confirm_email", %{ + nicknames: [ + first_user.nickname, + second_user.nickname + ] + }) + + assert ret_conn.status == 200 + + first_user = User.get_by_id(first_user.id) + second_user = User.get_by_id(second_user.id) + + assert first_user.is_confirmed + assert second_user.is_confirmed + + log_entry = Repo.one(ModerationLog) + + assert ModerationLog.get_log_entry_message(log_entry) == + "@#{admin.nickname} confirmed email for users: @#{first_user.nickname}, @#{second_user.nickname}" + end + end + + describe "PATCH /resend_confirmation_email" do + test "it resend emails for two users", %{conn: conn, admin: admin} do + [first_user, second_user] = insert_pair(:user, is_confirmed: false) + + ret_conn = + patch(conn, "/api/pleroma/admin/users/resend_confirmation_email", %{ + nicknames: [ + first_user.nickname, + second_user.nickname + ] + }) + + assert ret_conn.status == 200 + + log_entry = Repo.one(ModerationLog) + + assert ModerationLog.get_log_entry_message(log_entry) == + "@#{admin.nickname} re-sent confirmation email for users: @#{first_user.nickname}, @#{second_user.nickname}" + + ObanHelpers.perform_all() + + Pleroma.Emails.UserEmail.account_confirmation_email(first_user) + # temporary hackney fix until hackney max_connections bug is fixed + # https://git.pleroma.social/pleroma/pleroma/-/issues/2101 + |> Swoosh.Email.put_private(:hackney_options, ssl_options: [versions: [:"tlsv1.2"]]) + |> assert_email_sent() + end + end + + describe "/api/pleroma/admin/stats" do + test "status visibility count", %{conn: conn} do + user = insert(:user) + CommonAPI.post(user, %{visibility: "public", status: "hey"}) + CommonAPI.post(user, %{visibility: "unlisted", status: "hey"}) + CommonAPI.post(user, %{visibility: "unlisted", status: "hey"}) + + response = + conn + |> get("/api/pleroma/admin/stats") + |> json_response(200) + + assert %{"direct" => 0, "private" => 0, "public" => 1, "unlisted" => 2} = + response["status_visibility"] + end + + test "by instance", %{conn: conn} do + user1 = insert(:user) + instance2 = "instance2.tld" + user2 = insert(:user, %{ap_id: "https://#{instance2}/@actor"}) + + CommonAPI.post(user1, %{visibility: "public", status: "hey"}) + CommonAPI.post(user2, %{visibility: "unlisted", status: "hey"}) + CommonAPI.post(user2, %{visibility: "private", status: "hey"}) + + response = + conn + |> get("/api/pleroma/admin/stats", instance: instance2) + |> json_response(200) + + assert %{"direct" => 0, "private" => 1, "public" => 0, "unlisted" => 1} = + response["status_visibility"] + end + end + + describe "/api/pleroma/backups" do + test "it creates a backup", %{conn: conn} do + admin = %{id: admin_id, nickname: admin_nickname} = insert(:user, is_admin: true) + token = insert(:oauth_admin_token, user: admin) + user = %{id: user_id, nickname: user_nickname} = insert(:user) + + assert "" == + conn + |> assign(:user, admin) + |> assign(:token, token) + |> post("/api/pleroma/admin/backups", %{nickname: user.nickname}) + |> json_response(200) + + assert [backup] = Repo.all(Pleroma.User.Backup) + + ObanHelpers.perform_all() + + email = Pleroma.Emails.UserEmail.backup_is_ready_email(backup, admin.id) + + assert String.contains?(email.html_body, "Admin @#{admin.nickname} requested a full backup") + assert_email_sent(to: {user.name, user.email}, html_body: email.html_body) + + log_message = "@#{admin_nickname} requested account backup for @#{user_nickname}" + + assert [ + %{ + data: %{ + "action" => "create_backup", + "actor" => %{ + "id" => ^admin_id, + "nickname" => ^admin_nickname + }, + "message" => ^log_message, + "subject" => %{ + "id" => ^user_id, + "nickname" => ^user_nickname + } + } + } + ] = Pleroma.ModerationLog |> Repo.all() + end + + test "it doesn't limit admins", %{conn: conn} do + admin = insert(:user, is_admin: true) + token = insert(:oauth_admin_token, user: admin) + user = insert(:user) + + assert "" == + conn + |> assign(:user, admin) + |> assign(:token, token) + |> post("/api/pleroma/admin/backups", %{nickname: user.nickname}) + |> json_response(200) + + assert [_backup] = Repo.all(Pleroma.User.Backup) + + assert "" == + conn + |> assign(:user, admin) + |> assign(:token, token) + |> post("/api/pleroma/admin/backups", %{nickname: user.nickname}) + |> json_response(200) + + assert Repo.aggregate(Pleroma.User.Backup, :count) == 2 + end + end +end + +# Needed for testing +defmodule Pleroma.Web.Endpoint.NotReal do +end + +defmodule Pleroma.Captcha.NotReal do +end diff --git a/test/pleroma/web/admin_api/controllers/chat_controller_test.exs b/test/pleroma/web/admin_api/controllers/chat_controller_test.exs new file mode 100644 index 000000000..0e8f7beef --- /dev/null +++ b/test/pleroma/web/admin_api/controllers/chat_controller_test.exs @@ -0,0 +1,218 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.AdminAPI.ChatControllerTest do + use Pleroma.Web.ConnCase, async: true + + import Pleroma.Factory + + alias Pleroma.Chat + alias Pleroma.Chat.MessageReference + alias Pleroma.ModerationLog + alias Pleroma.Object + alias Pleroma.Repo + alias Pleroma.Web.CommonAPI + + defp admin_setup do + admin = insert(:user, is_admin: true) + token = insert(:oauth_admin_token, user: admin) + + conn = + build_conn() + |> assign(:user, admin) + |> assign(:token, token) + + {:ok, %{admin: admin, token: token, conn: conn}} + end + + describe "DELETE /api/pleroma/admin/chats/:id/messages/:message_id" do + setup do: admin_setup() + + test "it deletes a message from the chat", %{conn: conn, admin: admin} do + user = insert(:user) + recipient = insert(:user) + + {:ok, message} = + CommonAPI.post_chat_message(user, recipient, "Hello darkness my old friend") + + object = Object.normalize(message, fetch: false) + + chat = Chat.get(user.id, recipient.ap_id) + recipient_chat = Chat.get(recipient.id, user.ap_id) + + cm_ref = MessageReference.for_chat_and_object(chat, object) + recipient_cm_ref = MessageReference.for_chat_and_object(recipient_chat, object) + + result = + conn + |> put_req_header("content-type", "application/json") + |> delete("/api/pleroma/admin/chats/#{chat.id}/messages/#{cm_ref.id}") + |> json_response_and_validate_schema(200) + + log_entry = Repo.one(ModerationLog) + + assert ModerationLog.get_log_entry_message(log_entry) == + "@#{admin.nickname} deleted chat message ##{cm_ref.id}" + + assert result["id"] == cm_ref.id + refute MessageReference.get_by_id(cm_ref.id) + refute MessageReference.get_by_id(recipient_cm_ref.id) + assert %{data: %{"type" => "Tombstone"}} = Object.get_by_id(object.id) + end + end + + describe "GET /api/pleroma/admin/chats/:id/messages" do + setup do: admin_setup() + + test "it paginates", %{conn: conn} do + user = insert(:user) + recipient = insert(:user) + + Enum.each(1..30, fn _ -> + {:ok, _} = CommonAPI.post_chat_message(user, recipient, "hey") + end) + + chat = Chat.get(user.id, recipient.ap_id) + + result = + conn + |> get("/api/pleroma/admin/chats/#{chat.id}/messages") + |> json_response_and_validate_schema(200) + + assert length(result) == 20 + + result = + conn + |> get("/api/pleroma/admin/chats/#{chat.id}/messages?max_id=#{List.last(result)["id"]}") + |> json_response_and_validate_schema(200) + + assert length(result) == 10 + end + + test "it returns the messages for a given chat", %{conn: conn} do + user = insert(:user) + other_user = insert(:user) + third_user = insert(:user) + + {:ok, _} = CommonAPI.post_chat_message(user, other_user, "hey") + {:ok, _} = CommonAPI.post_chat_message(user, third_user, "hey") + {:ok, _} = CommonAPI.post_chat_message(user, other_user, "how are you?") + {:ok, _} = CommonAPI.post_chat_message(other_user, user, "fine, how about you?") + + chat = Chat.get(user.id, other_user.ap_id) + + result = + conn + |> get("/api/pleroma/admin/chats/#{chat.id}/messages") + |> json_response_and_validate_schema(200) + + result + |> Enum.each(fn message -> + assert message["chat_id"] == chat.id |> to_string() + end) + + assert length(result) == 3 + end + end + + describe "GET /api/pleroma/admin/chats/:id" do + setup do: admin_setup() + + test "it returns a chat", %{conn: conn} do + user = insert(:user) + other_user = insert(:user) + + {:ok, chat} = Chat.get_or_create(user.id, other_user.ap_id) + + result = + conn + |> get("/api/pleroma/admin/chats/#{chat.id}") + |> json_response_and_validate_schema(200) + + assert result["id"] == to_string(chat.id) + assert %{} = result["sender"] + assert %{} = result["receiver"] + refute result["account"] + end + end + + describe "unauthorized chat moderation" do + setup do + user = insert(:user) + recipient = insert(:user) + + {:ok, message} = CommonAPI.post_chat_message(user, recipient, "Yo") + object = Object.normalize(message, fetch: false) + chat = Chat.get(user.id, recipient.ap_id) + cm_ref = MessageReference.for_chat_and_object(chat, object) + + %{conn: conn} = oauth_access(["read:chats", "write:chats"]) + %{conn: conn, chat: chat, cm_ref: cm_ref} + end + + test "DELETE /api/pleroma/admin/chats/:id/messages/:message_id", %{ + conn: conn, + chat: chat, + cm_ref: cm_ref + } do + conn + |> put_req_header("content-type", "application/json") + |> delete("/api/pleroma/admin/chats/#{chat.id}/messages/#{cm_ref.id}") + |> json_response(403) + + assert MessageReference.get_by_id(cm_ref.id) == cm_ref + end + + test "GET /api/pleroma/admin/chats/:id/messages", %{conn: conn, chat: chat} do + conn + |> get("/api/pleroma/admin/chats/#{chat.id}/messages") + |> json_response(403) + end + + test "GET /api/pleroma/admin/chats/:id", %{conn: conn, chat: chat} do + conn + |> get("/api/pleroma/admin/chats/#{chat.id}") + |> json_response(403) + end + end + + describe "unauthenticated chat moderation" do + setup do + user = insert(:user) + recipient = insert(:user) + + {:ok, message} = CommonAPI.post_chat_message(user, recipient, "Yo") + object = Object.normalize(message, fetch: false) + chat = Chat.get(user.id, recipient.ap_id) + cm_ref = MessageReference.for_chat_and_object(chat, object) + + %{conn: build_conn(), chat: chat, cm_ref: cm_ref} + end + + test "DELETE /api/pleroma/admin/chats/:id/messages/:message_id", %{ + conn: conn, + chat: chat, + cm_ref: cm_ref + } do + conn + |> put_req_header("content-type", "application/json") + |> delete("/api/pleroma/admin/chats/#{chat.id}/messages/#{cm_ref.id}") + |> json_response(403) + + assert MessageReference.get_by_id(cm_ref.id) == cm_ref + end + + test "GET /api/pleroma/admin/chats/:id/messages", %{conn: conn, chat: chat} do + conn + |> get("/api/pleroma/admin/chats/#{chat.id}/messages") + |> json_response(403) + end + + test "GET /api/pleroma/admin/chats/:id", %{conn: conn, chat: chat} do + conn + |> get("/api/pleroma/admin/chats/#{chat.id}") + |> json_response(403) + end + end +end diff --git a/test/web/admin_api/controllers/config_controller_test.exs b/test/pleroma/web/admin_api/controllers/config_controller_test.exs index 4e897455f..7c786c389 100644 --- a/test/web/admin_api/controllers/config_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/config_controller_test.exs @@ -1,14 +1,13 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do - use Pleroma.Web.ConnCase, async: true + use Pleroma.Web.ConnCase import ExUnit.CaptureLog import Pleroma.Factory - alias Pleroma.Config alias Pleroma.ConfigDB setup do @@ -27,12 +26,12 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do setup do: clear_config(:configurable_from_database, true) test "when configuration from database is off", %{conn: conn} do - Config.put(:configurable_from_database, false) + clear_config(:configurable_from_database, false) conn = get(conn, "/api/pleroma/admin/config") assert json_response_and_validate_schema(conn, 400) == %{ - "error" => "To use this endpoint you need to enable configuration from database." + "error" => "You must enable configurable_from_database in your config file." } end @@ -162,14 +161,16 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do end end - test "POST /api/pleroma/admin/config error", %{conn: conn} do + test "POST /api/pleroma/admin/config with configdb disabled", %{conn: conn} do + clear_config(:configurable_from_database, false) + conn = conn |> put_req_header("content-type", "application/json") |> post("/api/pleroma/admin/config", %{"configs" => []}) assert json_response_and_validate_schema(conn, 400) == - %{"error" => "To use this endpoint you need to enable configuration from database."} + %{"error" => "You must enable configurable_from_database in your config file."} end describe "POST /api/pleroma/admin/config" do @@ -408,8 +409,7 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do end test "saving config which need pleroma reboot", %{conn: conn} do - chat = Config.get(:chat) - on_exit(fn -> Config.put(:chat, chat) end) + clear_config([:shout, :enabled], true) assert conn |> put_req_header("content-type", "application/json") @@ -417,7 +417,7 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do "/api/pleroma/admin/config", %{ configs: [ - %{group: ":pleroma", key: ":chat", value: [%{"tuple" => [":enabled", true]}]} + %{group: ":pleroma", key: ":shout", value: [%{"tuple" => [":enabled", true]}]} ] } ) @@ -426,7 +426,7 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do %{ "db" => [":enabled"], "group" => ":pleroma", - "key" => ":chat", + "key" => ":shout", "value" => [%{"tuple" => [":enabled", true]}] } ], @@ -454,8 +454,7 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do end test "update setting which need reboot, don't change reboot flag until reboot", %{conn: conn} do - chat = Config.get(:chat) - on_exit(fn -> Config.put(:chat, chat) end) + clear_config([:shout, :enabled], true) assert conn |> put_req_header("content-type", "application/json") @@ -463,7 +462,7 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do "/api/pleroma/admin/config", %{ configs: [ - %{group: ":pleroma", key: ":chat", value: [%{"tuple" => [":enabled", true]}]} + %{group: ":pleroma", key: ":shout", value: [%{"tuple" => [":enabled", true]}]} ] } ) @@ -472,7 +471,7 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do %{ "db" => [":enabled"], "group" => ":pleroma", - "key" => ":chat", + "key" => ":shout", "value" => [%{"tuple" => [":enabled", true]}] } ], @@ -1411,15 +1410,84 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do "need_reboot" => false } end + + test "custom instance thumbnail", %{conn: conn} do + clear_config([:instance]) + + params = %{ + "group" => ":pleroma", + "key" => ":instance", + "value" => [ + %{ + "tuple" => [ + ":instance_thumbnail", + "https://example.com/media/new_thumbnail.jpg" + ] + } + ] + } + + assert conn + |> put_req_header("content-type", "application/json") + |> post("/api/pleroma/admin/config", %{"configs" => [params]}) + |> json_response_and_validate_schema(200) == + %{ + "configs" => [ + %{ + "db" => [":instance_thumbnail"], + "group" => ":pleroma", + "key" => ":instance", + "value" => params["value"] + } + ], + "need_reboot" => false + } + + assert conn + |> get("/api/v1/instance") + |> json_response_and_validate_schema(200) + |> Map.take(["thumbnail"]) == + %{"thumbnail" => "https://example.com/media/new_thumbnail.jpg"} + end + + test "Concurrent Limiter", %{conn: conn} do + clear_config([ConcurrentLimiter]) + + params = %{ + "group" => ":pleroma", + "key" => "ConcurrentLimiter", + "value" => [ + %{ + "tuple" => [ + "Pleroma.Web.RichMedia.Helpers", + [ + %{"tuple" => [":max_running", 6]}, + %{"tuple" => [":max_waiting", 6]} + ] + ] + }, + %{ + "tuple" => [ + "Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy", + [ + %{"tuple" => [":max_running", 7]}, + %{"tuple" => [":max_waiting", 7]} + ] + ] + } + ] + } + + assert conn + |> put_req_header("content-type", "application/json") + |> post("/api/pleroma/admin/config", %{"configs" => [params]}) + |> json_response_and_validate_schema(200) + end end describe "GET /api/pleroma/admin/config/descriptions" do test "structure", %{conn: conn} do - admin = insert(:user, is_admin: true) - - conn = - assign(conn, :user, admin) - |> get("/api/pleroma/admin/config/descriptions") + conn = get(conn, "/api/pleroma/admin/config/descriptions") assert [child | _others] = json_response_and_validate_schema(conn, 200) @@ -1437,11 +1505,7 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do {:esshd} ]) - admin = insert(:user, is_admin: true) - - conn = - assign(conn, :user, admin) - |> get("/api/pleroma/admin/config/descriptions") + conn = get(conn, "/api/pleroma/admin/config/descriptions") children = json_response_and_validate_schema(conn, 200) diff --git a/test/pleroma/web/admin_api/controllers/frontend_controller_test.exs b/test/pleroma/web/admin_api/controllers/frontend_controller_test.exs new file mode 100644 index 000000000..200682ba9 --- /dev/null +++ b/test/pleroma/web/admin_api/controllers/frontend_controller_test.exs @@ -0,0 +1,155 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.AdminAPI.FrontendControllerTest do + use Pleroma.Web.ConnCase + + import Pleroma.Factory + + alias Pleroma.Config + + @dir "test/frontend_static_test" + + setup do + clear_config([:instance, :static_dir], @dir) + File.mkdir_p!(Pleroma.Frontend.dir()) + + on_exit(fn -> + File.rm_rf(@dir) + end) + + admin = insert(:user, is_admin: true) + token = insert(:oauth_admin_token, user: admin) + + conn = + build_conn() + |> assign(:user, admin) + |> assign(:token, token) + + {:ok, %{admin: admin, token: token, conn: conn}} + end + + describe "GET /api/pleroma/admin/frontends" do + test "it lists available frontends", %{conn: conn} do + response = + conn + |> get("/api/pleroma/admin/frontends") + |> json_response_and_validate_schema(:ok) + + assert Enum.map(response, & &1["name"]) == + Enum.map(Config.get([:frontends, :available]), fn {_, map} -> map["name"] end) + + refute Enum.any?(response, fn frontend -> frontend["installed"] == true end) + end + + test "it lists available frontends when no frontend folder was created yet", %{conn: conn} do + File.rm_rf(@dir) + + response = + conn + |> get("/api/pleroma/admin/frontends") + |> json_response_and_validate_schema(:ok) + + assert Enum.map(response, & &1["name"]) == + Enum.map(Config.get([:frontends, :available]), fn {_, map} -> map["name"] end) + + refute Enum.any?(response, fn frontend -> frontend["installed"] == true end) + end + end + + describe "POST /api/pleroma/admin/frontends/install" do + test "from available frontends", %{conn: conn} do + clear_config([:frontends, :available], %{ + "pleroma" => %{ + "ref" => "fantasy", + "name" => "pleroma", + "build_url" => "http://gensokyo.2hu/builds/${ref}" + } + }) + + Tesla.Mock.mock(fn %{url: "http://gensokyo.2hu/builds/fantasy"} -> + %Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/frontend_dist.zip")} + end) + + conn + |> put_req_header("content-type", "application/json") + |> post("/api/pleroma/admin/frontends/install", %{name: "pleroma"}) + |> json_response_and_validate_schema(:ok) + + assert File.exists?(Path.join([@dir, "frontends", "pleroma", "fantasy", "test.txt"])) + + response = + conn + |> get("/api/pleroma/admin/frontends") + |> json_response_and_validate_schema(:ok) + + assert response == [ + %{ + "build_url" => "http://gensokyo.2hu/builds/${ref}", + "git" => nil, + "installed" => true, + "name" => "pleroma", + "ref" => "fantasy" + } + ] + end + + test "from a file", %{conn: conn} do + clear_config([:frontends, :available], %{ + "pleroma" => %{ + "ref" => "fantasy", + "name" => "pleroma", + "build_dir" => "" + } + }) + + conn + |> put_req_header("content-type", "application/json") + |> post("/api/pleroma/admin/frontends/install", %{ + name: "pleroma", + file: "test/fixtures/tesla_mock/frontend.zip" + }) + |> json_response_and_validate_schema(:ok) + + assert File.exists?(Path.join([@dir, "frontends", "pleroma", "fantasy", "test.txt"])) + end + + test "from an URL", %{conn: conn} do + Tesla.Mock.mock(fn %{url: "http://gensokyo.2hu/madeup.zip"} -> + %Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/frontend.zip")} + end) + + conn + |> put_req_header("content-type", "application/json") + |> post("/api/pleroma/admin/frontends/install", %{ + name: "unknown", + ref: "baka", + build_url: "http://gensokyo.2hu/madeup.zip", + build_dir: "" + }) + |> json_response_and_validate_schema(:ok) + + assert File.exists?(Path.join([@dir, "frontends", "unknown", "baka", "test.txt"])) + end + + test "failing returns an error", %{conn: conn} do + Tesla.Mock.mock(fn %{url: "http://gensokyo.2hu/madeup.zip"} -> + %Tesla.Env{status: 404, body: ""} + end) + + result = + conn + |> put_req_header("content-type", "application/json") + |> post("/api/pleroma/admin/frontends/install", %{ + name: "unknown", + ref: "baka", + build_url: "http://gensokyo.2hu/madeup.zip", + build_dir: "" + }) + |> json_response_and_validate_schema(400) + + assert result == %{"error" => "Could not download or unzip the frontend"} + end + end +end diff --git a/test/pleroma/web/admin_api/controllers/instance_controller_test.exs b/test/pleroma/web/admin_api/controllers/instance_controller_test.exs new file mode 100644 index 000000000..c78307fc8 --- /dev/null +++ b/test/pleroma/web/admin_api/controllers/instance_controller_test.exs @@ -0,0 +1,80 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.AdminAPI.InstanceControllerTest do + use Pleroma.Web.ConnCase + use Oban.Testing, repo: Pleroma.Repo + + import Pleroma.Factory + + alias Pleroma.Repo + alias Pleroma.Tests.ObanHelpers + alias Pleroma.Web.CommonAPI + + setup_all do + Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) + + :ok + end + + setup do + admin = insert(:user, is_admin: true) + token = insert(:oauth_admin_token, user: admin) + + conn = + build_conn() + |> assign(:user, admin) + |> assign(:token, token) + + {:ok, %{admin: admin, token: token, conn: conn}} + end + + test "GET /instances/:instance/statuses", %{conn: conn} do + user = insert(:user, local: false, ap_id: "https://archae.me/users/archaeme") + user2 = insert(:user, local: false, ap_id: "https://test.com/users/test") + insert_pair(:note_activity, user: user) + activity = insert(:note_activity, user: user2) + + %{"total" => 2, "activities" => activities} = + conn |> get("/api/pleroma/admin/instances/archae.me/statuses") |> json_response(200) + + assert length(activities) == 2 + + %{"total" => 1, "activities" => [_]} = + conn |> get("/api/pleroma/admin/instances/test.com/statuses") |> json_response(200) + + %{"total" => 0, "activities" => []} = + conn |> get("/api/pleroma/admin/instances/nonexistent.com/statuses") |> json_response(200) + + CommonAPI.repeat(activity.id, user) + + %{"total" => 2, "activities" => activities} = + conn |> get("/api/pleroma/admin/instances/archae.me/statuses") |> json_response(200) + + assert length(activities) == 2 + + %{"total" => 3, "activities" => activities} = + conn + |> get("/api/pleroma/admin/instances/archae.me/statuses?with_reblogs=true") + |> json_response(200) + + assert length(activities) == 3 + end + + test "DELETE /instances/:instance", %{conn: conn} do + user = insert(:user, nickname: "lain@lain.com") + post = insert(:note_activity, user: user) + + response = + conn + |> delete("/api/pleroma/admin/instances/lain.com") + |> json_response(200) + + [:ok] = ObanHelpers.perform_all() + + assert response == "lain.com" + refute Repo.reload(user).is_active + refute Repo.reload(post) + end +end diff --git a/test/pleroma/web/admin_api/controllers/instance_document_controller_test.exs b/test/pleroma/web/admin_api/controllers/instance_document_controller_test.exs new file mode 100644 index 000000000..e100f6929 --- /dev/null +++ b/test/pleroma/web/admin_api/controllers/instance_document_controller_test.exs @@ -0,0 +1,105 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.AdminAPI.InstanceDocumentControllerTest do + use Pleroma.Web.ConnCase, async: true + import Pleroma.Factory + + @dir "test/tmp/instance_static" + @default_instance_panel ~s(<p>Welcome to <a href="https://pleroma.social" target="_blank">Pleroma!</a></p>) + + setup do + File.mkdir_p!(@dir) + on_exit(fn -> File.rm_rf(@dir) end) + end + + setup do: clear_config([:instance, :static_dir], @dir) + + setup do + admin = insert(:user, is_admin: true) + token = insert(:oauth_admin_token, user: admin) + + conn = + build_conn() + |> assign(:user, admin) + |> assign(:token, token) + + {:ok, %{admin: admin, token: token, conn: conn}} + end + + describe "GET /api/pleroma/admin/instance_document/:name" do + test "return the instance document url", %{conn: conn} do + conn = get(conn, "/api/pleroma/admin/instance_document/instance-panel") + + assert content = html_response(conn, 200) + assert String.contains?(content, @default_instance_panel) + end + + test "it returns 403 if requested by a non-admin" do + non_admin_user = insert(:user) + token = insert(:oauth_token, user: non_admin_user) + + conn = + build_conn() + |> assign(:user, non_admin_user) + |> assign(:token, token) + |> get("/api/pleroma/admin/instance_document/instance-panel") + + assert json_response(conn, :forbidden) + end + + test "it returns 404 if the instance document with the given name doesn't exist", %{ + conn: conn + } do + conn = get(conn, "/api/pleroma/admin/instance_document/1234") + + assert json_response_and_validate_schema(conn, 404) + end + end + + describe "PATCH /api/pleroma/admin/instance_document/:name" do + test "uploads the instance document", %{conn: conn} do + image = %Plug.Upload{ + content_type: "text/html", + path: Path.absname("test/fixtures/custom_instance_panel.html"), + filename: "custom_instance_panel.html" + } + + conn = + conn + |> put_req_header("content-type", "multipart/form-data") + |> patch("/api/pleroma/admin/instance_document/instance-panel", %{ + "file" => image + }) + + assert %{"url" => url} = json_response_and_validate_schema(conn, 200) + index = get(build_conn(), url) + assert html_response(index, 200) == "<h2>Custom instance panel</h2>" + end + end + + describe "DELETE /api/pleroma/admin/instance_document/:name" do + test "deletes the instance document", %{conn: conn} do + File.mkdir!(@dir <> "/instance/") + File.write!(@dir <> "/instance/panel.html", "Custom instance panel") + + conn_resp = + conn + |> get("/api/pleroma/admin/instance_document/instance-panel") + + assert html_response(conn_resp, 200) == "Custom instance panel" + + conn + |> delete("/api/pleroma/admin/instance_document/instance-panel") + |> json_response_and_validate_schema(200) + + conn_resp = + conn + |> get("/api/pleroma/admin/instance_document/instance-panel") + + assert content = html_response(conn_resp, 200) + assert String.contains?(content, @default_instance_panel) + end + end +end diff --git a/test/web/admin_api/controllers/invite_controller_test.exs b/test/pleroma/web/admin_api/controllers/invite_controller_test.exs index ab186c5e7..6366061c8 100644 --- a/test/web/admin_api/controllers/invite_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/invite_controller_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.AdminAPI.InviteControllerTest do @@ -7,7 +7,6 @@ defmodule Pleroma.Web.AdminAPI.InviteControllerTest do import Pleroma.Factory - alias Pleroma.Config alias Pleroma.Repo alias Pleroma.UserInviteToken @@ -119,8 +118,8 @@ defmodule Pleroma.Web.AdminAPI.InviteControllerTest do setup do: clear_config([:instance, :invites_enabled]) test "it returns 500 if `invites_enabled` is not enabled", %{conn: conn} do - Config.put([:instance, :registrations_open], false) - Config.put([:instance, :invites_enabled], false) + clear_config([:instance, :registrations_open], false) + clear_config([:instance, :invites_enabled], false) conn = conn @@ -138,8 +137,8 @@ defmodule Pleroma.Web.AdminAPI.InviteControllerTest do end test "it returns 500 if `registrations_open` is enabled", %{conn: conn} do - Config.put([:instance, :registrations_open], true) - Config.put([:instance, :invites_enabled], true) + clear_config([:instance, :registrations_open], true) + clear_config([:instance, :invites_enabled], true) conn = conn diff --git a/test/web/admin_api/controllers/media_proxy_cache_controller_test.exs b/test/pleroma/web/admin_api/controllers/media_proxy_cache_controller_test.exs index f243d1fb2..1818c8a8e 100644 --- a/test/web/admin_api/controllers/media_proxy_cache_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/media_proxy_cache_controller_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.AdminAPI.MediaProxyCacheControllerTest do @@ -13,10 +13,6 @@ defmodule Pleroma.Web.AdminAPI.MediaProxyCacheControllerTest do setup do: clear_config([:media_proxy]) setup do - on_exit(fn -> Cachex.clear(:banned_urls_cache) end) - end - - setup do admin = insert(:user, is_admin: true) token = insert(:oauth_admin_token, user: admin) @@ -25,9 +21,9 @@ defmodule Pleroma.Web.AdminAPI.MediaProxyCacheControllerTest do |> assign(:user, admin) |> assign(:token, token) - Config.put([:media_proxy, :enabled], true) - Config.put([:media_proxy, :invalidation, :enabled], true) - Config.put([:media_proxy, :invalidation, :provider], MediaProxy.Invalidation.Script) + clear_config([:media_proxy, :enabled], true) + clear_config([:media_proxy, :invalidation, :enabled], true) + clear_config([:media_proxy, :invalidation, :provider], MediaProxy.Invalidation.Script) {:ok, %{admin: admin, token: token, conn: conn}} end @@ -51,30 +47,34 @@ defmodule Pleroma.Web.AdminAPI.MediaProxyCacheControllerTest do assert response["page_size"] == 2 assert response["count"] == 5 - assert response["urls"] == [ - "http://localhost:4001/media/fb1f4d.jpg", - "http://localhost:4001/media/a688346.jpg" - ] + results = response["urls"] response = conn |> get("/api/pleroma/admin/media_proxy_caches?page_size=2&page=2") |> json_response_and_validate_schema(200) - assert response["urls"] == [ - "http://localhost:4001/media/gb1f44.jpg", - "http://localhost:4001/media/tb13f47.jpg" - ] - assert response["page_size"] == 2 assert response["count"] == 5 + results = results ++ response["urls"] + response = conn |> get("/api/pleroma/admin/media_proxy_caches?page_size=2&page=3") |> json_response_and_validate_schema(200) - assert response["urls"] == ["http://localhost:4001/media/wb1f46.jpg"] + results = results ++ response["urls"] + + assert results |> Enum.sort() == + [ + "http://localhost:4001/media/wb1f46.jpg", + "http://localhost:4001/media/gb1f44.jpg", + "http://localhost:4001/media/tb13f47.jpg", + "http://localhost:4001/media/fb1f4d.jpg", + "http://localhost:4001/media/a688346.jpg" + ] + |> Enum.sort() end test "search banned MediaProxy URLs", %{conn: conn} do @@ -92,9 +92,9 @@ defmodule Pleroma.Web.AdminAPI.MediaProxyCacheControllerTest do |> get("/api/pleroma/admin/media_proxy_caches?page_size=2&query=F44") |> json_response_and_validate_schema(200) - assert response["urls"] == [ - "http://localhost:4001/media/gb1f44.jpg", - "http://localhost:4001/media/ff44b1f4d.jpg" + assert response["urls"] |> Enum.sort() == [ + "http://localhost:4001/media/ff44b1f4d.jpg", + "http://localhost:4001/media/gb1f44.jpg" ] assert response["page_size"] == 2 diff --git a/test/web/admin_api/controllers/oauth_app_controller_test.exs b/test/pleroma/web/admin_api/controllers/o_auth_app_controller_test.exs index ed7c4172c..d9b25719a 100644 --- a/test/web/admin_api/controllers/oauth_app_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/o_auth_app_controller_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.AdminAPI.OAuthAppControllerTest do @@ -8,8 +8,7 @@ defmodule Pleroma.Web.AdminAPI.OAuthAppControllerTest do import Pleroma.Factory - alias Pleroma.Config - alias Pleroma.Web + alias Pleroma.Web.Endpoint setup do admin = insert(:user, is_admin: true) @@ -37,7 +36,7 @@ defmodule Pleroma.Web.AdminAPI.OAuthAppControllerTest do end test "success", %{conn: conn} do - base_url = Web.base_url() + base_url = Endpoint.url() app_name = "Trusted app" response = @@ -59,7 +58,7 @@ defmodule Pleroma.Web.AdminAPI.OAuthAppControllerTest do end test "with trusted", %{conn: conn} do - base_url = Web.base_url() + base_url = Endpoint.url() app_name = "Trusted app" response = diff --git a/test/web/admin_api/controllers/relay_controller_test.exs b/test/pleroma/web/admin_api/controllers/relay_controller_test.exs index adadf2b5c..11a480cc0 100644 --- a/test/web/admin_api/controllers/relay_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/relay_controller_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.AdminAPI.RelayControllerTest do @@ -7,7 +7,6 @@ defmodule Pleroma.Web.AdminAPI.RelayControllerTest do import Pleroma.Factory - alias Pleroma.Config alias Pleroma.ModerationLog alias Pleroma.Repo alias Pleroma.User @@ -61,7 +60,7 @@ defmodule Pleroma.Web.AdminAPI.RelayControllerTest do conn = get(conn, "/api/pleroma/admin/relay") - assert json_response_and_validate_schema(conn, 200)["relays"] == [ + assert json_response_and_validate_schema(conn, 200)["relays"] |> Enum.sort() == [ %{ "actor" => "http://mastodon.example.org/users/admin", "followed_back" => true diff --git a/test/web/admin_api/controllers/report_controller_test.exs b/test/pleroma/web/admin_api/controllers/report_controller_test.exs index 57946e6bb..99cc7bbd0 100644 --- a/test/web/admin_api/controllers/report_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/report_controller_test.exs @@ -1,14 +1,13 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.AdminAPI.ReportControllerTest do - use Pleroma.Web.ConnCase + use Pleroma.Web.ConnCase, async: true import Pleroma.Factory alias Pleroma.Activity - alias Pleroma.Config alias Pleroma.ModerationLog alias Pleroma.Repo alias Pleroma.ReportNote @@ -38,12 +37,21 @@ defmodule Pleroma.Web.AdminAPI.ReportControllerTest do status_ids: [activity.id] }) + conn + |> put_req_header("content-type", "application/json") + |> post("/api/pleroma/admin/reports/#{report_id}/notes", %{ + content: "this is an admin note" + }) + response = conn |> get("/api/pleroma/admin/reports/#{report_id}") |> json_response_and_validate_schema(:ok) assert response["id"] == report_id + + [notes] = response["notes"] + assert notes["content"] == "this is an admin note" end test "returns 404 when report id is invalid", %{conn: conn} do @@ -114,13 +122,13 @@ defmodule Pleroma.Web.AdminAPI.ReportControllerTest do }) |> json_response_and_validate_schema(:no_content) - activity = Activity.get_by_id(id) + activity = Activity.get_by_id_with_user_actor(id) assert activity.data["state"] == "resolved" log_entry = Repo.one(ModerationLog) assert ModerationLog.get_log_entry_message(log_entry) == - "@#{admin.nickname} updated report ##{id} with 'resolved' state" + "@#{admin.nickname} updated report ##{id} (on user @#{activity.user_actor.nickname}) with 'resolved' state" end test "closes report", %{conn: conn, id: id, admin: admin} do @@ -133,13 +141,13 @@ defmodule Pleroma.Web.AdminAPI.ReportControllerTest do }) |> json_response_and_validate_schema(:no_content) - activity = Activity.get_by_id(id) + activity = Activity.get_by_id_with_user_actor(id) assert activity.data["state"] == "closed" log_entry = Repo.one(ModerationLog) assert ModerationLog.get_log_entry_message(log_entry) == - "@#{admin.nickname} updated report ##{id} with 'closed' state" + "@#{admin.nickname} updated report ##{id} (on user @#{activity.user_actor.nickname}) with 'closed' state" end test "returns 400 when state is unknown", %{conn: conn, id: id} do @@ -185,18 +193,18 @@ defmodule Pleroma.Web.AdminAPI.ReportControllerTest do }) |> json_response_and_validate_schema(:no_content) - activity = Activity.get_by_id(id) - second_activity = Activity.get_by_id(second_report_id) + activity = Activity.get_by_id_with_user_actor(id) + second_activity = Activity.get_by_id_with_user_actor(second_report_id) assert activity.data["state"] == "resolved" assert second_activity.data["state"] == "closed" [first_log_entry, second_log_entry] = Repo.all(ModerationLog) assert ModerationLog.get_log_entry_message(first_log_entry) == - "@#{admin.nickname} updated report ##{id} with 'resolved' state" + "@#{admin.nickname} updated report ##{id} (on user @#{activity.user_actor.nickname}) with 'resolved' state" assert ModerationLog.get_log_entry_message(second_log_entry) == - "@#{admin.nickname} updated report ##{second_report_id} with 'closed' state" + "@#{admin.nickname} updated report ##{second_report_id} (on user @#{second_activity.user_actor.nickname}) with 'closed' state" end end @@ -295,7 +303,7 @@ defmodule Pleroma.Web.AdminAPI.ReportControllerTest do |> get("/api/pleroma/admin/reports") assert json_response(conn, :forbidden) == - %{"error" => "User is not an admin."} + %{"error" => "User is not a staff member."} end test "returns 403 when requested by anonymous" do diff --git a/test/web/admin_api/controllers/status_controller_test.exs b/test/pleroma/web/admin_api/controllers/status_controller_test.exs index eff78fb0a..3fdf23ba2 100644 --- a/test/web/admin_api/controllers/status_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/status_controller_test.exs @@ -1,14 +1,13 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.AdminAPI.StatusControllerTest do - use Pleroma.Web.ConnCase + use Pleroma.Web.ConnCase, async: true import Pleroma.Factory alias Pleroma.Activity - alias Pleroma.Config alias Pleroma.ModerationLog alias Pleroma.Repo alias Pleroma.User @@ -48,8 +47,8 @@ defmodule Pleroma.Web.AdminAPI.StatusControllerTest do assert account["id"] == actor.id assert account["nickname"] == actor.nickname - assert account["deactivated"] == actor.deactivated - assert account["confirmation_pending"] == actor.confirmation_pending + assert account["is_active"] == actor.is_active + assert account["is_confirmed"] == actor.is_confirmed end end diff --git a/test/pleroma/web/admin_api/controllers/user_controller_test.exs b/test/pleroma/web/admin_api/controllers/user_controller_test.exs new file mode 100644 index 000000000..b199fa704 --- /dev/null +++ b/test/pleroma/web/admin_api/controllers/user_controller_test.exs @@ -0,0 +1,967 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.AdminAPI.UserControllerTest do + use Pleroma.Web.ConnCase + use Oban.Testing, repo: Pleroma.Repo + + import Mock + import Pleroma.Factory + + alias Pleroma.HTML + alias Pleroma.ModerationLog + alias Pleroma.Repo + alias Pleroma.Tests.ObanHelpers + alias Pleroma.User + alias Pleroma.Web.ActivityPub.Relay + alias Pleroma.Web.CommonAPI + alias Pleroma.Web.Endpoint + alias Pleroma.Web.MediaProxy + + setup_all do + Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) + + :ok + end + + setup do + admin = insert(:user, is_admin: true) + token = insert(:oauth_admin_token, user: admin) + + conn = + build_conn() + |> assign(:user, admin) + |> assign(:token, token) + + {:ok, %{admin: admin, token: token, conn: conn}} + end + + test "with valid `admin_token` query parameter, skips OAuth scopes check" do + clear_config([:admin_token], "password123") + + user = insert(:user) + + conn = get(build_conn(), "/api/pleroma/admin/users/#{user.nickname}?admin_token=password123") + + assert json_response_and_validate_schema(conn, 200) + end + + test "GET /api/pleroma/admin/users/:nickname requires admin:read:accounts or broader scope", + %{admin: admin} do + user = insert(:user) + url = "/api/pleroma/admin/users/#{user.nickname}" + + good_token1 = insert(:oauth_token, user: admin, scopes: ["admin"]) + good_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read"]) + good_token3 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts"]) + + bad_token1 = insert(:oauth_token, user: admin, scopes: ["read:accounts"]) + bad_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts:partial"]) + bad_token3 = nil + + for good_token <- [good_token1, good_token2, good_token3] do + conn = + build_conn() + |> assign(:user, admin) + |> assign(:token, good_token) + |> get(url) + + assert json_response_and_validate_schema(conn, 200) + end + + for good_token <- [good_token1, good_token2, good_token3] do + conn = + build_conn() + |> assign(:user, nil) + |> assign(:token, good_token) + |> get(url) + + assert json_response(conn, :forbidden) + end + + for bad_token <- [bad_token1, bad_token2, bad_token3] do + conn = + build_conn() + |> assign(:user, admin) + |> assign(:token, bad_token) + |> get(url) + + assert json_response_and_validate_schema(conn, :forbidden) + end + end + + describe "DELETE /api/pleroma/admin/users" do + test "single user", %{admin: admin, conn: conn} do + clear_config([:instance, :federating], true) + + user = + insert(:user, + avatar: %{"url" => [%{"href" => "https://someurl"}]}, + banner: %{"url" => [%{"href" => "https://somebanner"}]}, + bio: "Hello world!", + name: "A guy" + ) + + # Create some activities to check they got deleted later + follower = insert(:user) + {:ok, _} = CommonAPI.post(user, %{status: "test"}) + {:ok, _, _, _} = CommonAPI.follow(user, follower) + {:ok, _, _, _} = CommonAPI.follow(follower, user) + user = Repo.get(User, user.id) + assert user.note_count == 1 + assert user.follower_count == 1 + assert user.following_count == 1 + assert user.is_active + + with_mock Pleroma.Web.Federator, + publish: fn _ -> nil end, + perform: fn _, _ -> nil end do + conn = + conn + |> put_req_header("accept", "application/json") + |> delete("/api/pleroma/admin/users?nickname=#{user.nickname}") + + ObanHelpers.perform_all() + + refute User.get_by_nickname(user.nickname).is_active + + log_entry = Repo.one(ModerationLog) + + assert ModerationLog.get_log_entry_message(log_entry) == + "@#{admin.nickname} deleted users: @#{user.nickname}" + + assert json_response_and_validate_schema(conn, 200) == [user.nickname] + + user = Repo.get(User, user.id) + refute user.is_active + + assert user.avatar == %{} + assert user.banner == %{} + assert user.note_count == 0 + assert user.follower_count == 0 + assert user.following_count == 0 + assert user.bio == "" + assert user.name == nil + + assert called(Pleroma.Web.Federator.publish(:_)) + end + end + + test "multiple users", %{admin: admin, conn: conn} do + user_one = insert(:user) + user_two = insert(:user) + + response = + conn + |> put_req_header("accept", "application/json") + |> put_req_header("content-type", "application/json") + |> delete("/api/pleroma/admin/users", %{ + nicknames: [user_one.nickname, user_two.nickname] + }) + |> json_response_and_validate_schema(200) + + log_entry = Repo.one(ModerationLog) + + assert ModerationLog.get_log_entry_message(log_entry) == + "@#{admin.nickname} deleted users: @#{user_one.nickname}, @#{user_two.nickname}" + + assert response -- [user_one.nickname, user_two.nickname] == [] + end + end + + describe "/api/pleroma/admin/users" do + test "Create", %{conn: conn} do + response = + conn + |> put_req_header("accept", "application/json") + |> put_req_header("content-type", "application/json") + |> post("/api/pleroma/admin/users", %{ + "users" => [ + %{ + "nickname" => "lain", + "email" => "lain@example.org", + "password" => "test" + }, + %{ + "nickname" => "lain2", + "email" => "lain2@example.org", + "password" => "test" + } + ] + }) + |> json_response_and_validate_schema(200) + |> Enum.map(&Map.get(&1, "type")) + + assert response == ["success", "success"] + + log_entry = Repo.one(ModerationLog) + + assert ["lain", "lain2"] -- Enum.map(log_entry.data["subjects"], & &1["nickname"]) == [] + end + + test "Cannot create user with existing email", %{conn: conn} do + user = insert(:user) + + conn = + conn + |> put_req_header("accept", "application/json") + |> put_req_header("content-type", "application/json") + |> post("/api/pleroma/admin/users", %{ + "users" => [ + %{ + "nickname" => "lain", + "email" => user.email, + "password" => "test" + } + ] + }) + + assert json_response_and_validate_schema(conn, 409) == [ + %{ + "code" => 409, + "data" => %{ + "email" => user.email, + "nickname" => "lain" + }, + "error" => "email has already been taken", + "type" => "error" + } + ] + end + + test "Cannot create user with existing nickname", %{conn: conn} do + user = insert(:user) + + conn = + conn + |> put_req_header("accept", "application/json") + |> put_req_header("content-type", "application/json") + |> post("/api/pleroma/admin/users", %{ + "users" => [ + %{ + "nickname" => user.nickname, + "email" => "someuser@plerama.social", + "password" => "test" + } + ] + }) + + assert json_response_and_validate_schema(conn, 409) == [ + %{ + "code" => 409, + "data" => %{ + "email" => "someuser@plerama.social", + "nickname" => user.nickname + }, + "error" => "nickname has already been taken", + "type" => "error" + } + ] + end + + test "Multiple user creation works in transaction", %{conn: conn} do + user = insert(:user) + + conn = + conn + |> put_req_header("accept", "application/json") + |> put_req_header("content-type", "application/json") + |> post("/api/pleroma/admin/users", %{ + "users" => [ + %{ + "nickname" => "newuser", + "email" => "newuser@pleroma.social", + "password" => "test" + }, + %{ + "nickname" => "lain", + "email" => user.email, + "password" => "test" + } + ] + }) + + assert json_response_and_validate_schema(conn, 409) == [ + %{ + "code" => 409, + "data" => %{ + "email" => user.email, + "nickname" => "lain" + }, + "error" => "email has already been taken", + "type" => "error" + }, + %{ + "code" => 409, + "data" => %{ + "email" => "newuser@pleroma.social", + "nickname" => "newuser" + }, + "error" => "", + "type" => "error" + } + ] + + assert User.get_by_nickname("newuser") === nil + end + end + + describe "/api/pleroma/admin/users/:nickname" do + test "Show", %{conn: conn} do + user = insert(:user) + + conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}") + + assert user_response(user) == json_response_and_validate_schema(conn, 200) + end + + test "when the user doesn't exist", %{conn: conn} do + user = build(:user) + + conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}") + + assert %{"error" => "Not found"} == json_response_and_validate_schema(conn, 404) + end + end + + describe "/api/pleroma/admin/users/follow" do + test "allows to force-follow another user", %{admin: admin, conn: conn} do + user = insert(:user) + follower = insert(:user) + + conn + |> put_req_header("accept", "application/json") + |> put_req_header("content-type", "application/json") + |> post("/api/pleroma/admin/users/follow", %{ + "follower" => follower.nickname, + "followed" => user.nickname + }) + + user = User.get_cached_by_id(user.id) + follower = User.get_cached_by_id(follower.id) + + assert User.following?(follower, user) + + log_entry = Repo.one(ModerationLog) + + assert ModerationLog.get_log_entry_message(log_entry) == + "@#{admin.nickname} made @#{follower.nickname} follow @#{user.nickname}" + end + end + + describe "/api/pleroma/admin/users/unfollow" do + test "allows to force-unfollow another user", %{admin: admin, conn: conn} do + user = insert(:user) + follower = insert(:user) + + User.follow(follower, user) + + conn + |> put_req_header("accept", "application/json") + |> put_req_header("content-type", "application/json") + |> post("/api/pleroma/admin/users/unfollow", %{ + "follower" => follower.nickname, + "followed" => user.nickname + }) + + user = User.get_cached_by_id(user.id) + follower = User.get_cached_by_id(follower.id) + + refute User.following?(follower, user) + + log_entry = Repo.one(ModerationLog) + + assert ModerationLog.get_log_entry_message(log_entry) == + "@#{admin.nickname} made @#{follower.nickname} unfollow @#{user.nickname}" + end + end + + describe "GET /api/pleroma/admin/users" do + test "renders users array for the first page", %{conn: conn, admin: admin} do + user = insert(:user, local: false, tags: ["foo", "bar"]) + user2 = insert(:user, is_approved: false, registration_reason: "I'm a chill dude") + + conn = get(conn, "/api/pleroma/admin/users?page=1") + + users = [ + user_response( + user2, + %{ + "local" => true, + "is_approved" => false, + "registration_reason" => "I'm a chill dude", + "actor_type" => "Person" + } + ), + user_response(user, %{"local" => false, "tags" => ["foo", "bar"]}), + user_response( + admin, + %{"roles" => %{"admin" => true, "moderator" => false}} + ) + ] + + assert json_response_and_validate_schema(conn, 200) == %{ + "count" => 3, + "page_size" => 50, + "users" => users + } + end + + test "pagination works correctly with service users", %{conn: conn} do + service1 = User.get_or_create_service_actor_by_ap_id(Endpoint.url() <> "/meido", "meido") + + insert_list(25, :user) + + assert %{"count" => 26, "page_size" => 10, "users" => users1} = + conn + |> get("/api/pleroma/admin/users?page=1&filters=", %{page_size: "10"}) + |> json_response_and_validate_schema(200) + + assert Enum.count(users1) == 10 + assert service1 not in users1 + + assert %{"count" => 26, "page_size" => 10, "users" => users2} = + conn + |> get("/api/pleroma/admin/users?page=2&filters=", %{page_size: "10"}) + |> json_response_and_validate_schema(200) + + assert Enum.count(users2) == 10 + assert service1 not in users2 + + assert %{"count" => 26, "page_size" => 10, "users" => users3} = + conn + |> get("/api/pleroma/admin/users?page=3&filters=", %{page_size: "10"}) + |> json_response_and_validate_schema(200) + + assert Enum.count(users3) == 6 + assert service1 not in users3 + end + + test "renders empty array for the second page", %{conn: conn} do + insert(:user) + + conn = get(conn, "/api/pleroma/admin/users?page=2") + + assert json_response_and_validate_schema(conn, 200) == %{ + "count" => 2, + "page_size" => 50, + "users" => [] + } + end + + test "regular search", %{conn: conn} do + user = insert(:user, nickname: "bob") + + conn = get(conn, "/api/pleroma/admin/users?query=bo") + + assert json_response_and_validate_schema(conn, 200) == %{ + "count" => 1, + "page_size" => 50, + "users" => [user_response(user, %{"local" => true})] + } + end + + test "search by domain", %{conn: conn} do + user = insert(:user, nickname: "nickname@domain.com") + insert(:user) + + conn = get(conn, "/api/pleroma/admin/users?query=domain.com") + + assert json_response_and_validate_schema(conn, 200) == %{ + "count" => 1, + "page_size" => 50, + "users" => [user_response(user)] + } + end + + test "search by full nickname", %{conn: conn} do + user = insert(:user, nickname: "nickname@domain.com") + insert(:user) + + conn = get(conn, "/api/pleroma/admin/users?query=nickname@domain.com") + + assert json_response_and_validate_schema(conn, 200) == %{ + "count" => 1, + "page_size" => 50, + "users" => [user_response(user)] + } + end + + test "search by display name", %{conn: conn} do + user = insert(:user, name: "Display name") + insert(:user) + + conn = get(conn, "/api/pleroma/admin/users?name=display") + + assert json_response_and_validate_schema(conn, 200) == %{ + "count" => 1, + "page_size" => 50, + "users" => [user_response(user)] + } + end + + test "search by email", %{conn: conn} do + user = insert(:user, email: "email@example.com") + insert(:user) + + conn = get(conn, "/api/pleroma/admin/users?email=email@example.com") + + assert json_response_and_validate_schema(conn, 200) == %{ + "count" => 1, + "page_size" => 50, + "users" => [user_response(user)] + } + end + + test "regular search with page size", %{conn: conn} do + user = insert(:user, nickname: "aalice") + user2 = insert(:user, nickname: "alice") + + conn1 = get(conn, "/api/pleroma/admin/users?query=a&page_size=1&page=1") + + assert json_response_and_validate_schema(conn1, 200) == %{ + "count" => 2, + "page_size" => 1, + "users" => [user_response(user2)] + } + + conn2 = get(conn, "/api/pleroma/admin/users?query=a&page_size=1&page=2") + + assert json_response_and_validate_schema(conn2, 200) == %{ + "count" => 2, + "page_size" => 1, + "users" => [user_response(user)] + } + end + + test "only local users" do + admin = insert(:user, is_admin: true, nickname: "john") + token = insert(:oauth_admin_token, user: admin) + user = insert(:user, nickname: "bob") + + insert(:user, nickname: "bobb", local: false) + + conn = + build_conn() + |> assign(:user, admin) + |> assign(:token, token) + |> get("/api/pleroma/admin/users?query=bo&filters=local") + + assert json_response_and_validate_schema(conn, 200) == %{ + "count" => 1, + "page_size" => 50, + "users" => [user_response(user)] + } + end + + test "only local users with no query", %{conn: conn, admin: old_admin} do + admin = insert(:user, is_admin: true, nickname: "john") + user = insert(:user, nickname: "bob") + + insert(:user, nickname: "bobb", local: false) + + conn = get(conn, "/api/pleroma/admin/users?filters=local") + + users = [ + user_response(user), + user_response(admin, %{ + "roles" => %{"admin" => true, "moderator" => false} + }), + user_response(old_admin, %{ + "is_active" => true, + "roles" => %{"admin" => true, "moderator" => false} + }) + ] + + assert json_response_and_validate_schema(conn, 200) == %{ + "count" => 3, + "page_size" => 50, + "users" => users + } + end + + test "only unconfirmed users", %{conn: conn} do + sad_user = insert(:user, nickname: "sadboy", is_confirmed: false) + old_user = insert(:user, nickname: "oldboy", is_confirmed: false) + + insert(:user, nickname: "happyboy", is_approved: true) + insert(:user, is_confirmed: true) + + result = + conn + |> get("/api/pleroma/admin/users?filters=unconfirmed") + |> json_response_and_validate_schema(200) + + users = + Enum.map([old_user, sad_user], fn user -> + user_response(user, %{ + "is_confirmed" => false, + "is_approved" => true + }) + end) + + assert result == %{"count" => 2, "page_size" => 50, "users" => users} + end + + test "only unapproved users", %{conn: conn} do + user = + insert(:user, + nickname: "sadboy", + is_approved: false, + registration_reason: "Plz let me in!" + ) + + insert(:user, nickname: "happyboy", is_approved: true) + + conn = get(conn, "/api/pleroma/admin/users?filters=need_approval") + + users = [ + user_response( + user, + %{"is_approved" => false, "registration_reason" => "Plz let me in!"} + ) + ] + + assert json_response_and_validate_schema(conn, 200) == %{ + "count" => 1, + "page_size" => 50, + "users" => users + } + end + + test "load only admins", %{conn: conn, admin: admin} do + second_admin = insert(:user, is_admin: true) + insert(:user) + insert(:user) + + conn = get(conn, "/api/pleroma/admin/users?filters=is_admin") + + users = [ + user_response(second_admin, %{ + "is_active" => true, + "roles" => %{"admin" => true, "moderator" => false} + }), + user_response(admin, %{ + "is_active" => true, + "roles" => %{"admin" => true, "moderator" => false} + }) + ] + + assert json_response_and_validate_schema(conn, 200) == %{ + "count" => 2, + "page_size" => 50, + "users" => users + } + end + + test "load only moderators", %{conn: conn} do + moderator = insert(:user, is_moderator: true) + insert(:user) + insert(:user) + + conn = get(conn, "/api/pleroma/admin/users?filters=is_moderator") + + assert json_response_and_validate_schema(conn, 200) == %{ + "count" => 1, + "page_size" => 50, + "users" => [ + user_response(moderator, %{ + "is_active" => true, + "roles" => %{"admin" => false, "moderator" => true} + }) + ] + } + end + + test "load users with actor_type is Person", %{admin: admin, conn: conn} do + insert(:user, actor_type: "Service") + insert(:user, actor_type: "Application") + + user1 = insert(:user) + user2 = insert(:user) + + response = + conn + |> get(user_path(conn, :index), %{actor_types: ["Person"]}) + |> json_response_and_validate_schema(200) + + users = [ + user_response(user2), + user_response(user1), + user_response(admin, %{"roles" => %{"admin" => true, "moderator" => false}}) + ] + + assert response == %{"count" => 3, "page_size" => 50, "users" => users} + end + + test "load users with actor_type is Person and Service", %{admin: admin, conn: conn} do + user_service = insert(:user, actor_type: "Service") + insert(:user, actor_type: "Application") + + user1 = insert(:user) + user2 = insert(:user) + + response = + conn + |> get(user_path(conn, :index), %{actor_types: ["Person", "Service"]}) + |> json_response_and_validate_schema(200) + + users = [ + user_response(user2), + user_response(user1), + user_response(user_service, %{"actor_type" => "Service"}), + user_response(admin, %{"roles" => %{"admin" => true, "moderator" => false}}) + ] + + assert response == %{"count" => 4, "page_size" => 50, "users" => users} + end + + test "load users with actor_type is Service", %{conn: conn} do + user_service = insert(:user, actor_type: "Service") + insert(:user, actor_type: "Application") + insert(:user) + insert(:user) + + response = + conn + |> get(user_path(conn, :index), %{actor_types: ["Service"]}) + |> json_response_and_validate_schema(200) + + users = [user_response(user_service, %{"actor_type" => "Service"})] + + assert response == %{"count" => 1, "page_size" => 50, "users" => users} + end + + test "load users with tags list", %{conn: conn} do + user1 = insert(:user, tags: ["first"]) + user2 = insert(:user, tags: ["second"]) + insert(:user) + insert(:user) + + conn = get(conn, "/api/pleroma/admin/users?tags[]=first&tags[]=second") + + users = [ + user_response(user2, %{"tags" => ["second"]}), + user_response(user1, %{"tags" => ["first"]}) + ] + + assert json_response_and_validate_schema(conn, 200) == %{ + "count" => 2, + "page_size" => 50, + "users" => users + } + end + + test "`active` filters out users pending approval", %{token: token} do + insert(:user, is_approved: false) + %{id: user_id} = insert(:user, is_approved: true) + %{id: admin_id} = token.user + + conn = + build_conn() + |> assign(:user, token.user) + |> assign(:token, token) + |> get("/api/pleroma/admin/users?filters=active") + + assert %{ + "count" => 2, + "page_size" => 50, + "users" => [ + %{"id" => ^user_id}, + %{"id" => ^admin_id} + ] + } = json_response_and_validate_schema(conn, 200) + end + + test "it works with multiple filters" do + admin = insert(:user, nickname: "john", is_admin: true) + token = insert(:oauth_admin_token, user: admin) + user = insert(:user, nickname: "bob", local: false, is_active: false) + + insert(:user, nickname: "ken", local: true, is_active: false) + insert(:user, nickname: "bobb", local: false, is_active: true) + + conn = + build_conn() + |> assign(:user, admin) + |> assign(:token, token) + |> get("/api/pleroma/admin/users?filters=deactivated,external") + + assert json_response_and_validate_schema(conn, 200) == %{ + "count" => 1, + "page_size" => 50, + "users" => [user_response(user)] + } + end + + test "it omits relay user", %{admin: admin, conn: conn} do + assert %User{} = Relay.get_actor() + + conn = get(conn, "/api/pleroma/admin/users") + + assert json_response_and_validate_schema(conn, 200) == %{ + "count" => 1, + "page_size" => 50, + "users" => [ + user_response(admin, %{"roles" => %{"admin" => true, "moderator" => false}}) + ] + } + end + end + + test "PATCH /api/pleroma/admin/users/activate", %{admin: admin, conn: conn} do + user_one = insert(:user, is_active: false) + user_two = insert(:user, is_active: false) + + conn = + conn + |> put_req_header("content-type", "application/json") + |> patch( + "/api/pleroma/admin/users/activate", + %{nicknames: [user_one.nickname, user_two.nickname]} + ) + + response = json_response_and_validate_schema(conn, 200) + assert Enum.map(response["users"], & &1["is_active"]) == [true, true] + + log_entry = Repo.one(ModerationLog) + + assert ModerationLog.get_log_entry_message(log_entry) == + "@#{admin.nickname} activated users: @#{user_one.nickname}, @#{user_two.nickname}" + end + + test "PATCH /api/pleroma/admin/users/deactivate", %{admin: admin, conn: conn} do + user_one = insert(:user, is_active: true) + user_two = insert(:user, is_active: true) + + conn = + conn + |> put_req_header("content-type", "application/json") + |> patch( + "/api/pleroma/admin/users/deactivate", + %{nicknames: [user_one.nickname, user_two.nickname]} + ) + + response = json_response_and_validate_schema(conn, 200) + assert Enum.map(response["users"], & &1["is_active"]) == [false, false] + + log_entry = Repo.one(ModerationLog) + + assert ModerationLog.get_log_entry_message(log_entry) == + "@#{admin.nickname} deactivated users: @#{user_one.nickname}, @#{user_two.nickname}" + end + + test "PATCH /api/pleroma/admin/users/approve", %{admin: admin, conn: conn} do + user_one = insert(:user, is_approved: false) + user_two = insert(:user, is_approved: false) + + conn = + conn + |> put_req_header("content-type", "application/json") + |> patch( + "/api/pleroma/admin/users/approve", + %{nicknames: [user_one.nickname, user_two.nickname]} + ) + + response = json_response_and_validate_schema(conn, 200) + assert Enum.map(response["users"], & &1["is_approved"]) == [true, true] + + log_entry = Repo.one(ModerationLog) + + assert ModerationLog.get_log_entry_message(log_entry) == + "@#{admin.nickname} approved users: @#{user_one.nickname}, @#{user_two.nickname}" + end + + test "PATCH /api/pleroma/admin/users/suggest", %{admin: admin, conn: conn} do + user1 = insert(:user, is_suggested: false) + user2 = insert(:user, is_suggested: false) + + response = + conn + |> put_req_header("content-type", "application/json") + |> patch( + "/api/pleroma/admin/users/suggest", + %{nicknames: [user1.nickname, user2.nickname]} + ) + |> json_response_and_validate_schema(200) + + assert Enum.map(response["users"], & &1["is_suggested"]) == [true, true] + [user1, user2] = Repo.reload!([user1, user2]) + + assert user1.is_suggested + assert user2.is_suggested + + log_entry = Repo.one(ModerationLog) + + assert ModerationLog.get_log_entry_message(log_entry) == + "@#{admin.nickname} added suggested users: @#{user1.nickname}, @#{user2.nickname}" + end + + test "PATCH /api/pleroma/admin/users/unsuggest", %{admin: admin, conn: conn} do + user1 = insert(:user, is_suggested: true) + user2 = insert(:user, is_suggested: true) + + response = + conn + |> put_req_header("content-type", "application/json") + |> patch( + "/api/pleroma/admin/users/unsuggest", + %{nicknames: [user1.nickname, user2.nickname]} + ) + |> json_response_and_validate_schema(200) + + assert Enum.map(response["users"], & &1["is_suggested"]) == [false, false] + [user1, user2] = Repo.reload!([user1, user2]) + + refute user1.is_suggested + refute user2.is_suggested + + log_entry = Repo.one(ModerationLog) + + assert ModerationLog.get_log_entry_message(log_entry) == + "@#{admin.nickname} removed suggested users: @#{user1.nickname}, @#{user2.nickname}" + end + + test "PATCH /api/pleroma/admin/users/:nickname/toggle_activation", %{admin: admin, conn: conn} do + user = insert(:user) + + conn = + conn + |> put_req_header("content-type", "application/json") + |> patch("/api/pleroma/admin/users/#{user.nickname}/toggle_activation") + + assert json_response_and_validate_schema(conn, 200) == + user_response( + user, + %{"is_active" => !user.is_active} + ) + + log_entry = Repo.one(ModerationLog) + + assert ModerationLog.get_log_entry_message(log_entry) == + "@#{admin.nickname} deactivated users: @#{user.nickname}" + end + + defp user_response(user, attrs \\ %{}) do + %{ + "is_active" => user.is_active, + "id" => user.id, + "email" => user.email, + "nickname" => user.nickname, + "roles" => %{"admin" => false, "moderator" => false}, + "local" => user.local, + "tags" => [], + "avatar" => User.avatar_url(user) |> MediaProxy.url(), + "display_name" => HTML.strip_tags(user.name || user.nickname), + "is_confirmed" => true, + "is_approved" => true, + "is_suggested" => false, + "url" => user.ap_id, + "registration_reason" => nil, + "actor_type" => "Person", + "created_at" => CommonAPI.Utils.to_masto_date(user.inserted_at) + } + |> Map.merge(attrs) + end +end diff --git a/test/web/admin_api/search_test.exs b/test/pleroma/web/admin_api/search_test.exs index b974cedd5..2335c5228 100644 --- a/test/web/admin_api/search_test.exs +++ b/test/pleroma/web/admin_api/search_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.AdminAPI.SearchTest do - use Pleroma.Web.ConnCase + use Pleroma.Web.ConnCase, async: true alias Pleroma.Web.AdminAPI.Search @@ -47,9 +47,9 @@ defmodule Pleroma.Web.AdminAPI.SearchTest do end test "it returns active/deactivated users" do - insert(:user, deactivated: true) - insert(:user, deactivated: true) - insert(:user, deactivated: false) + insert(:user, is_active: false) + insert(:user, is_active: false) + insert(:user, is_active: true) {:ok, _results, active_count} = Search.user(%{ @@ -70,7 +70,7 @@ defmodule Pleroma.Web.AdminAPI.SearchTest do test "it returns specific user" do insert(:user) insert(:user) - user = insert(:user, nickname: "bob", local: true, deactivated: false) + user = insert(:user, nickname: "bob", local: true, is_active: true) {:ok, _results, total_count} = Search.user(%{query: ""}) @@ -143,6 +143,20 @@ defmodule Pleroma.Web.AdminAPI.SearchTest do assert user2 in users end + test "it returns users by actor_types" do + user_service = insert(:user, actor_type: "Service") + user_application = insert(:user, actor_type: "Application") + user1 = insert(:user) + user2 = insert(:user) + + {:ok, [^user_service], 1} = Search.user(%{actor_types: ["Service"]}) + {:ok, [^user_application], 1} = Search.user(%{actor_types: ["Application"]}) + {:ok, [^user2, ^user1], 2} = Search.user(%{actor_types: ["Person"]}) + + {:ok, [^user2, ^user1, ^user_service], 3} = + Search.user(%{actor_types: ["Person", "Service"]}) + end + test "it returns user by display name" do user = insert(:user, name: "Display name") insert(:user) @@ -168,7 +182,7 @@ defmodule Pleroma.Web.AdminAPI.SearchTest do end test "it returns unapproved user" do - unapproved = insert(:user, approval_pending: true) + unapproved = insert(:user, is_approved: false) insert(:user) insert(:user) @@ -177,5 +191,26 @@ defmodule Pleroma.Web.AdminAPI.SearchTest do assert total == 3 assert count == 1 end + + test "it returns unconfirmed user" do + unconfirmed = insert(:user, is_confirmed: false) + insert(:user) + insert(:user) + + {:ok, _results, total} = Search.user() + {:ok, [^unconfirmed], count} = Search.user(%{unconfirmed: true}) + assert total == 3 + assert count == 1 + end + + # Note: as in Mastodon, `is_discoverable` doesn't anyhow relate to user searchability + test "it returns non-discoverable users" do + insert(:user) + insert(:user, is_discoverable: false) + + {:ok, _results, total} = Search.user() + + assert total == 2 + end end end diff --git a/test/pleroma/web/admin_api/views/account_view_test.exs b/test/pleroma/web/admin_api/views/account_view_test.exs new file mode 100644 index 000000000..025726c73 --- /dev/null +++ b/test/pleroma/web/admin_api/views/account_view_test.exs @@ -0,0 +1,16 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.AdminAPI.AccountViewTest do + use Pleroma.DataCase, async: true + import Pleroma.Factory + alias Pleroma.Web.AdminAPI.AccountView + + describe "show.json" do + test "renders the user's email" do + user = insert(:user, email: "yolo@yolofam.tld") + assert %{"email" => "yolo@yolofam.tld"} = AccountView.render("show.json", %{user: user}) + end + end +end diff --git a/test/pleroma/web/admin_api/views/moderation_log_view_test.exs b/test/pleroma/web/admin_api/views/moderation_log_view_test.exs new file mode 100644 index 000000000..4efe4c4c8 --- /dev/null +++ b/test/pleroma/web/admin_api/views/moderation_log_view_test.exs @@ -0,0 +1,103 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only +defmodule Pleroma.Web.AdminAPI.ModerationLogViewTest do + use Pleroma.DataCase, async: true + + alias Pleroma.Web.AdminAPI.ModerationLogView + + describe "renders `report_note_delete` log messages" do + setup do + log1 = %Pleroma.ModerationLog{ + id: 1, + data: %{ + "action" => "report_note_delete", + "actor" => %{"id" => "A1I7G8", "nickname" => "admin", "type" => "user"}, + "message" => "@admin deleted note 'mistake' from report #A1I7be on user @b-612", + "subject" => %{"id" => "A1I7be", "state" => "open", "type" => "report"}, + "subject_actor" => %{"id" => "A1I7G8", "nickname" => "b-612", "type" => "user"}, + "text" => "mistake" + }, + inserted_at: ~N[2020-11-17 14:13:20] + } + + log2 = %Pleroma.ModerationLog{ + id: 2, + data: %{ + "action" => "report_note_delete", + "actor" => %{"id" => "A1I7G8", "nickname" => "admin", "type" => "user"}, + "message" => "@admin deleted note 'fake user' from report #A1I7be on user @j-612", + "subject" => %{"id" => "A1I7be", "state" => "open", "type" => "report"}, + "subject_actor" => %{"id" => "A1I7G8", "nickname" => "j-612", "type" => "user"}, + "text" => "fake user" + }, + inserted_at: ~N[2020-11-17 14:13:20] + } + + {:ok, %{log1: log1, log2: log2}} + end + + test "renders `report_note_delete` log messages", %{log1: log1, log2: log2} do + assert ModerationLogView.render( + "index.json", + %{log: %{items: [log1, log2], count: 2}} + ) == %{ + items: [ + %{ + id: 1, + data: %{ + "action" => "report_note_delete", + "actor" => %{"id" => "A1I7G8", "nickname" => "admin", "type" => "user"}, + "message" => + "@admin deleted note 'mistake' from report #A1I7be on user @b-612", + "subject" => %{"id" => "A1I7be", "state" => "open", "type" => "report"}, + "subject_actor" => %{ + "id" => "A1I7G8", + "nickname" => "b-612", + "type" => "user" + }, + "text" => "mistake" + }, + message: "@admin deleted note 'mistake' from report #A1I7be on user @b-612", + time: 1_605_622_400 + }, + %{ + id: 2, + data: %{ + "action" => "report_note_delete", + "actor" => %{"id" => "A1I7G8", "nickname" => "admin", "type" => "user"}, + "message" => + "@admin deleted note 'fake user' from report #A1I7be on user @j-612", + "subject" => %{"id" => "A1I7be", "state" => "open", "type" => "report"}, + "subject_actor" => %{ + "id" => "A1I7G8", + "nickname" => "j-612", + "type" => "user" + }, + "text" => "fake user" + }, + message: "@admin deleted note 'fake user' from report #A1I7be on user @j-612", + time: 1_605_622_400 + } + ], + total: 2 + } + end + + test "renders `report_note_delete` log message", %{log1: log} do + assert ModerationLogView.render("show.json", %{log_entry: log}) == %{ + id: 1, + data: %{ + "action" => "report_note_delete", + "actor" => %{"id" => "A1I7G8", "nickname" => "admin", "type" => "user"}, + "message" => "@admin deleted note 'mistake' from report #A1I7be on user @b-612", + "subject" => %{"id" => "A1I7be", "state" => "open", "type" => "report"}, + "subject_actor" => %{"id" => "A1I7G8", "nickname" => "b-612", "type" => "user"}, + "text" => "mistake" + }, + message: "@admin deleted note 'mistake' from report #A1I7be on user @b-612", + time: 1_605_622_400 + } + end + end +end diff --git a/test/web/admin_api/views/report_view_test.exs b/test/pleroma/web/admin_api/views/report_view_test.exs index 5a02292be..093e2d95d 100644 --- a/test/web/admin_api/views/report_view_test.exs +++ b/test/pleroma/web/admin_api/views/report_view_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.AdminAPI.ReportViewTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true import Pleroma.Factory @@ -143,4 +143,29 @@ defmodule Pleroma.Web.AdminAPI.ReportViewTest do assert %{} = ReportView.render("show.json", Report.extract_report_info(activity)) end + + test "reports are ordered newest first" do + user = insert(:user) + other_user = insert(:user) + + {:ok, report1} = + CommonAPI.report(user, %{ + account_id: other_user.id, + comment: "first report" + }) + + {:ok, report2} = + CommonAPI.report(user, %{ + account_id: other_user.id, + comment: "second report" + }) + + %{reports: rendered} = + ReportView.render("index.json", + reports: Pleroma.Web.ActivityPub.Utils.get_reports(%{}, 1, 50) + ) + + assert report2.id == rendered |> Enum.at(0) |> Map.get(:id) + assert report1.id == rendered |> Enum.at(1) |> Map.get(:id) + end end diff --git a/test/web/api_spec/schema_examples_test.exs b/test/pleroma/web/api_spec/schema_examples_test.exs index f00e834fc..981890d77 100644 --- a/test/web/api_spec/schema_examples_test.exs +++ b/test/pleroma/web/api_spec/schema_examples_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ApiSpec.SchemaExamplesTest do diff --git a/test/web/auth/auth_test_controller_test.exs b/test/pleroma/web/auth/auth_controller_test.exs index fed52b7f3..a869389e3 100644 --- a/test/web/auth/auth_test_controller_test.exs +++ b/test/pleroma/web/auth/auth_controller_test.exs @@ -1,8 +1,8 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.Tests.AuthTestControllerTest do +defmodule Pleroma.Web.Auth.AuthControllerTest do use Pleroma.Web.ConnCase import Pleroma.Factory diff --git a/test/web/auth/authenticator_test.exs b/test/pleroma/web/auth/authenticator_test.exs index d54253343..26779df03 100644 --- a/test/web/auth/authenticator_test.exs +++ b/test/pleroma/web/auth/authenticator_test.exs @@ -1,42 +1,42 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.Auth.AuthenticatorTest do - use Pleroma.Web.ConnCase + use Pleroma.Web.ConnCase, async: true - alias Pleroma.Web.Auth.Authenticator + alias Pleroma.Web.Auth.Helpers import Pleroma.Factory describe "fetch_user/1" do test "returns user by name" do user = insert(:user) - assert Authenticator.fetch_user(user.nickname) == user + assert Helpers.fetch_user(user.nickname) == user end test "returns user by email" do user = insert(:user) - assert Authenticator.fetch_user(user.email) == user + assert Helpers.fetch_user(user.email) == user end test "returns nil" do - assert Authenticator.fetch_user("email") == nil + assert Helpers.fetch_user("email") == nil end end describe "fetch_credentials/1" do test "returns name and password from authorization params" do params = %{"authorization" => %{"name" => "test", "password" => "test-pass"}} - assert Authenticator.fetch_credentials(params) == {:ok, {"test", "test-pass"}} + assert Helpers.fetch_credentials(params) == {:ok, {"test", "test-pass"}} end test "returns name and password with grant_type 'password'" do params = %{"grant_type" => "password", "username" => "test", "password" => "test-pass"} - assert Authenticator.fetch_credentials(params) == {:ok, {"test", "test-pass"}} + assert Helpers.fetch_credentials(params) == {:ok, {"test", "test-pass"}} end test "returns error" do - assert Authenticator.fetch_credentials(%{}) == {:error, :invalid_credentials} + assert Helpers.fetch_credentials(%{}) == {:error, :invalid_credentials} end end end diff --git a/test/web/auth/basic_auth_test.exs b/test/pleroma/web/auth/basic_auth_test.exs index bf6e3d2fc..2816aae4c 100644 --- a/test/web/auth/basic_auth_test.exs +++ b/test/pleroma/web/auth/basic_auth_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.Auth.BasicAuthTest do - use Pleroma.Web.ConnCase + use Pleroma.Web.ConnCase, async: true import Pleroma.Factory @@ -11,7 +11,7 @@ defmodule Pleroma.Web.Auth.BasicAuthTest do conn: conn } do user = insert(:user) - assert Pbkdf2.verify_pass("test", user.password_hash) + assert Pleroma.Password.Pbkdf2.verify_pass("test", user.password_hash) basic_auth_contents = (URI.encode_www_form(user.nickname) <> ":" <> URI.encode_www_form("test")) diff --git a/test/web/auth/pleroma_authenticator_test.exs b/test/pleroma/web/auth/pleroma_authenticator_test.exs index 1ba0dfecc..b1397c523 100644 --- a/test/web/auth/pleroma_authenticator_test.exs +++ b/test/pleroma/web/auth/pleroma_authenticator_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.Auth.PleromaAuthenticatorTest do - use Pleroma.Web.ConnCase + use Pleroma.Web.ConnCase, async: true alias Pleroma.Web.Auth.PleromaAuthenticator import Pleroma.Factory @@ -11,7 +11,13 @@ defmodule Pleroma.Web.Auth.PleromaAuthenticatorTest do setup do password = "testpassword" name = "AgentSmith" - user = insert(:user, nickname: name, password_hash: Pbkdf2.hash_pwd_salt(password)) + + user = + insert(:user, + nickname: name, + password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt(password) + ) + {:ok, [user: user, name: name, password: password]} end diff --git a/test/web/auth/totp_authenticator_test.exs b/test/pleroma/web/auth/totp_authenticator_test.exs index 84d4cd840..ac4209f2d 100644 --- a/test/web/auth/totp_authenticator_test.exs +++ b/test/pleroma/web/auth/totp_authenticator_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.Auth.TOTPAuthenticatorTest do - use Pleroma.Web.ConnCase + use Pleroma.Web.ConnCase, async: true alias Pleroma.MFA alias Pleroma.MFA.BackupCodes @@ -34,7 +34,7 @@ defmodule Pleroma.Web.Auth.TOTPAuthenticatorTest do hashed_codes = backup_codes - |> Enum.map(&Pbkdf2.hash_pwd_salt(&1)) + |> Enum.map(&Pleroma.Password.Pbkdf2.hash_pwd_salt(&1)) user = insert(:user, diff --git a/test/web/common_api/common_api_utils_test.exs b/test/pleroma/web/common_api/utils_test.exs index e67c10b93..fc01f820a 100644 --- a/test/web/common_api/common_api_utils_test.exs +++ b/test/pleroma/web/common_api/utils_test.exs @@ -1,11 +1,12 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.CommonAPI.UtilsTest do alias Pleroma.Builders.UserBuilder alias Pleroma.Object alias Pleroma.Web.CommonAPI + alias Pleroma.Web.CommonAPI.ActivityDraft alias Pleroma.Web.CommonAPI.Utils use Pleroma.DataCase @@ -159,11 +160,116 @@ defmodule Pleroma.Web.CommonAPI.UtilsTest do {output, _, _} = Utils.format_input(text, "text/markdown") assert output == - ~s(<p><strong>hello world</strong></p><p><em>another <span class="h-card"><a class="u-url mention" data-user="#{ - user.id - }" href="http://foo.com/user__test" rel="ugc">@<span>user__test</span></a></span> and <span class="h-card"><a class="u-url mention" data-user="#{ - user.id - }" href="http://foo.com/user__test" rel="ugc">@<span>user__test</span></a></span> <a href="http://google.com" rel="ugc">google.com</a> paragraph</em></p>) + ~s(<p><strong>hello world</strong></p><p><em>another <span class="h-card"><a class="u-url mention" data-user="#{user.id}" href="http://foo.com/user__test" rel="ugc">@<span>user__test</span></a></span> and <span class="h-card"><a class="u-url mention" data-user="#{user.id}" href="http://foo.com/user__test" rel="ugc">@<span>user__test</span></a></span> <a href="http://google.com" rel="ugc">google.com</a> paragraph</em></p>) + end + end + + describe "format_input/3 with markdown" do + test "Paragraph" do + code = ~s[Hello\n\nWorld!] + {result, [], []} = Utils.format_input(code, "text/markdown") + assert result == "<p>Hello</p><p>World!</p>" + end + + test "links" do + code = "https://en.wikipedia.org/wiki/Animal_Crossing_(video_game)" + {result, [], []} = Utils.format_input(code, "text/markdown") + assert result == ~s[<p><a href="#{code}">#{code}</a></p>] + + code = "https://github.com/pragdave/earmark/" + {result, [], []} = Utils.format_input(code, "text/markdown") + assert result == ~s[<p><a href="#{code}">#{code}</a></p>] + end + + test "link with local mention" do + insert(:user, %{nickname: "lain"}) + + code = "https://example.com/@lain" + {result, [], []} = Utils.format_input(code, "text/markdown") + assert result == ~s[<p><a href="#{code}">#{code}</a></p>] + end + + test "local mentions" do + mario = insert(:user, %{nickname: "mario"}) + luigi = insert(:user, %{nickname: "luigi"}) + + code = "@mario @luigi yo what's up?" + {result, _, []} = Utils.format_input(code, "text/markdown") + + assert result == + ~s[<p><span class="h-card"><a class="u-url mention" data-user="#{mario.id}" href="#{mario.ap_id}" rel="ugc">@<span>mario</span></a></span> <span class="h-card"><a class="u-url mention" data-user="#{luigi.id}" href="#{luigi.ap_id}" rel="ugc">@<span>luigi</span></a></span> yo what’s up?</p>] + end + + test "remote mentions" do + mario = insert(:user, %{nickname: "mario@mushroom.world", local: false}) + luigi = insert(:user, %{nickname: "luigi@mushroom.world", local: false}) + + code = "@mario@mushroom.world @luigi@mushroom.world yo what's up?" + {result, _, []} = Utils.format_input(code, "text/markdown") + + assert result == + ~s[<p><span class="h-card"><a class="u-url mention" data-user="#{mario.id}" href="#{mario.ap_id}" rel="ugc">@<span>mario</span></a></span> <span class="h-card"><a class="u-url mention" data-user="#{luigi.id}" href="#{luigi.ap_id}" rel="ugc">@<span>luigi</span></a></span> yo what’s up?</p>] + end + + test "raw HTML" do + code = ~s[<a href="http://example.org/">OwO</a><!-- what's this?-->] + {result, [], []} = Utils.format_input(code, "text/markdown") + assert result == ~s[<a href="http://example.org/">OwO</a>] + end + + test "rulers" do + code = ~s[before\n\n-----\n\nafter] + {result, [], []} = Utils.format_input(code, "text/markdown") + assert result == "<p>before</p><hr/><p>after</p>" + end + + test "blockquote" do + code = ~s[> whoms't are you quoting?] + {result, [], []} = Utils.format_input(code, "text/markdown") + assert result == "<blockquote><p>whoms’t are you quoting?</p></blockquote>" + end + + test "code" do + code = ~s[`mix`] + {result, [], []} = Utils.format_input(code, "text/markdown") + assert result == ~s[<p><code class="inline">mix</code></p>] + + code = ~s[``mix``] + {result, [], []} = Utils.format_input(code, "text/markdown") + assert result == ~s[<p><code class="inline">mix</code></p>] + + code = ~s[```\nputs "Hello World"\n```] + {result, [], []} = Utils.format_input(code, "text/markdown") + assert result == ~s[<pre><code>puts "Hello World"</code></pre>] + + code = ~s[ <div>\n </div>] + {result, [], []} = Utils.format_input(code, "text/markdown") + assert result == ~s[<pre><code><div>\n</div></code></pre>] + end + + test "lists" do + code = ~s[- one\n- two\n- three\n- four] + {result, [], []} = Utils.format_input(code, "text/markdown") + assert result == "<ul><li>one</li><li>two</li><li>three</li><li>four</li></ul>" + + code = ~s[1. one\n2. two\n3. three\n4. four\n] + {result, [], []} = Utils.format_input(code, "text/markdown") + assert result == "<ol><li>one</li><li>two</li><li>three</li><li>four</li></ol>" + end + + test "delegated renderers" do + code = ~s[*aaaa~*] + {result, [], []} = Utils.format_input(code, "text/markdown") + assert result == ~s[<p><em>aaaa~</em></p>] + + code = ~s[**aaaa~**] + {result, [], []} = Utils.format_input(code, "text/markdown") + assert result == ~s[<p><strong>aaaa~</strong></p>] + + # strikethrough + code = ~s[~~aaaa~~~] + {result, [], []} = Utils.format_input(code, "text/markdown") + assert result == ~s[<p><del>aaaa</del>~</p>] end end @@ -235,9 +341,9 @@ defmodule Pleroma.Web.CommonAPI.UtilsTest do test "for public posts, not a reply" do user = insert(:user) mentioned_user = insert(:user) - mentions = [mentioned_user.ap_id] + draft = %ActivityDraft{user: user, mentions: [mentioned_user.ap_id], visibility: "public"} - {to, cc} = Utils.get_to_and_cc(user, mentions, nil, "public", nil) + {to, cc} = Utils.get_to_and_cc(draft) assert length(to) == 2 assert length(cc) == 1 @@ -252,9 +358,15 @@ defmodule Pleroma.Web.CommonAPI.UtilsTest do mentioned_user = insert(:user) third_user = insert(:user) {:ok, activity} = CommonAPI.post(third_user, %{status: "uguu"}) - mentions = [mentioned_user.ap_id] - {to, cc} = Utils.get_to_and_cc(user, mentions, activity, "public", nil) + draft = %ActivityDraft{ + user: user, + mentions: [mentioned_user.ap_id], + visibility: "public", + in_reply_to: activity + } + + {to, cc} = Utils.get_to_and_cc(draft) assert length(to) == 3 assert length(cc) == 1 @@ -268,9 +380,9 @@ defmodule Pleroma.Web.CommonAPI.UtilsTest do test "for unlisted posts, not a reply" do user = insert(:user) mentioned_user = insert(:user) - mentions = [mentioned_user.ap_id] + draft = %ActivityDraft{user: user, mentions: [mentioned_user.ap_id], visibility: "unlisted"} - {to, cc} = Utils.get_to_and_cc(user, mentions, nil, "unlisted", nil) + {to, cc} = Utils.get_to_and_cc(draft) assert length(to) == 2 assert length(cc) == 1 @@ -285,9 +397,15 @@ defmodule Pleroma.Web.CommonAPI.UtilsTest do mentioned_user = insert(:user) third_user = insert(:user) {:ok, activity} = CommonAPI.post(third_user, %{status: "uguu"}) - mentions = [mentioned_user.ap_id] - {to, cc} = Utils.get_to_and_cc(user, mentions, activity, "unlisted", nil) + draft = %ActivityDraft{ + user: user, + mentions: [mentioned_user.ap_id], + visibility: "unlisted", + in_reply_to: activity + } + + {to, cc} = Utils.get_to_and_cc(draft) assert length(to) == 3 assert length(cc) == 1 @@ -301,9 +419,9 @@ defmodule Pleroma.Web.CommonAPI.UtilsTest do test "for private posts, not a reply" do user = insert(:user) mentioned_user = insert(:user) - mentions = [mentioned_user.ap_id] + draft = %ActivityDraft{user: user, mentions: [mentioned_user.ap_id], visibility: "private"} - {to, cc} = Utils.get_to_and_cc(user, mentions, nil, "private", nil) + {to, cc} = Utils.get_to_and_cc(draft) assert length(to) == 2 assert Enum.empty?(cc) @@ -316,9 +434,15 @@ defmodule Pleroma.Web.CommonAPI.UtilsTest do mentioned_user = insert(:user) third_user = insert(:user) {:ok, activity} = CommonAPI.post(third_user, %{status: "uguu"}) - mentions = [mentioned_user.ap_id] - {to, cc} = Utils.get_to_and_cc(user, mentions, activity, "private", nil) + draft = %ActivityDraft{ + user: user, + mentions: [mentioned_user.ap_id], + visibility: "private", + in_reply_to: activity + } + + {to, cc} = Utils.get_to_and_cc(draft) assert length(to) == 2 assert Enum.empty?(cc) @@ -330,9 +454,9 @@ defmodule Pleroma.Web.CommonAPI.UtilsTest do test "for direct posts, not a reply" do user = insert(:user) mentioned_user = insert(:user) - mentions = [mentioned_user.ap_id] + draft = %ActivityDraft{user: user, mentions: [mentioned_user.ap_id], visibility: "direct"} - {to, cc} = Utils.get_to_and_cc(user, mentions, nil, "direct", nil) + {to, cc} = Utils.get_to_and_cc(draft) assert length(to) == 1 assert Enum.empty?(cc) @@ -345,9 +469,15 @@ defmodule Pleroma.Web.CommonAPI.UtilsTest do mentioned_user = insert(:user) third_user = insert(:user) {:ok, activity} = CommonAPI.post(third_user, %{status: "uguu"}) - mentions = [mentioned_user.ap_id] - {to, cc} = Utils.get_to_and_cc(user, mentions, activity, "direct", nil) + draft = %ActivityDraft{ + user: user, + mentions: [mentioned_user.ap_id], + visibility: "direct", + in_reply_to: activity + } + + {to, cc} = Utils.get_to_and_cc(draft) assert length(to) == 1 assert Enum.empty?(cc) @@ -356,7 +486,14 @@ defmodule Pleroma.Web.CommonAPI.UtilsTest do {:ok, direct_activity} = CommonAPI.post(third_user, %{status: "uguu", visibility: "direct"}) - {to, cc} = Utils.get_to_and_cc(user, mentions, direct_activity, "direct", nil) + draft = %ActivityDraft{ + user: user, + mentions: [mentioned_user.ap_id], + visibility: "direct", + in_reply_to: direct_activity + } + + {to, cc} = Utils.get_to_and_cc(draft) assert length(to) == 2 assert Enum.empty?(cc) @@ -532,41 +669,6 @@ defmodule Pleroma.Web.CommonAPI.UtilsTest do end end - describe "make_note_data/11" do - test "returns note data" do - user = insert(:user) - note = insert(:note) - user2 = insert(:user) - user3 = insert(:user) - - assert Utils.make_note_data( - user.ap_id, - [user2.ap_id], - "2hu", - "<h1>This is :moominmamma: note</h1>", - [], - note.id, - [name: "jimm"], - "test summary", - [user3.ap_id], - false, - %{"custom_tag" => "test"} - ) == %{ - "actor" => user.ap_id, - "attachment" => [], - "cc" => [user3.ap_id], - "content" => "<h1>This is :moominmamma: note</h1>", - "context" => "2hu", - "sensitive" => false, - "summary" => "test summary", - "tag" => ["jimm"], - "to" => [user2.ap_id], - "type" => "Note", - "custom_tag" => "test" - } - end - end - describe "maybe_add_attachments/3" do test "returns parsed results when attachment_links is false" do assert Utils.maybe_add_attachments( diff --git a/test/web/common_api/common_api_test.exs b/test/pleroma/web/common_api_test.exs index 800db9a20..ad0b87543 100644 --- a/test/web/common_api/common_api_test.exs +++ b/test/pleroma/web/common_api_test.exs @@ -1,9 +1,11 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.CommonAPITest do + use Oban.Testing, repo: Pleroma.Repo use Pleroma.DataCase + alias Pleroma.Activity alias Pleroma.Chat alias Pleroma.Conversation.Participation @@ -16,6 +18,7 @@ defmodule Pleroma.Web.CommonAPITest do alias Pleroma.Web.ActivityPub.Visibility alias Pleroma.Web.AdminAPI.AccountView alias Pleroma.Web.CommonAPI + alias Pleroma.Workers.PollWorker import Pleroma.Factory import Mock @@ -23,10 +26,38 @@ defmodule Pleroma.Web.CommonAPITest do require Pleroma.Constants + setup_all do + Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) + :ok + end + setup do: clear_config([:instance, :safe_dm_mentions]) setup do: clear_config([:instance, :limit]) setup do: clear_config([:instance, :max_pinned_statuses]) + describe "posting polls" do + test "it posts a poll" do + user = insert(:user) + + {:ok, activity} = + CommonAPI.post(user, %{ + status: "who is the best", + poll: %{expires_in: 600, options: ["reimu", "marisa"]} + }) + + object = Object.normalize(activity, fetch: false) + + assert object.data["type"] == "Question" + assert object.data["oneOf"] |> length() == 2 + + assert_enqueued( + worker: PollWorker, + args: %{op: "poll_end", activity_id: activity.id}, + scheduled_at: NaiveDateTime.from_iso8601!(object.data["closed"]) + ) + end + end + describe "blocking" do setup do blocker = insert(:user) @@ -76,12 +107,26 @@ defmodule Pleroma.Web.CommonAPITest do describe "posting chat messages" do setup do: clear_config([:instance, :chat_limit]) + test "it posts a self-chat" do + author = insert(:user) + recipient = author + + {:ok, activity} = + CommonAPI.post_chat_message( + author, + recipient, + "remember to buy milk when milk truk arive" + ) + + assert activity.data["type"] == "Create" + end + test "it posts a chat message without content but with an attachment" do author = insert(:user) recipient = insert(:user) file = %Plug.Upload{ - content_type: "image/jpg", + content_type: "image/jpeg", path: Path.absname("test/fixtures/image.jpg"), filename: "an_image.jpg" } @@ -141,7 +186,7 @@ defmodule Pleroma.Web.CommonAPITest do assert other_user.ap_id not in activity.recipients - object = Object.normalize(activity, false) + object = Object.normalize(activity, fetch: false) assert object.data["content"] == "uguu<br/>uguuu" end @@ -161,12 +206,10 @@ defmodule Pleroma.Web.CommonAPITest do assert other_user.ap_id not in activity.recipients - object = Object.normalize(activity, false) + object = Object.normalize(activity, fetch: false) assert object.data["content"] == - "<a href=\"https://example.org\" rel=\"ugc\">https://example.org</a> is the site of <span class=\"h-card\"><a class=\"u-url mention\" data-user=\"#{ - other_user.id - }\" href=\"#{other_user.ap_id}\" rel=\"ugc\">@<span>#{other_user.nickname}</span></a></span> <a class=\"hashtag\" data-tag=\"2hu\" href=\"http://localhost:4001/tag/2hu\">#2hu</a>" + "<a href=\"https://example.org\" rel=\"ugc\">https://example.org</a> is the site of <span class=\"h-card\"><a class=\"u-url mention\" data-user=\"#{other_user.id}\" href=\"#{other_user.ap_id}\" rel=\"ugc\">@<span>#{other_user.nickname}</span></a></span> <a class=\"hashtag\" data-tag=\"2hu\" href=\"http://localhost:4001/tag/2hu\">#2hu</a>" end test "it posts a chat message" do @@ -182,7 +225,7 @@ defmodule Pleroma.Web.CommonAPITest do assert activity.data["type"] == "Create" assert activity.local - object = Object.normalize(activity) + object = Object.normalize(activity, fetch: false) assert object.data["type"] == "ChatMessage" assert object.data["to"] == [recipient.ap_id] @@ -201,7 +244,7 @@ defmodule Pleroma.Web.CommonAPITest do end test "it reject messages over the local limit" do - Pleroma.Config.put([:instance, :chat_limit], 2) + clear_config([:instance, :chat_limit], 2) author = insert(:user) recipient = insert(:user) @@ -215,6 +258,17 @@ defmodule Pleroma.Web.CommonAPITest do assert message == :content_too_long end + + test "it reject messages via MRF" do + clear_config([:mrf_keyword, :reject], ["GNO"]) + clear_config([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.KeywordPolicy]) + + author = insert(:user) + recipient = insert(:user) + + assert {:reject, "[KeywordPolicy] Matches with rejected keyword"} == + CommonAPI.post_chat_message(author, recipient, "GNO/Linux") + end end describe "unblocking" do @@ -237,7 +291,7 @@ defmodule Pleroma.Web.CommonAPITest do clear_config([:instance, :federating], true) - Object.normalize(post, false) + Object.normalize(post, fetch: false) |> Object.prune() with_mock Pleroma.Web.Federator, @@ -431,7 +485,7 @@ defmodule Pleroma.Web.CommonAPITest do jafnhar = insert(:user) tridi = insert(:user) - Pleroma.Config.put([:instance, :safe_dm_mentions], true) + clear_config([:instance, :safe_dm_mentions], true) {:ok, activity} = CommonAPI.post(har, %{ @@ -447,21 +501,55 @@ defmodule Pleroma.Web.CommonAPITest do user = insert(:user) {:ok, activity} = CommonAPI.post(user, %{status: "#2hu #2HU"}) - object = Object.normalize(activity) + object = Object.normalize(activity, fetch: false) - assert object.data["tag"] == ["2hu"] + assert Object.tags(object) == ["2hu"] end test "it adds emoji in the object" do user = insert(:user) {:ok, activity} = CommonAPI.post(user, %{status: ":firefox:"}) - assert Object.normalize(activity).data["emoji"]["firefox"] + assert Object.normalize(activity, fetch: false).data["emoji"]["firefox"] end describe "posting" do + test "it adds an emoji on an external site" do + user = insert(:user) + {:ok, activity} = CommonAPI.post(user, %{status: "hey :external_emoji:"}) + + assert %{"external_emoji" => url} = Object.normalize(activity).data["emoji"] + assert url == "https://example.com/emoji.png" + + {:ok, activity} = CommonAPI.post(user, %{status: "hey :blank:"}) + + assert %{"blank" => url} = Object.normalize(activity).data["emoji"] + assert url == "#{Pleroma.Web.Endpoint.url()}/emoji/blank.png" + end + + test "it copies emoji from the subject of the parent post" do + %Object{} = + object = + Object.normalize("https://patch.cx/objects/a399c28e-c821-4820-bc3e-4afeb044c16f", + fetch: true + ) + + activity = Activity.get_create_by_object_ap_id(object.data["id"]) + user = insert(:user) + + {:ok, reply_activity} = + CommonAPI.post(user, %{ + in_reply_to_id: activity.id, + status: ":joker_disapprove:", + spoiler_text: ":joker_smile:" + }) + + assert Object.normalize(reply_activity).data["emoji"]["joker_smile"] + refute Object.normalize(reply_activity).data["emoji"]["joker_disapprove"] + end + test "deactivated users can't post" do - user = insert(:user, deactivated: true) + user = insert(:user, is_active: false) assert {:error, _} = CommonAPI.post(user, %{status: "ye"}) end @@ -495,7 +583,7 @@ defmodule Pleroma.Web.CommonAPITest do content_type: "text/html" }) - object = Object.normalize(activity) + object = Object.normalize(activity, fetch: false) assert object.data["content"] == "<p><b>2hu</b></p>alert('xss')" assert object.data["source"] == post @@ -512,9 +600,9 @@ defmodule Pleroma.Web.CommonAPITest do content_type: "text/markdown" }) - object = Object.normalize(activity) + object = Object.normalize(activity, fetch: false) - assert object.data["content"] == "<p><b>2hu</b></p>alert('xss')" + assert object.data["content"] == "<p><b>2hu</b></p>" assert object.data["source"] == post end @@ -585,28 +673,28 @@ defmodule Pleroma.Web.CommonAPITest do end test "it validates character limits are correctly enforced" do - Pleroma.Config.put([:instance, :limit], 5) + clear_config([:instance, :limit], 5) user = insert(:user) assert {:error, "The status is over the character limit"} = CommonAPI.post(user, %{status: "foobar"}) - assert {:ok, activity} = CommonAPI.post(user, %{status: "12345"}) + assert {:ok, _activity} = CommonAPI.post(user, %{status: "12345"}) end test "it can handle activities that expire" do user = insert(:user) - expires_at = - NaiveDateTime.utc_now() - |> NaiveDateTime.truncate(:second) - |> NaiveDateTime.add(1_000_000, :second) + expires_at = DateTime.add(DateTime.utc_now(), 1_000_000) assert {:ok, activity} = CommonAPI.post(user, %{status: "chai", expires_in: 1_000_000}) - assert expiration = Pleroma.ActivityExpiration.get_by_activity_id(activity.id) - assert expiration.scheduled_at == expires_at + assert_enqueued( + worker: Pleroma.Workers.PurgeExpiredActivity, + args: %{activity_id: activity.id}, + scheduled_at: expires_at + ) end end @@ -687,6 +775,22 @@ defmodule Pleroma.Web.CommonAPITest do refute Visibility.visible_for_user?(announce_activity, nil) end + test "author can repeat own private statuses" do + author = insert(:user) + follower = insert(:user) + CommonAPI.follow(follower, author) + + {:ok, activity} = CommonAPI.post(author, %{status: "cofe", visibility: "private"}) + + {:ok, %Activity{} = announce_activity} = CommonAPI.repeat(activity.id, author) + + assert Visibility.is_private?(announce_activity) + refute Visibility.visible_for_user?(announce_activity, nil) + + assert Visibility.visible_for_user?(activity, follower) + assert {:error, :not_found} = CommonAPI.repeat(activity.id, follower) + end + test "favoriting a status" do user = insert(:user) other_user = insert(:user) @@ -720,7 +824,7 @@ defmodule Pleroma.Web.CommonAPITest do describe "pinned statuses" do setup do - Pleroma.Config.put([:instance, :max_pinned_statuses], 1) + clear_config([:instance, :max_pinned_statuses], 1) user = insert(:user) {:ok, activity} = CommonAPI.post(user, %{status: "HI!!!"}) @@ -728,13 +832,17 @@ defmodule Pleroma.Web.CommonAPITest do [user: user, activity: activity] end + test "activity not found error", %{user: user} do + assert {:error, :not_found} = CommonAPI.pin("id", user) + end + test "pin status", %{user: user, activity: activity} do assert {:ok, ^activity} = CommonAPI.pin(activity.id, user) - id = activity.id + %{data: %{"id" => object_id}} = Object.normalize(activity) user = refresh_record(user) - assert %User{pinned_activities: [^id]} = user + assert user.pinned_objects |> Map.keys() == [object_id] end test "pin poll", %{user: user} do @@ -746,10 +854,11 @@ defmodule Pleroma.Web.CommonAPITest do assert {:ok, ^activity} = CommonAPI.pin(activity.id, user) - id = activity.id + %{data: %{"id" => object_id}} = Object.normalize(activity) + user = refresh_record(user) - assert %User{pinned_activities: [^id]} = user + assert user.pinned_objects |> Map.keys() == [object_id] end test "unlisted statuses can be pinned", %{user: user} do @@ -760,7 +869,7 @@ defmodule Pleroma.Web.CommonAPITest do test "only self-authored can be pinned", %{activity: activity} do user = insert(:user) - assert {:error, "Could not pin"} = CommonAPI.pin(activity.id, user) + assert {:error, :ownership_error} = CommonAPI.pin(activity.id, user) end test "max pinned statuses", %{user: user, activity: activity_one} do @@ -770,8 +879,12 @@ defmodule Pleroma.Web.CommonAPITest do user = refresh_record(user) - assert {:error, "You have already pinned the maximum number of statuses"} = - CommonAPI.pin(activity_two.id, user) + assert {:error, :pinned_statuses_limit_reached} = CommonAPI.pin(activity_two.id, user) + end + + test "only public can be pinned", %{user: user} do + {:ok, activity} = CommonAPI.post(user, %{status: "private status", visibility: "private"}) + {:error, :visibility_error} = CommonAPI.pin(activity.id, user) end test "unpin status", %{user: user, activity: activity} do @@ -785,7 +898,7 @@ defmodule Pleroma.Web.CommonAPITest do user = refresh_record(user) - assert %User{pinned_activities: []} = user + assert user.pinned_objects == %{} end test "should unpin when deleting a status", %{user: user, activity: activity} do @@ -797,7 +910,40 @@ defmodule Pleroma.Web.CommonAPITest do user = refresh_record(user) - assert %User{pinned_activities: []} = user + assert user.pinned_objects == %{} + end + + test "ephemeral activity won't be deleted if was pinned", %{user: user} do + {:ok, activity} = CommonAPI.post(user, %{status: "Hello!", expires_in: 601}) + + assert Pleroma.Workers.PurgeExpiredActivity.get_expiration(activity.id) + + {:ok, _activity} = CommonAPI.pin(activity.id, user) + refute Pleroma.Workers.PurgeExpiredActivity.get_expiration(activity.id) + + user = refresh_record(user) + {:ok, _} = CommonAPI.unpin(activity.id, user) + + # recreates expiration job on unpin + assert Pleroma.Workers.PurgeExpiredActivity.get_expiration(activity.id) + end + + test "ephemeral activity deletion job won't be deleted on pinning error", %{ + user: user, + activity: activity + } do + clear_config([:instance, :max_pinned_statuses], 1) + + {:ok, _activity} = CommonAPI.pin(activity.id, user) + + {:ok, activity2} = CommonAPI.post(user, %{status: "another status", expires_in: 601}) + + assert Pleroma.Workers.PurgeExpiredActivity.get_expiration(activity2.id) + + user = refresh_record(user) + {:error, :pinned_statuses_limit_reached} = CommonAPI.pin(activity2.id, user) + + assert Pleroma.Workers.PurgeExpiredActivity.get_expiration(activity2.id) end end @@ -878,12 +1024,34 @@ defmodule Pleroma.Web.CommonAPITest do assert CommonAPI.thread_muted?(user, activity) end + test "add expiring mute", %{user: user, activity: activity} do + {:ok, _} = CommonAPI.add_mute(user, activity, %{expires_in: 60}) + assert CommonAPI.thread_muted?(user, activity) + + worker = Pleroma.Workers.MuteExpireWorker + args = %{"op" => "unmute_conversation", "user_id" => user.id, "activity_id" => activity.id} + + assert_enqueued( + worker: worker, + args: args + ) + + assert :ok = perform_job(worker, args) + refute CommonAPI.thread_muted?(user, activity) + end + test "remove mute", %{user: user, activity: activity} do CommonAPI.add_mute(user, activity) {:ok, _} = CommonAPI.remove_mute(user, activity) refute CommonAPI.thread_muted?(user, activity) end + test "remove mute by ids", %{user: user, activity: activity} do + CommonAPI.add_mute(user, activity) + {:ok, _} = CommonAPI.remove_mute(user.id, activity.id) + refute CommonAPI.thread_muted?(user, activity) + end + test "check that mutes can't be duplicate", %{user: user, activity: activity} do CommonAPI.add_mute(user, activity) {:error, _} = CommonAPI.add_mute(user, activity) @@ -1041,7 +1209,7 @@ defmodule Pleroma.Web.CommonAPITest do test "cancels a pending follow for a local user" do follower = insert(:user) - followed = insert(:user, locked: true) + followed = insert(:user, is_locked: true) assert {:ok, follower, followed, %{id: activity_id, data: %{"state" => "pending"}}} = CommonAPI.follow(follower, followed) @@ -1063,7 +1231,7 @@ defmodule Pleroma.Web.CommonAPITest do test "cancels a pending follow for a remote user" do follower = insert(:user) - followed = insert(:user, locked: true, local: false, ap_enabled: true) + followed = insert(:user, is_locked: true, local: false, ap_enabled: true) assert {:ok, follower, followed, %{id: activity_id, data: %{"state" => "pending"}}} = CommonAPI.follow(follower, followed) @@ -1086,7 +1254,7 @@ defmodule Pleroma.Web.CommonAPITest do describe "accept_follow_request/2" do test "after acceptance, it sets all existing pending follow request states to 'accept'" do - user = insert(:user, locked: true) + user = insert(:user, is_locked: true) follower = insert(:user) follower_two = insert(:user) @@ -1106,7 +1274,7 @@ defmodule Pleroma.Web.CommonAPITest do end test "after rejection, it sets all existing pending follow request states to 'reject'" do - user = insert(:user, locked: true) + user = insert(:user, is_locked: true) follower = insert(:user) follower_two = insert(:user) @@ -1126,7 +1294,7 @@ defmodule Pleroma.Web.CommonAPITest do end test "doesn't create a following relationship if the corresponding follow request doesn't exist" do - user = insert(:user, locked: true) + user = insert(:user, is_locked: true) not_follower = insert(:user) CommonAPI.accept_follow_request(not_follower, user) @@ -1145,7 +1313,7 @@ defmodule Pleroma.Web.CommonAPITest do poll: %{options: ["Yes", "No"], expires_in: 20} }) - object = Object.normalize(activity) + object = Object.normalize(activity, fetch: false) {:ok, _, object} = CommonAPI.vote(other_user, object, [0]) @@ -1165,7 +1333,7 @@ defmodule Pleroma.Web.CommonAPITest do length: 180_000 }) - object = Object.normalize(activity) + object = Object.normalize(activity, fetch: false) assert object.data["title"] == "lain radio episode 1" @@ -1184,11 +1352,155 @@ defmodule Pleroma.Web.CommonAPITest do visibility: "private" }) - object = Object.normalize(activity) + object = Object.normalize(activity, fetch: false) assert object.data["title"] == "lain radio episode 1" assert Visibility.get_visibility(activity) == "private" end end + + describe "get_user/1" do + test "gets user by ap_id" do + user = insert(:user) + assert CommonAPI.get_user(user.ap_id) == user + end + + test "gets user by guessed nickname" do + user = insert(:user, ap_id: "", nickname: "mario@mushroom.kingdom") + assert CommonAPI.get_user("https://mushroom.kingdom/users/mario") == user + end + + test "fallback" do + assert %User{ + name: "", + ap_id: "", + nickname: "erroruser@example.com" + } = CommonAPI.get_user("") + end + end + + describe "with `local` visibility" do + setup do: clear_config([:instance, :federating], true) + + test "post" do + user = insert(:user) + + with_mock Pleroma.Web.Federator, publish: fn _ -> :ok end do + {:ok, activity} = CommonAPI.post(user, %{status: "#2hu #2HU", visibility: "local"}) + + assert Visibility.is_local_public?(activity) + assert_not_called(Pleroma.Web.Federator.publish(activity)) + end + end + + test "delete" do + user = insert(:user) + + {:ok, %Activity{id: activity_id}} = + CommonAPI.post(user, %{status: "#2hu #2HU", visibility: "local"}) + + with_mock Pleroma.Web.Federator, publish: fn _ -> :ok end do + assert {:ok, %Activity{data: %{"deleted_activity_id" => ^activity_id}} = activity} = + CommonAPI.delete(activity_id, user) + + assert Visibility.is_local_public?(activity) + assert_not_called(Pleroma.Web.Federator.publish(activity)) + end + end + + test "repeat" do + user = insert(:user) + other_user = insert(:user) + + {:ok, %Activity{id: activity_id}} = + CommonAPI.post(other_user, %{status: "cofe", visibility: "local"}) + + with_mock Pleroma.Web.Federator, publish: fn _ -> :ok end do + assert {:ok, %Activity{data: %{"type" => "Announce"}} = activity} = + CommonAPI.repeat(activity_id, user) + + assert Visibility.is_local_public?(activity) + refute called(Pleroma.Web.Federator.publish(activity)) + end + end + + test "unrepeat" do + user = insert(:user) + other_user = insert(:user) + + {:ok, %Activity{id: activity_id}} = + CommonAPI.post(other_user, %{status: "cofe", visibility: "local"}) + + assert {:ok, _} = CommonAPI.repeat(activity_id, user) + + with_mock Pleroma.Web.Federator, publish: fn _ -> :ok end do + assert {:ok, %Activity{data: %{"type" => "Undo"}} = activity} = + CommonAPI.unrepeat(activity_id, user) + + assert Visibility.is_local_public?(activity) + refute called(Pleroma.Web.Federator.publish(activity)) + end + end + + test "favorite" do + user = insert(:user) + other_user = insert(:user) + + {:ok, activity} = CommonAPI.post(other_user, %{status: "cofe", visibility: "local"}) + + with_mock Pleroma.Web.Federator, publish: fn _ -> :ok end do + assert {:ok, %Activity{data: %{"type" => "Like"}} = activity} = + CommonAPI.favorite(user, activity.id) + + assert Visibility.is_local_public?(activity) + refute called(Pleroma.Web.Federator.publish(activity)) + end + end + + test "unfavorite" do + user = insert(:user) + other_user = insert(:user) + + {:ok, activity} = CommonAPI.post(other_user, %{status: "cofe", visibility: "local"}) + + {:ok, %Activity{}} = CommonAPI.favorite(user, activity.id) + + with_mock Pleroma.Web.Federator, publish: fn _ -> :ok end do + assert {:ok, activity} = CommonAPI.unfavorite(activity.id, user) + assert Visibility.is_local_public?(activity) + refute called(Pleroma.Web.Federator.publish(activity)) + end + end + + test "react_with_emoji" do + user = insert(:user) + other_user = insert(:user) + {:ok, activity} = CommonAPI.post(other_user, %{status: "cofe", visibility: "local"}) + + with_mock Pleroma.Web.Federator, publish: fn _ -> :ok end do + assert {:ok, %Activity{data: %{"type" => "EmojiReact"}} = activity} = + CommonAPI.react_with_emoji(activity.id, user, "👍") + + assert Visibility.is_local_public?(activity) + refute called(Pleroma.Web.Federator.publish(activity)) + end + end + + test "unreact_with_emoji" do + user = insert(:user) + other_user = insert(:user) + {:ok, activity} = CommonAPI.post(other_user, %{status: "cofe", visibility: "local"}) + + {:ok, _reaction} = CommonAPI.react_with_emoji(activity.id, user, "👍") + + with_mock Pleroma.Web.Federator, publish: fn _ -> :ok end do + assert {:ok, %Activity{data: %{"type" => "Undo"}} = activity} = + CommonAPI.unreact_with_emoji(activity.id, user, "👍") + + assert Visibility.is_local_public?(activity) + refute called(Pleroma.Web.Federator.publish(activity)) + end + end + end end diff --git a/test/pleroma/web/endpoint/metrics_exporter_test.exs b/test/pleroma/web/endpoint/metrics_exporter_test.exs new file mode 100644 index 000000000..376e82149 --- /dev/null +++ b/test/pleroma/web/endpoint/metrics_exporter_test.exs @@ -0,0 +1,69 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.Endpoint.MetricsExporterTest do + # Modifies AppEnv, has to stay synchronous + use Pleroma.Web.ConnCase + + alias Pleroma.Web.Endpoint.MetricsExporter + + defp config do + Application.get_env(:prometheus, MetricsExporter) + end + + describe "with default config" do + test "does NOT expose app metrics", %{conn: conn} do + conn + |> get(config()[:path]) + |> json_response(404) + end + end + + describe "when enabled" do + setup do + initial_config = config() + on_exit(fn -> Application.put_env(:prometheus, MetricsExporter, initial_config) end) + + Application.put_env( + :prometheus, + MetricsExporter, + Keyword.put(initial_config, :enabled, true) + ) + end + + test "serves app metrics", %{conn: conn} do + conn = get(conn, config()[:path]) + assert response = response(conn, 200) + + for metric <- [ + "http_requests_total", + "http_request_duration_microseconds", + "phoenix_controller_call_duration", + "telemetry_scrape_duration", + "erlang_vm_memory_atom_bytes_total" + ] do + assert response =~ ~r/#{metric}/ + end + end + + test "when IP whitelist configured, " <> + "serves app metrics only if client IP is whitelisted", + %{conn: conn} do + Application.put_env( + :prometheus, + MetricsExporter, + Keyword.put(config(), :ip_whitelist, ["127.127.127.127", {1, 1, 1, 1}, '255.255.255.255']) + ) + + conn + |> get(config()[:path]) + |> json_response(404) + + conn + |> Map.put(:remote_ip, {127, 127, 127, 127}) + |> get(config()[:path]) + |> response(200) + end + end +end diff --git a/test/web/fallback_test.exs b/test/pleroma/web/fallback_test.exs index a65865860..512baf813 100644 --- a/test/web/fallback_test.exs +++ b/test/pleroma/web/fallback_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.FallbackTest do @@ -20,15 +20,26 @@ defmodule Pleroma.Web.FallbackTest do end end + test "GET /*path adds a title", %{conn: conn} do + clear_config([:instance, :name], "a cool title") + + assert conn + |> get("/") + |> html_response(200) =~ "<title>a cool title</title>" + end + describe "preloaded data and metadata attached to" do test "GET /:maybe_nickname_or_id", %{conn: conn} do + clear_config([:instance, :name], "a cool title") + user = insert(:user) user_missing = get(conn, "/foo") user_present = get(conn, "/#{user.nickname}") - assert(html_response(user_missing, 200) =~ "<!--server-generated-meta-->") + assert html_response(user_missing, 200) =~ "<!--server-generated-meta-->" refute html_response(user_present, 200) =~ "<!--server-generated-meta-->" assert html_response(user_present, 200) =~ "initial-results" + assert html_response(user_present, 200) =~ "<title>a cool title</title>" end test "GET /*path", %{conn: conn} do @@ -44,10 +55,13 @@ defmodule Pleroma.Web.FallbackTest do describe "preloaded data is attached to" do test "GET /main/public", %{conn: conn} do + clear_config([:instance, :name], "a cool title") + public_page = get(conn, "/main/public") refute html_response(public_page, 200) =~ "<!--server-generated-meta-->" assert html_response(public_page, 200) =~ "initial-results" + assert html_response(public_page, 200) =~ "<title>a cool title</title>" end test "GET /main/all", %{conn: conn} do diff --git a/test/web/federator_test.exs b/test/pleroma/web/federator_test.exs index 592fdccd1..372b6a73a 100644 --- a/test/web/federator_test.exs +++ b/test/pleroma/web/federator_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.FederatorTest do @@ -56,7 +56,7 @@ defmodule Pleroma.Web.FederatorTest do activity: activity, relay_mock: relay_mock } do - Pleroma.Config.put([:instance, :allow_relay], false) + clear_config([:instance, :allow_relay], false) with_mocks([relay_mock]) do Federator.publish(activity) @@ -123,7 +123,8 @@ defmodule Pleroma.Web.FederatorTest do "type" => "Note", "content" => "hi world!", "id" => "http://mastodon.example.org/users/admin/objects/1", - "attributedTo" => "http://mastodon.example.org/users/admin" + "attributedTo" => "http://mastodon.example.org/users/admin", + "to" => ["https://www.w3.org/ns/activitystreams#Public"] }, "to" => ["https://www.w3.org/ns/activitystreams#Public"] } @@ -145,7 +146,8 @@ defmodule Pleroma.Web.FederatorTest do "type" => "Note", "content" => "hi world!", "id" => "http://mastodon.example.org/users/admin/objects/1", - "attributedTo" => "http://mastodon.example.org/users/admin" + "attributedTo" => "http://mastodon.example.org/users/admin", + "to" => ["https://www.w3.org/ns/activitystreams#Public"] }, "to" => ["https://www.w3.org/ns/activitystreams#Public"] } @@ -155,16 +157,16 @@ defmodule Pleroma.Web.FederatorTest do end test "it does not crash if MRF rejects the post" do - Pleroma.Config.put([:mrf_keyword, :reject], ["lain"]) + clear_config([:mrf_keyword, :reject], ["lain"]) - Pleroma.Config.put( + clear_config( [:mrf, :policies], Pleroma.Web.ActivityPub.MRF.KeywordPolicy ) params = File.read!("test/fixtures/mastodon-post-activity.json") - |> Poison.decode!() + |> Jason.decode!() assert {:ok, job} = Federator.incoming_ap_doc(params) assert {:error, _} = ObanHelpers.perform(job) diff --git a/test/web/feed/tag_controller_test.exs b/test/pleroma/web/feed/tag_controller_test.exs index 3c29cd94f..140cdb8bf 100644 --- a/test/web/feed/tag_controller_test.exs +++ b/test/pleroma/web/feed/tag_controller_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.Feed.TagControllerTest do @@ -15,7 +15,7 @@ defmodule Pleroma.Web.Feed.TagControllerTest do setup do: clear_config([:feed]) test "gets a feed (ATOM)", %{conn: conn} do - Pleroma.Config.put( + clear_config( [:feed, :post_title], %{max_length: 25, omission: "..."} ) @@ -23,7 +23,7 @@ defmodule Pleroma.Web.Feed.TagControllerTest do user = insert(:user) {:ok, activity1} = CommonAPI.post(user, %{status: "yeah #PleromaArt"}) - object = Object.normalize(activity1) + object = Object.normalize(activity1, fetch: false) object_data = Map.put(object.data, "attachment", [ @@ -82,7 +82,7 @@ defmodule Pleroma.Web.Feed.TagControllerTest do end test "gets a feed (RSS)", %{conn: conn} do - Pleroma.Config.put( + clear_config( [:feed, :post_title], %{max_length: 25, omission: "..."} ) @@ -90,7 +90,7 @@ defmodule Pleroma.Web.Feed.TagControllerTest do user = insert(:user) {:ok, activity1} = CommonAPI.post(user, %{status: "yeah #PleromaArt"}) - object = Object.normalize(activity1) + object = Object.normalize(activity1, fetch: false) object_data = Map.put(object.data, "attachment", [ @@ -127,10 +127,10 @@ defmodule Pleroma.Web.Feed.TagControllerTest do "These are public toots tagged with #pleromaart. You can interact with them if you have an account anywhere in the fediverse." assert xpath(xml, ~x"//channel/link/text()") == - '#{Pleroma.Web.base_url()}/tags/pleromaart.rss' + '#{Pleroma.Web.Endpoint.url()}/tags/pleromaart.rss' assert xpath(xml, ~x"//channel/webfeeds:logo/text()") == - '#{Pleroma.Web.base_url()}/static/logo.png' + '#{Pleroma.Web.Endpoint.url()}/static/logo.svg' assert xpath(xml, ~x"//channel/item/title/text()"l) == [ '42 This is :moominmamm...', @@ -146,8 +146,8 @@ defmodule Pleroma.Web.Feed.TagControllerTest do "https://peertube.moe/static/webseed/df5f464b-be8d-46fb-ad81-2d4c2d1630e3-480.mp4" ] - obj1 = Object.normalize(activity1) - obj2 = Object.normalize(activity2) + obj1 = Object.normalize(activity1, fetch: false) + obj2 = Object.normalize(activity2, fetch: false) assert xpath(xml, ~x"//channel/item/description/text()"sl) == [ HtmlEntities.decode(FeedView.activity_content(obj2.data)), @@ -157,7 +157,7 @@ defmodule Pleroma.Web.Feed.TagControllerTest do response = conn |> put_req_header("accept", "application/rss+xml") - |> get(tag_feed_path(conn, :feed, "pleromaart")) + |> get(tag_feed_path(conn, :feed, "pleromaart.rss")) |> response(200) xml = parse(response) @@ -181,4 +181,15 @@ defmodule Pleroma.Web.Feed.TagControllerTest do 'yeah #PleromaArt' ] end + + describe "private instance" do + setup do: clear_config([:instance, :public], false) + + test "returns 404 for tags feed", %{conn: conn} do + conn + |> put_req_header("accept", "application/rss+xml") + |> get(tag_feed_path(conn, :feed, "pleromaart.rss")) + |> response(404) + end + end end diff --git a/test/web/feed/user_controller_test.exs b/test/pleroma/web/feed/user_controller_test.exs index 0d2a61967..6e3f790b2 100644 --- a/test/web/feed/user_controller_test.exs +++ b/test/pleroma/web/feed/user_controller_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.Feed.UserControllerTest do @@ -8,20 +8,20 @@ defmodule Pleroma.Web.Feed.UserControllerTest do import Pleroma.Factory import SweetXml - alias Pleroma.Config alias Pleroma.Object alias Pleroma.User alias Pleroma.Web.CommonAPI + alias Pleroma.Web.Feed.FeedView - setup do: clear_config([:instance, :federating], true) + setup do: clear_config([:static_fe, :enabled], false) describe "feed" do setup do: clear_config([:feed]) - test "gets an atom feed", %{conn: conn} do - Config.put( + setup do + clear_config( [:feed, :post_title], - %{max_length: 10, omission: "..."} + %{max_length: 15, omission: "..."} ) activity = insert(:note_activity) @@ -29,7 +29,8 @@ defmodule Pleroma.Web.Feed.UserControllerTest do note = insert(:note, data: %{ - "content" => "This is :moominmamma: note ", + "content" => "This & this is :moominmamma: note ", + "source" => "This & this is :moominmamma: note ", "attachment" => [ %{ "url" => [ @@ -37,7 +38,9 @@ defmodule Pleroma.Web.Feed.UserControllerTest do ] } ], - "inReplyTo" => activity.data["id"] + "inReplyTo" => activity.data["id"], + "context" => "2hu & as", + "summary" => "2hu & as" } ) @@ -48,14 +51,18 @@ defmodule Pleroma.Web.Feed.UserControllerTest do insert(:note, user: user, data: %{ - "content" => "42 This is :moominmamma: note ", + "content" => "42 & This is :moominmamma: note ", "inReplyTo" => activity.data["id"] } ) note_activity2 = insert(:note_activity, note: note2) - object = Object.normalize(note_activity) + object = Object.normalize(note_activity, fetch: false) + + [user: user, object: object, max_id: note_activity2.id] + end + test "gets an atom feed", %{conn: conn, user: user, object: object, max_id: max_id} do resp = conn |> put_req_header("accept", "application/atom+xml") @@ -67,13 +74,15 @@ defmodule Pleroma.Web.Feed.UserControllerTest do |> SweetXml.parse() |> SweetXml.xpath(~x"//entry/title/text()"l) - assert activity_titles == ['42 This...', 'This is...'] - assert resp =~ object.data["content"] + assert activity_titles == ['42 & Thi...', 'This & t...'] + assert resp =~ FeedView.escape(object.data["content"]) + assert resp =~ FeedView.escape(object.data["summary"]) + assert resp =~ FeedView.escape(object.data["context"]) resp = conn |> put_req_header("accept", "application/atom+xml") - |> get("/users/#{user.nickname}/feed", %{"max_id" => note_activity2.id}) + |> get("/users/#{user.nickname}/feed", %{"max_id" => max_id}) |> response(200) activity_titles = @@ -81,47 +90,10 @@ defmodule Pleroma.Web.Feed.UserControllerTest do |> SweetXml.parse() |> SweetXml.xpath(~x"//entry/title/text()"l) - assert activity_titles == ['This is...'] + assert activity_titles == ['This & t...'] end - test "gets a rss feed", %{conn: conn} do - Pleroma.Config.put( - [:feed, :post_title], - %{max_length: 10, omission: "..."} - ) - - activity = insert(:note_activity) - - note = - insert(:note, - data: %{ - "content" => "This is :moominmamma: note ", - "attachment" => [ - %{ - "url" => [ - %{"mediaType" => "image/png", "href" => "https://pleroma.gov/image.png"} - ] - } - ], - "inReplyTo" => activity.data["id"] - } - ) - - note_activity = insert(:note_activity, note: note) - user = User.get_cached_by_ap_id(note_activity.data["actor"]) - - note2 = - insert(:note, - user: user, - data: %{ - "content" => "42 This is :moominmamma: note ", - "inReplyTo" => activity.data["id"] - } - ) - - note_activity2 = insert(:note_activity, note: note2) - object = Object.normalize(note_activity) - + test "gets a rss feed", %{conn: conn, user: user, object: object, max_id: max_id} do resp = conn |> put_req_header("accept", "application/rss+xml") @@ -133,13 +105,15 @@ defmodule Pleroma.Web.Feed.UserControllerTest do |> SweetXml.parse() |> SweetXml.xpath(~x"//item/title/text()"l) - assert activity_titles == ['42 This...', 'This is...'] - assert resp =~ object.data["content"] + assert activity_titles == ['42 & Thi...', 'This & t...'] + assert resp =~ FeedView.escape(object.data["content"]) + assert resp =~ FeedView.escape(object.data["summary"]) + assert resp =~ FeedView.escape(object.data["context"]) resp = conn |> put_req_header("accept", "application/rss+xml") - |> get("/users/#{user.nickname}/feed.rss", %{"max_id" => note_activity2.id}) + |> get("/users/#{user.nickname}/feed.rss", %{"max_id" => max_id}) |> response(200) activity_titles = @@ -147,7 +121,7 @@ defmodule Pleroma.Web.Feed.UserControllerTest do |> SweetXml.parse() |> SweetXml.xpath(~x"//item/title/text()"l) - assert activity_titles == ['This is...'] + assert activity_titles == ['This & t...'] end test "returns 404 for a missing feed", %{conn: conn} do @@ -192,6 +166,16 @@ defmodule Pleroma.Web.Feed.UserControllerTest do |> get(user_feed_path(conn, :feed, user.nickname)) |> response(404) end + + test "does not require authentication on non-federating instances", %{conn: conn} do + clear_config([:instance, :federating], false) + user = insert(:user) + + conn + |> put_req_header("accept", "application/rss+xml") + |> get("/users/#{user.nickname}/feed.rss") + |> response(200) + end end # Note: see ActivityPubControllerTest for JSON format tests @@ -206,19 +190,32 @@ defmodule Pleroma.Web.Feed.UserControllerTest do |> response(200) assert response == - Fallback.RedirectController.redirector_with_meta( + Pleroma.Web.Fallback.RedirectController.redirector_with_meta( conn, %{user: user} ).resp_body end - test "with html format, it returns error when user is not found", %{conn: conn} do + test "with html format, it falls back to frontend when user is remote", %{conn: conn} do + user = insert(:user, local: false) + + {:ok, _} = CommonAPI.post(user, %{status: "test"}) + + response = + conn + |> get("/users/#{user.nickname}") + |> response(200) + + assert response =~ "</html>" + end + + test "with html format, it falls back to frontend when user is not found", %{conn: conn} do response = conn |> get("/users/jimm") - |> json_response(404) + |> response(200) - assert response == %{"error" => "Not found"} + assert response =~ "</html>" end test "with non-html / non-json format, it redirects to user feed in atom format", %{ @@ -233,7 +230,9 @@ defmodule Pleroma.Web.Feed.UserControllerTest do |> get("/users/#{user.nickname}") assert conn.status == 302 - assert redirected_to(conn) == "#{Pleroma.Web.base_url()}/users/#{user.nickname}/feed.atom" + + assert redirected_to(conn) == + "#{Pleroma.Web.Endpoint.url()}/users/#{user.nickname}/feed.atom" end test "with non-html / non-json format, it returns error when user is not found", %{conn: conn} do @@ -246,4 +245,20 @@ defmodule Pleroma.Web.Feed.UserControllerTest do assert response == ~S({"error":"Not found"}) end end + + describe "private instance" do + setup do: clear_config([:instance, :public]) + + test "returns 404 for user feed", %{conn: conn} do + clear_config([:instance, :public], false) + user = insert(:user) + + {:ok, _} = CommonAPI.post(user, %{status: "test"}) + + assert conn + |> put_req_header("accept", "application/atom+xml") + |> get(user_feed_path(conn, :feed, user.nickname)) + |> response(404) + end + end end diff --git a/test/pleroma/web/manifest_controller_test.exs b/test/pleroma/web/manifest_controller_test.exs new file mode 100644 index 000000000..b7a4940db --- /dev/null +++ b/test/pleroma/web/manifest_controller_test.exs @@ -0,0 +1,17 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ManifestControllerTest do + use Pleroma.Web.ConnCase + + setup do + clear_config([:instance, :name], "Manifest Test") + clear_config([:manifest, :theme_color], "#ff0000") + end + + test "manifest.json", %{conn: conn} do + conn = get(conn, "/manifest.json") + assert %{"name" => "Manifest Test", "theme_color" => "#ff0000"} = json_response(conn, 200) + end +end diff --git a/test/web/mastodon_api/controllers/account_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/account_controller_test.exs index 17a1e7d66..374e2048a 100644 --- a/test/web/mastodon_api/controllers/account_controller_test.exs +++ b/test/pleroma/web/mastodon_api/controllers/account_controller_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do @@ -29,10 +29,49 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do |> json_response_and_validate_schema(404) end + test "relationship field" do + %{conn: conn, user: user} = oauth_access(["read"]) + + other_user = insert(:user) + + response = + conn + |> get("/api/v1/accounts/#{other_user.id}") + |> json_response_and_validate_schema(200) + + assert response["id"] == other_user.id + assert response["pleroma"]["relationship"] == %{} + + assert %{"pleroma" => %{"relationship" => %{"following" => false, "followed_by" => false}}} = + conn + |> get("/api/v1/accounts/#{other_user.id}?with_relationships=true") + |> json_response_and_validate_schema(200) + + {:ok, _, %{id: other_id}} = User.follow(user, other_user) + + assert %{ + "id" => ^other_id, + "pleroma" => %{"relationship" => %{"following" => true, "followed_by" => false}} + } = + conn + |> get("/api/v1/accounts/#{other_id}?with_relationships=true") + |> json_response_and_validate_schema(200) + + {:ok, _, _} = User.follow(other_user, user) + + assert %{ + "id" => ^other_id, + "pleroma" => %{"relationship" => %{"following" => true, "followed_by" => true}} + } = + conn + |> get("/api/v1/accounts/#{other_id}?with_relationships=true") + |> json_response_and_validate_schema(200) + end + test "works by nickname" do user = insert(:user) - assert %{"id" => user_id} = + assert %{"id" => _user_id} = build_conn() |> get("/api/v1/accounts/#{user.nickname}") |> json_response_and_validate_schema(200) @@ -43,7 +82,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do user = insert(:user, nickname: "user@example.com", local: false) - assert %{"id" => user_id} = + assert %{"id" => _user_id} = build_conn() |> get("/api/v1/accounts/#{user.nickname}") |> json_response_and_validate_schema(200) @@ -126,7 +165,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do end test "returns 404 for deactivated user", %{conn: conn} do - user = insert(:user, deactivated: true) + user = insert(:user, is_active: false) assert %{"error" => "Can't find user"} = conn @@ -256,7 +295,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do end test "deactivated user", %{conn: conn} do - user = insert(:user, deactivated: true) + user = insert(:user, is_active: false) assert %{"error" => "Can't find user"} == conn @@ -320,7 +359,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do user_two = insert(:user) user_three = insert(:user) - {:ok, _user_three} = User.follow(user_three, user_one) + {:ok, _user_three, _user_one} = User.follow(user_three, user_one) {:ok, activity} = CommonAPI.post(user_one, %{status: "HI!!!"}) @@ -380,7 +419,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do other_user = insert(:user) file = %Plug.Upload{ - content_type: "image/jpg", + content_type: "image/jpeg", path: Path.absname("test/fixtures/image.jpg"), filename: "an_image.jpg" } @@ -436,6 +475,54 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do conn = get(conn, "/api/v1/accounts/#{user.id}/statuses?exclude_visibilities[]=direct") assert [%{"id" => ^public_activity_id}] = json_response_and_validate_schema(conn, 200) end + + test "muted reactions", %{user: user, conn: conn} do + user2 = insert(:user) + User.mute(user, user2) + {:ok, activity} = CommonAPI.post(user, %{status: "."}) + {:ok, _} = CommonAPI.react_with_emoji(activity.id, user2, "🎅") + + result = + conn + |> get("/api/v1/accounts/#{user.id}/statuses") + |> json_response_and_validate_schema(200) + + assert [ + %{ + "pleroma" => %{ + "emoji_reactions" => [] + } + } + ] = result + + result = + conn + |> get("/api/v1/accounts/#{user.id}/statuses?with_muted=true") + |> json_response_and_validate_schema(200) + + assert [ + %{ + "pleroma" => %{ + "emoji_reactions" => [%{"count" => 1, "me" => false, "name" => "🎅"}] + } + } + ] = result + end + + test "paginates a user's statuses", %{user: user, conn: conn} do + {:ok, post_1} = CommonAPI.post(user, %{status: "first post"}) + {:ok, post_2} = CommonAPI.post(user, %{status: "second post"}) + + response_1 = get(conn, "/api/v1/accounts/#{user.id}/statuses?limit=1") + assert [res] = json_response_and_validate_schema(response_1, 200) + assert res["id"] == post_2.id + + response_2 = get(conn, "/api/v1/accounts/#{user.id}/statuses?limit=1&max_id=#{res["id"]}") + assert [res] = json_response_and_validate_schema(response_2, 200) + assert res["id"] == post_1.id + + refute response_1 == response_2 + end end defp local_and_remote_activities(%{local: local, remote: remote}) do @@ -535,16 +622,55 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do test "getting followers", %{user: user, conn: conn} do other_user = insert(:user) - {:ok, %{id: user_id}} = User.follow(user, other_user) + {:ok, %{id: user_id}, other_user} = User.follow(user, other_user) conn = get(conn, "/api/v1/accounts/#{other_user.id}/followers") assert [%{"id" => ^user_id}] = json_response_and_validate_schema(conn, 200) end + test "following with relationship", %{conn: conn, user: user} do + other_user = insert(:user) + {:ok, %{id: id}, _} = User.follow(other_user, user) + + assert [ + %{ + "id" => ^id, + "pleroma" => %{ + "relationship" => %{ + "id" => ^id, + "following" => false, + "followed_by" => true + } + } + } + ] = + conn + |> get("/api/v1/accounts/#{user.id}/followers?with_relationships=true") + |> json_response_and_validate_schema(200) + + {:ok, _, _} = User.follow(user, other_user) + + assert [ + %{ + "id" => ^id, + "pleroma" => %{ + "relationship" => %{ + "id" => ^id, + "following" => true, + "followed_by" => true + } + } + } + ] = + conn + |> get("/api/v1/accounts/#{user.id}/followers?with_relationships=true") + |> json_response_and_validate_schema(200) + end + test "getting followers, hide_followers", %{user: user, conn: conn} do other_user = insert(:user, hide_followers: true) - {:ok, _user} = User.follow(user, other_user) + {:ok, _user, _other_user} = User.follow(user, other_user) conn = get(conn, "/api/v1/accounts/#{other_user.id}/followers") @@ -554,7 +680,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do test "getting followers, hide_followers, same user requesting" do user = insert(:user) other_user = insert(:user, hide_followers: true) - {:ok, _user} = User.follow(user, other_user) + {:ok, _user, _other_user} = User.follow(user, other_user) conn = build_conn() @@ -566,9 +692,9 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do end test "getting followers, pagination", %{user: user, conn: conn} do - {:ok, %User{id: follower1_id}} = :user |> insert() |> User.follow(user) - {:ok, %User{id: follower2_id}} = :user |> insert() |> User.follow(user) - {:ok, %User{id: follower3_id}} = :user |> insert() |> User.follow(user) + {:ok, %User{id: follower1_id}, _user} = :user |> insert() |> User.follow(user) + {:ok, %User{id: follower2_id}, _user} = :user |> insert() |> User.follow(user) + {:ok, %User{id: follower3_id}, _user} = :user |> insert() |> User.follow(user) assert [%{"id" => ^follower3_id}, %{"id" => ^follower2_id}] = conn @@ -583,9 +709,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do assert [%{"id" => ^follower2_id}, %{"id" => ^follower1_id}] = conn |> get( - "/api/v1/accounts/#{user.id}/followers?id=#{user.id}&limit=20&max_id=#{ - follower3_id - }" + "/api/v1/accounts/#{user.id}/followers?id=#{user.id}&limit=20&max_id=#{follower3_id}" ) |> json_response_and_validate_schema(200) @@ -604,7 +728,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do test "getting following", %{user: user, conn: conn} do other_user = insert(:user) - {:ok, user} = User.follow(user, other_user) + {:ok, user, other_user} = User.follow(user, other_user) conn = get(conn, "/api/v1/accounts/#{user.id}/following") @@ -612,10 +736,28 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do assert id == to_string(other_user.id) end + test "following with relationship", %{conn: conn, user: user} do + other_user = insert(:user) + {:ok, user, other_user} = User.follow(user, other_user) + + conn = get(conn, "/api/v1/accounts/#{user.id}/following?with_relationships=true") + + id = other_user.id + + assert [ + %{ + "id" => ^id, + "pleroma" => %{ + "relationship" => %{"id" => ^id, "following" => true, "followed_by" => false} + } + } + ] = json_response_and_validate_schema(conn, 200) + end + test "getting following, hide_follows, other user requesting" do user = insert(:user, hide_follows: true) other_user = insert(:user) - {:ok, user} = User.follow(user, other_user) + {:ok, user, other_user} = User.follow(user, other_user) conn = build_conn() @@ -629,7 +771,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do test "getting following, hide_follows, same user requesting" do user = insert(:user, hide_follows: true) other_user = insert(:user) - {:ok, user} = User.follow(user, other_user) + {:ok, user, _other_user} = User.follow(user, other_user) conn = build_conn() @@ -644,9 +786,9 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do following1 = insert(:user) following2 = insert(:user) following3 = insert(:user) - {:ok, _} = User.follow(user, following1) - {:ok, _} = User.follow(user, following2) - {:ok, _} = User.follow(user, following3) + {:ok, _, _} = User.follow(user, following1) + {:ok, _, _} = User.follow(user, following2) + {:ok, _, _} = User.follow(user, following3) res_conn = get(conn, "/api/v1/accounts/#{user.id}/following?since_id=#{following1.id}") @@ -706,7 +848,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do end test "cancelling follow request", %{conn: conn} do - %{id: other_user_id} = insert(:user, %{locked: true}) + %{id: other_user_id} = insert(:user, %{is_locked: true}) assert %{"id" => ^other_user_id, "following" => false, "requested" => true} = conn @@ -737,7 +879,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do assert [] == conn |> get("/api/v1/timelines/home") - |> json_response(200) + |> json_response_and_validate_schema(200) assert %{"showing_reblogs" => true} = conn @@ -748,7 +890,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do assert [%{"id" => ^reblog_id}] = conn |> get("/api/v1/timelines/home") - |> json_response(200) + |> json_response_and_validate_schema(200) end test "following with reblogs" do @@ -766,7 +908,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do assert [%{"id" => ^reblog_id}] = conn |> get("/api/v1/timelines/home") - |> json_response(200) + |> json_response_and_validate_schema(200) assert %{"showing_reblogs" => false} = conn @@ -777,7 +919,28 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do assert [] == conn |> get("/api/v1/timelines/home") - |> json_response(200) + |> json_response_and_validate_schema(200) + end + + test "following with subscription and unsubscribing" do + %{conn: conn} = oauth_access(["follow"]) + followed = insert(:user) + + ret_conn = + conn + |> put_req_header("content-type", "application/json") + |> post("/api/v1/accounts/#{followed.id}/follow", %{notify: true}) + + assert %{"id" => _id, "subscribing" => true} = + json_response_and_validate_schema(ret_conn, 200) + + ret_conn = + conn + |> put_req_header("content-type", "application/json") + |> post("/api/v1/accounts/#{followed.id}/follow", %{notify: false}) + + assert %{"id" => _id, "subscribing" => false} = + json_response_and_validate_schema(ret_conn, 200) end test "following / unfollowing errors", %{user: user, conn: conn} do @@ -959,7 +1122,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do assert %{"error" => "{\"email\":[\"Invalid email\"]}"} = json_response_and_validate_schema(conn, 400) - Pleroma.Config.put([User, :email_blacklist], []) + clear_config([User, :email_blacklist], []) conn = build_conn() @@ -979,8 +1142,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do user = Repo.preload(token_from_db, :user).user assert user - refute user.confirmation_pending - refute user.approval_pending + assert user.is_confirmed + assert user.is_approved end test "registers but does not log in with :account_activation_required", %{conn: conn} do @@ -1040,7 +1203,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do refute response["token_type"] user = Repo.get_by(User, email: "lain@example.org") - assert user.confirmation_pending + refute user.is_confirmed end test "registers but does not log in with :account_approval_required", %{conn: conn} do @@ -1102,7 +1265,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do user = Repo.get_by(User, email: "lain@example.org") - assert user.approval_pending + refute user.is_approved assert user.registration_reason == "I'm a cool dude, bro" end @@ -1378,8 +1541,6 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do |> json_response_and_validate_schema(:ok) assert Token |> Repo.get_by(token: access_token) |> Repo.preload(:user) |> Map.get(:user) - - Cachex.del(:used_captcha_cache, token) end test "returns 400 if any captcha field is not provided", %{conn: conn} do @@ -1429,10 +1590,10 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do test "returns lists to which the account belongs" do %{user: user, conn: conn} = oauth_access(["read:lists"]) other_user = insert(:user) - assert {:ok, %Pleroma.List{id: list_id} = list} = Pleroma.List.create("Test List", user) + assert {:ok, %Pleroma.List{id: _list_id} = list} = Pleroma.List.create("Test List", user) {:ok, %{following: _following}} = Pleroma.List.follow(list, other_user) - assert [%{"id" => list_id, "title" => "Test List"}] = + assert [%{"id" => _list_id, "title" => "Test List"}] = conn |> get("/api/v1/accounts/#{other_user.id}/lists") |> json_response_and_validate_schema(200) @@ -1442,7 +1603,10 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do describe "verify_credentials" do test "verify_credentials" do %{user: user, conn: conn} = oauth_access(["read:accounts"]) - [notification | _] = insert_list(7, :notification, user: user) + + [notification | _] = + insert_list(7, :notification, user: user, activity: insert(:note_activity)) + Pleroma.Notification.set_read_up_to(user, notification.id) conn = get(conn, "/api/v1/accounts/verify_credentials") @@ -1484,7 +1648,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do test "returns the relationships for the current user", %{user: user, conn: conn} do %{id: other_user_id} = other_user = insert(:user) - {:ok, _user} = User.follow(user, other_user) + {:ok, _user, _other_user} = User.follow(user, other_user) assert [%{"id" => ^other_user_id}] = conn @@ -1506,28 +1670,172 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do test "getting a list of mutes" do %{user: user, conn: conn} = oauth_access(["read:mutes"]) - other_user = insert(:user) + %{id: id1} = other_user1 = insert(:user) + %{id: id2} = other_user2 = insert(:user) + %{id: id3} = other_user3 = insert(:user) - {:ok, _user_relationships} = User.mute(user, other_user) + {:ok, _user_relationships} = User.mute(user, other_user1) + {:ok, _user_relationships} = User.mute(user, other_user2) + {:ok, _user_relationships} = User.mute(user, other_user3) + + result = + conn + |> get("/api/v1/mutes") + |> json_response_and_validate_schema(200) - conn = get(conn, "/api/v1/mutes") + assert [id1, id2, id3] == Enum.map(result, & &1["id"]) - other_user_id = to_string(other_user.id) - assert [%{"id" => ^other_user_id}] = json_response_and_validate_schema(conn, 200) + result = + conn + |> get("/api/v1/mutes?limit=1") + |> json_response_and_validate_schema(200) + + assert [%{"id" => ^id1}] = result + + result = + conn + |> get("/api/v1/mutes?since_id=#{id1}") + |> json_response_and_validate_schema(200) + + assert [%{"id" => ^id2}, %{"id" => ^id3}] = result + + result = + conn + |> get("/api/v1/mutes?since_id=#{id1}&max_id=#{id3}") + |> json_response_and_validate_schema(200) + + assert [%{"id" => ^id2}] = result + + result = + conn + |> get("/api/v1/mutes?since_id=#{id1}&limit=1") + |> json_response_and_validate_schema(200) + + assert [%{"id" => ^id2}] = result + end + + test "list of mutes with with_relationships parameter" do + %{user: user, conn: conn} = oauth_access(["read:mutes"]) + %{id: id1} = other_user1 = insert(:user) + %{id: id2} = other_user2 = insert(:user) + %{id: id3} = other_user3 = insert(:user) + + {:ok, _, _} = User.follow(other_user1, user) + {:ok, _, _} = User.follow(other_user2, user) + {:ok, _, _} = User.follow(other_user3, user) + + {:ok, _} = User.mute(user, other_user1) + {:ok, _} = User.mute(user, other_user2) + {:ok, _} = User.mute(user, other_user3) + + assert [ + %{ + "id" => ^id1, + "pleroma" => %{"relationship" => %{"muting" => true, "followed_by" => true}} + }, + %{ + "id" => ^id2, + "pleroma" => %{"relationship" => %{"muting" => true, "followed_by" => true}} + }, + %{ + "id" => ^id3, + "pleroma" => %{"relationship" => %{"muting" => true, "followed_by" => true}} + } + ] = + conn + |> get("/api/v1/mutes?with_relationships=true") + |> json_response_and_validate_schema(200) end test "getting a list of blocks" do %{user: user, conn: conn} = oauth_access(["read:blocks"]) - other_user = insert(:user) + %{id: id1} = other_user1 = insert(:user) + %{id: id2} = other_user2 = insert(:user) + %{id: id3} = other_user3 = insert(:user) - {:ok, _user_relationship} = User.block(user, other_user) + {:ok, _user_relationship} = User.block(user, other_user1) + {:ok, _user_relationship} = User.block(user, other_user3) + {:ok, _user_relationship} = User.block(user, other_user2) - conn = + result = conn |> assign(:user, user) |> get("/api/v1/blocks") + |> json_response_and_validate_schema(200) + + assert [id1, id2, id3] == Enum.map(result, & &1["id"]) + + result = + conn + |> assign(:user, user) + |> get("/api/v1/blocks?limit=1") + |> json_response_and_validate_schema(200) + + assert [%{"id" => ^id1}] = result + + result = + conn + |> assign(:user, user) + |> get("/api/v1/blocks?since_id=#{id1}") + |> json_response_and_validate_schema(200) + + assert [%{"id" => ^id2}, %{"id" => ^id3}] = result + + result = + conn + |> assign(:user, user) + |> get("/api/v1/blocks?since_id=#{id1}&max_id=#{id3}") + |> json_response_and_validate_schema(200) + + assert [%{"id" => ^id2}] = result + + result = + conn + |> assign(:user, user) + |> get("/api/v1/blocks?since_id=#{id1}&limit=1") + |> json_response_and_validate_schema(200) + + assert [%{"id" => ^id2}] = result + end + + test "account lookup", %{conn: conn} do + %{nickname: acct} = insert(:user, %{nickname: "nickname"}) + %{nickname: acct_two} = insert(:user, %{nickname: "nickname@notlocaldoma.in"}) + + result = + conn + |> get("/api/v1/accounts/lookup?acct=#{acct}") + |> json_response_and_validate_schema(200) + + assert %{"acct" => ^acct} = result + + result = + conn + |> get("/api/v1/accounts/lookup?acct=#{acct_two}") + |> json_response_and_validate_schema(200) + + assert %{"acct" => ^acct_two} = result + + _result = + conn + |> get("/api/v1/accounts/lookup?acct=unexisting_nickname") + |> json_response_and_validate_schema(404) + end + + test "create a note on a user" do + %{conn: conn} = oauth_access(["write:accounts", "read:follows"]) + other_user = insert(:user) - other_user_id = to_string(other_user.id) - assert [%{"id" => ^other_user_id}] = json_response_and_validate_schema(conn, 200) + conn + |> put_req_header("content-type", "application/json") + |> post("/api/v1/accounts/#{other_user.id}/note", %{ + "comment" => "Example note" + }) + + assert [%{"note" => "Example note"}] = + conn + |> put_req_header("content-type", "application/json") + |> get("/api/v1/accounts/relationships?id=#{other_user.id}") + |> json_response_and_validate_schema(200) end end diff --git a/test/web/mastodon_api/controllers/app_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/app_controller_test.exs index a0b8b126c..bfbb7f32d 100644 --- a/test/web/mastodon_api/controllers/app_controller_test.exs +++ b/test/pleroma/web/mastodon_api/controllers/app_controller_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.MastodonAPI.AppControllerTest do @@ -12,25 +12,56 @@ defmodule Pleroma.Web.MastodonAPI.AppControllerTest do import Pleroma.Factory test "apps/verify_credentials", %{conn: conn} do - token = insert(:oauth_token) + user_bound_token = insert(:oauth_token) + app_bound_token = insert(:oauth_token, user: nil) + refute app_bound_token.user + + for token <- [app_bound_token, user_bound_token] do + conn = + conn + |> put_req_header("authorization", "Bearer #{token.token}") + |> get("/api/v1/apps/verify_credentials") + + app = Repo.preload(token, :app).app + + expected = %{ + "name" => app.client_name, + "website" => app.website, + "vapid_key" => Push.vapid_config() |> Keyword.get(:public_key) + } + + assert expected == json_response_and_validate_schema(conn, 200) + end + end + + test "creates an oauth app", %{conn: conn} do + app_attrs = build(:oauth_app) conn = conn - |> put_req_header("authorization", "Bearer #{token.token}") - |> get("/api/v1/apps/verify_credentials") + |> put_req_header("content-type", "application/json") + |> post("/api/v1/apps", %{ + client_name: app_attrs.client_name, + redirect_uris: app_attrs.redirect_uris + }) - app = Repo.preload(token, :app).app + [app] = Repo.all(App) expected = %{ "name" => app.client_name, "website" => app.website, + "client_id" => app.client_id, + "client_secret" => app.client_secret, + "id" => app.id |> to_string(), + "redirect_uri" => app.redirect_uris, "vapid_key" => Push.vapid_config() |> Keyword.get(:public_key) } assert expected == json_response_and_validate_schema(conn, 200) + assert app.user_id == nil end - test "creates an oauth app", %{conn: conn} do + test "creates an oauth app with a user", %{conn: conn} do user = insert(:user) app_attrs = build(:oauth_app) @@ -56,5 +87,6 @@ defmodule Pleroma.Web.MastodonAPI.AppControllerTest do } assert expected == json_response_and_validate_schema(conn, 200) + assert app.user_id == user.id end end diff --git a/test/web/mastodon_api/controllers/conversation_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/conversation_controller_test.exs index 3e21e6bf1..00797a9ea 100644 --- a/test/web/mastodon_api/controllers/conversation_controller_test.exs +++ b/test/pleroma/web/mastodon_api/controllers/conversation_controller_test.exs @@ -1,10 +1,11 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.MastodonAPI.ConversationControllerTest do - use Pleroma.Web.ConnCase + use Pleroma.Web.ConnCase, async: true + alias Pleroma.Conversation.Participation alias Pleroma.User alias Pleroma.Web.CommonAPI @@ -17,7 +18,7 @@ defmodule Pleroma.Web.MastodonAPI.ConversationControllerTest do user_two = insert(:user) user_three = insert(:user) - {:ok, user_two} = User.follow(user_two, user_one) + {:ok, user_two, user_one} = User.follow(user_two, user_one) {:ok, %{user: user_one, user_two: user_two, user_three: user_three, conn: conn}} end @@ -28,10 +29,10 @@ defmodule Pleroma.Web.MastodonAPI.ConversationControllerTest do user_three: user_three, conn: conn } do - assert User.get_cached_by_id(user_two.id).unread_conversation_count == 0 + assert Participation.unread_count(user_two) == 0 {:ok, direct} = create_direct_message(user_one, [user_two, user_three]) - assert User.get_cached_by_id(user_two.id).unread_conversation_count == 1 + assert Participation.unread_count(user_two) == 1 {:ok, _follower_only} = CommonAPI.post(user_one, %{ @@ -54,12 +55,33 @@ defmodule Pleroma.Web.MastodonAPI.ConversationControllerTest do account_ids = Enum.map(res_accounts, & &1["id"]) assert length(res_accounts) == 2 + assert user_one.id not in account_ids assert user_two.id in account_ids assert user_three.id in account_ids assert is_binary(res_id) assert unread == false assert res_last_status["id"] == direct.id - assert User.get_cached_by_id(user_one.id).unread_conversation_count == 0 + assert res_last_status["account"]["id"] == user_one.id + assert Participation.unread_count(user_one) == 0 + end + + test "includes the user if the user is the only participant", %{ + user: user_one, + conn: conn + } do + {:ok, _direct} = create_direct_message(user_one, []) + + res_conn = get(conn, "/api/v1/conversations") + + assert response = json_response_and_validate_schema(res_conn, 200) + + assert [ + %{ + "accounts" => [account] + } + ] = response + + assert user_one.id == account["id"] end test "observes limit params", %{ @@ -134,8 +156,8 @@ defmodule Pleroma.Web.MastodonAPI.ConversationControllerTest do user_two = insert(:user) {:ok, direct} = create_direct_message(user_one, [user_two]) - assert User.get_cached_by_id(user_one.id).unread_conversation_count == 0 - assert User.get_cached_by_id(user_two.id).unread_conversation_count == 1 + assert Participation.unread_count(user_one) == 0 + assert Participation.unread_count(user_two) == 1 user_two_conn = build_conn() @@ -155,8 +177,8 @@ defmodule Pleroma.Web.MastodonAPI.ConversationControllerTest do |> post("/api/v1/conversations/#{direct_conversation_id}/read") |> json_response_and_validate_schema(200) - assert User.get_cached_by_id(user_one.id).unread_conversation_count == 0 - assert User.get_cached_by_id(user_two.id).unread_conversation_count == 0 + assert Participation.unread_count(user_one) == 0 + assert Participation.unread_count(user_two) == 0 # The conversation is marked as unread on reply {:ok, _} = @@ -171,8 +193,8 @@ defmodule Pleroma.Web.MastodonAPI.ConversationControllerTest do |> get("/api/v1/conversations") |> json_response_and_validate_schema(200) - assert User.get_cached_by_id(user_one.id).unread_conversation_count == 1 - assert User.get_cached_by_id(user_two.id).unread_conversation_count == 0 + assert Participation.unread_count(user_one) == 1 + assert Participation.unread_count(user_two) == 0 # A reply doesn't increment the user's unread_conversation_count if the conversation is unread {:ok, _} = @@ -182,8 +204,8 @@ defmodule Pleroma.Web.MastodonAPI.ConversationControllerTest do in_reply_to_status_id: direct.id }) - assert User.get_cached_by_id(user_one.id).unread_conversation_count == 1 - assert User.get_cached_by_id(user_two.id).unread_conversation_count == 0 + assert Participation.unread_count(user_one) == 1 + assert Participation.unread_count(user_two) == 0 end test "(vanilla) Mastodon frontend behaviour", %{user: user_one, conn: conn} do @@ -192,7 +214,34 @@ defmodule Pleroma.Web.MastodonAPI.ConversationControllerTest do res_conn = get(conn, "/api/v1/statuses/#{direct.id}/context") - assert %{"ancestors" => [], "descendants" => []} == json_response(res_conn, 200) + assert %{"ancestors" => [], "descendants" => []} == + json_response_and_validate_schema(res_conn, 200) + end + + test "Removes a conversation", %{user: user_one, conn: conn} do + user_two = insert(:user) + token = insert(:oauth_token, user: user_one, scopes: ["read:statuses", "write:conversations"]) + + {:ok, _direct} = create_direct_message(user_one, [user_two]) + {:ok, _direct} = create_direct_message(user_one, [user_two]) + + assert [%{"id" => conv1_id}, %{"id" => conv2_id}] = + conn + |> assign(:token, token) + |> get("/api/v1/conversations") + |> json_response_and_validate_schema(200) + + assert %{} = + conn + |> assign(:token, token) + |> delete("/api/v1/conversations/#{conv1_id}") + |> json_response_and_validate_schema(200) + + assert [%{"id" => ^conv2_id}] = + conn + |> assign(:token, token) + |> get("/api/v1/conversations") + |> json_response_and_validate_schema(200) end defp create_direct_message(sender, recips) do diff --git a/test/web/mastodon_api/controllers/custom_emoji_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/custom_emoji_controller_test.exs index ab0027f90..cbb1d54a6 100644 --- a/test/web/mastodon_api/controllers/custom_emoji_controller_test.exs +++ b/test/pleroma/web/mastodon_api/controllers/custom_emoji_controller_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.MastodonAPI.CustomEmojiControllerTest do diff --git a/test/pleroma/web/mastodon_api/controllers/directory_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/directory_controller_test.exs new file mode 100644 index 000000000..b8f55f832 --- /dev/null +++ b/test/pleroma/web/mastodon_api/controllers/directory_controller_test.exs @@ -0,0 +1,46 @@ +defmodule Pleroma.Web.MastodonAPI.DirectoryControllerTest do + use Pleroma.Web.ConnCase, async: true + alias Pleroma.Web.CommonAPI + import Pleroma.Factory + + test "GET /api/v1/directory with :profile_directory disabled returns empty array", %{conn: conn} do + clear_config([:instance, :profile_directory], false) + + insert(:user, is_discoverable: true) + insert(:user, is_discoverable: true) + + result = + conn + |> get("/api/v1/directory") + |> json_response_and_validate_schema(200) + + assert result == [] + end + + test "GET /api/v1/directory returns discoverable users only", %{conn: conn} do + %{id: user_id} = insert(:user, is_discoverable: true) + insert(:user, is_discoverable: false) + + result = + conn + |> get("/api/v1/directory") + |> json_response_and_validate_schema(200) + + assert [%{"id" => ^user_id}] = result + end + + test "GET /api/v1/directory returns users sorted by most recent statuses", %{conn: conn} do + insert(:user, is_discoverable: true) + %{id: user_id} = user = insert(:user, is_discoverable: true) + insert(:user, is_discoverable: true) + + {:ok, _activity} = CommonAPI.post(user, %{status: "yay i'm discoverable"}) + + result = + conn + |> get("/api/v1/directory?order=active") + |> json_response_and_validate_schema(200) + + assert [%{"id" => ^user_id} | _tail] = result + end +end diff --git a/test/web/mastodon_api/controllers/domain_block_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/domain_block_controller_test.exs index 664654500..0c3a7c0cf 100644 --- a/test/web/mastodon_api/controllers/domain_block_controller_test.exs +++ b/test/pleroma/web/mastodon_api/controllers/domain_block_controller_test.exs @@ -1,8 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.MastodonAPI.DomainBlockControllerTest do + # TODO: Should not need Cachex use Pleroma.Web.ConnCase alias Pleroma.User diff --git a/test/pleroma/web/mastodon_api/controllers/filter_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/filter_controller_test.exs new file mode 100644 index 000000000..98ab9e717 --- /dev/null +++ b/test/pleroma/web/mastodon_api/controllers/filter_controller_test.exs @@ -0,0 +1,415 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.FilterControllerTest do + use Pleroma.Web.ConnCase, async: true + use Oban.Testing, repo: Pleroma.Repo + + import Pleroma.Factory + + alias Pleroma.Filter + alias Pleroma.Repo + alias Pleroma.Workers.PurgeExpiredFilter + + test "non authenticated creation request", %{conn: conn} do + response = + conn + |> put_req_header("content-type", "application/json") + |> post("/api/v1/filters", %{"phrase" => "knights", context: ["home"]}) + |> json_response(403) + + assert response["error"] == "Invalid credentials." + end + + describe "creating" do + setup do: oauth_access(["write:filters"]) + + test "a common filter", %{conn: conn, user: user} do + params = %{ + phrase: "knights", + context: ["home"], + irreversible: true + } + + response = + conn + |> put_req_header("content-type", "application/json") + |> post("/api/v1/filters", params) + |> json_response_and_validate_schema(200) + + assert response["phrase"] == params.phrase + assert response["context"] == params.context + assert response["irreversible"] == true + assert response["id"] != nil + assert response["id"] != "" + assert response["expires_at"] == nil + + filter = Filter.get(response["id"], user) + assert filter.hide == true + end + + test "a filter with expires_in", %{conn: conn, user: user} do + in_seconds = 600 + + response = + conn + |> put_req_header("content-type", "application/json") + |> post("/api/v1/filters", %{ + "phrase" => "knights", + context: ["home"], + expires_in: in_seconds + }) + |> json_response_and_validate_schema(200) + + assert response["irreversible"] == false + + expires_at = + NaiveDateTime.utc_now() + |> NaiveDateTime.add(in_seconds) + |> Pleroma.Web.CommonAPI.Utils.to_masto_date() + + assert response["expires_at"] == expires_at + + filter = Filter.get(response["id"], user) + + id = filter.id + + assert_enqueued( + worker: PurgeExpiredFilter, + args: %{filter_id: filter.id} + ) + + assert {:ok, %{id: ^id}} = + perform_job(PurgeExpiredFilter, %{ + filter_id: filter.id + }) + + assert Repo.aggregate(Filter, :count, :id) == 0 + end + end + + test "fetching a list of filters" do + %{user: user, conn: conn} = oauth_access(["read:filters"]) + + %{filter_id: id1} = insert(:filter, user: user) + %{filter_id: id2} = insert(:filter, user: user) + + id1 = to_string(id1) + id2 = to_string(id2) + + assert [%{"id" => ^id2}, %{"id" => ^id1}] = + conn + |> get("/api/v1/filters") + |> json_response_and_validate_schema(200) + end + + test "fetching a list of filters without token", %{conn: conn} do + insert(:filter) + + response = + conn + |> get("/api/v1/filters") + |> json_response(403) + + assert response["error"] == "Invalid credentials." + end + + test "get a filter" do + %{user: user, conn: conn} = oauth_access(["read:filters"]) + + # check whole_word false + filter = insert(:filter, user: user, whole_word: false) + + resp1 = + conn |> get("/api/v1/filters/#{filter.filter_id}") |> json_response_and_validate_schema(200) + + assert resp1["whole_word"] == false + + # check whole_word true + filter = insert(:filter, user: user, whole_word: true) + + resp2 = + conn |> get("/api/v1/filters/#{filter.filter_id}") |> json_response_and_validate_schema(200) + + assert resp2["whole_word"] == true + end + + test "get a filter not_found error" do + filter = insert(:filter) + %{conn: conn} = oauth_access(["read:filters"]) + + response = + conn |> get("/api/v1/filters/#{filter.filter_id}") |> json_response_and_validate_schema(404) + + assert response["error"] == "Record not found" + end + + describe "updating a filter" do + setup do: oauth_access(["write:filters"]) + + test "common" do + %{conn: conn, user: user} = oauth_access(["write:filters"]) + + filter = + insert(:filter, + user: user, + hide: true, + whole_word: true + ) + + params = %{ + phrase: "nii", + context: ["public"], + irreversible: false + } + + response = + conn + |> put_req_header("content-type", "application/json") + |> put("/api/v1/filters/#{filter.filter_id}", params) + |> json_response_and_validate_schema(200) + + assert response["phrase"] == params.phrase + assert response["context"] == params.context + assert response["irreversible"] == false + assert response["whole_word"] == true + end + + test "with adding expires_at", %{conn: conn, user: user} do + filter = insert(:filter, user: user) + in_seconds = 600 + + response = + conn + |> put_req_header("content-type", "application/json") + |> put("/api/v1/filters/#{filter.filter_id}", %{ + phrase: "nii", + context: ["public"], + expires_in: in_seconds, + irreversible: true + }) + |> json_response_and_validate_schema(200) + + assert response["irreversible"] == true + + assert response["expires_at"] == + NaiveDateTime.utc_now() + |> NaiveDateTime.add(in_seconds) + |> Pleroma.Web.CommonAPI.Utils.to_masto_date() + + filter = Filter.get(response["id"], user) + + id = filter.id + + assert_enqueued( + worker: PurgeExpiredFilter, + args: %{filter_id: id} + ) + + assert {:ok, %{id: ^id}} = + perform_job(PurgeExpiredFilter, %{ + filter_id: id + }) + + assert Repo.aggregate(Filter, :count, :id) == 0 + end + + test "with removing expires_at", %{conn: conn, user: user} do + response = + conn + |> put_req_header("content-type", "application/json") + |> post("/api/v1/filters", %{ + phrase: "cofe", + context: ["home"], + expires_in: 600 + }) + |> json_response_and_validate_schema(200) + + filter = Filter.get(response["id"], user) + + assert_enqueued( + worker: PurgeExpiredFilter, + args: %{filter_id: filter.id} + ) + + response = + conn + |> put_req_header("content-type", "application/json") + |> put("/api/v1/filters/#{filter.filter_id}", %{ + phrase: "nii", + context: ["public"], + expires_in: nil, + whole_word: true + }) + |> json_response_and_validate_schema(200) + + refute_enqueued( + worker: PurgeExpiredFilter, + args: %{filter_id: filter.id} + ) + + assert response["irreversible"] == false + assert response["whole_word"] == true + assert response["expires_at"] == nil + end + + test "expires_at is the same in create and update so job is in db", %{conn: conn, user: user} do + resp1 = + conn + |> put_req_header("content-type", "application/json") + |> post("/api/v1/filters", %{ + phrase: "cofe", + context: ["home"], + expires_in: 600 + }) + |> json_response_and_validate_schema(200) + + filter = Filter.get(resp1["id"], user) + + assert_enqueued( + worker: PurgeExpiredFilter, + args: %{filter_id: filter.id} + ) + + job = PurgeExpiredFilter.get_expiration(filter.id) + + resp2 = + conn + |> put_req_header("content-type", "application/json") + |> put("/api/v1/filters/#{filter.filter_id}", %{ + phrase: "nii", + context: ["public"] + }) + |> json_response_and_validate_schema(200) + + updated_filter = Filter.get(resp2["id"], user) + + assert_enqueued( + worker: PurgeExpiredFilter, + args: %{filter_id: updated_filter.id} + ) + + after_update = PurgeExpiredFilter.get_expiration(updated_filter.id) + + assert resp1["expires_at"] == resp2["expires_at"] + + assert job.scheduled_at == after_update.scheduled_at + end + + test "updating expires_at updates oban job too", %{conn: conn, user: user} do + resp1 = + conn + |> put_req_header("content-type", "application/json") + |> post("/api/v1/filters", %{ + phrase: "cofe", + context: ["home"], + expires_in: 600 + }) + |> json_response_and_validate_schema(200) + + filter = Filter.get(resp1["id"], user) + + assert_enqueued( + worker: PurgeExpiredFilter, + args: %{filter_id: filter.id} + ) + + job = PurgeExpiredFilter.get_expiration(filter.id) + + resp2 = + conn + |> put_req_header("content-type", "application/json") + |> put("/api/v1/filters/#{filter.filter_id}", %{ + phrase: "nii", + context: ["public"], + expires_in: 300 + }) + |> json_response_and_validate_schema(200) + + updated_filter = Filter.get(resp2["id"], user) + + assert_enqueued( + worker: PurgeExpiredFilter, + args: %{filter_id: updated_filter.id} + ) + + after_update = PurgeExpiredFilter.get_expiration(updated_filter.id) + + refute resp1["expires_at"] == resp2["expires_at"] + + refute job.scheduled_at == after_update.scheduled_at + end + end + + test "update filter without token", %{conn: conn} do + filter = insert(:filter) + + response = + conn + |> put_req_header("content-type", "application/json") + |> put("/api/v1/filters/#{filter.filter_id}", %{ + phrase: "nii", + context: ["public"] + }) + |> json_response(403) + + assert response["error"] == "Invalid credentials." + end + + describe "delete a filter" do + setup do: oauth_access(["write:filters"]) + + test "common", %{conn: conn, user: user} do + filter = insert(:filter, user: user) + + assert conn + |> delete("/api/v1/filters/#{filter.filter_id}") + |> json_response_and_validate_schema(200) == %{} + + assert Repo.all(Filter) == [] + end + + test "with expires_at", %{conn: conn, user: user} do + response = + conn + |> put_req_header("content-type", "application/json") + |> post("/api/v1/filters", %{ + phrase: "cofe", + context: ["home"], + expires_in: 600 + }) + |> json_response_and_validate_schema(200) + + filter = Filter.get(response["id"], user) + + assert_enqueued( + worker: PurgeExpiredFilter, + args: %{filter_id: filter.id} + ) + + assert conn + |> delete("/api/v1/filters/#{filter.filter_id}") + |> json_response_and_validate_schema(200) == %{} + + refute_enqueued( + worker: PurgeExpiredFilter, + args: %{filter_id: filter.id} + ) + + assert Repo.all(Filter) == [] + assert Repo.all(Oban.Job) == [] + end + end + + test "delete a filter without token", %{conn: conn} do + filter = insert(:filter) + + response = + conn + |> delete("/api/v1/filters/#{filter.filter_id}") + |> json_response(403) + + assert response["error"] == "Invalid credentials." + end +end diff --git a/test/web/mastodon_api/controllers/follow_request_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/follow_request_controller_test.exs index 6749e0e83..069ffb3d6 100644 --- a/test/web/mastodon_api/controllers/follow_request_controller_test.exs +++ b/test/pleroma/web/mastodon_api/controllers/follow_request_controller_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.MastodonAPI.FollowRequestControllerTest do - use Pleroma.Web.ConnCase + use Pleroma.Web.ConnCase, async: true alias Pleroma.User alias Pleroma.Web.CommonAPI @@ -12,7 +12,7 @@ defmodule Pleroma.Web.MastodonAPI.FollowRequestControllerTest do describe "locked accounts" do setup do - user = insert(:user, locked: true) + user = insert(:user, is_locked: true) %{conn: conn} = oauth_access(["follow"], user: user) %{user: user, conn: conn} end @@ -21,7 +21,7 @@ defmodule Pleroma.Web.MastodonAPI.FollowRequestControllerTest do other_user = insert(:user) {:ok, _, _, _activity} = CommonAPI.follow(other_user, user) - {:ok, other_user} = User.follow(other_user, user, :follow_pending) + {:ok, other_user, user} = User.follow(other_user, user, :follow_pending) assert User.following?(other_user, user) == false @@ -35,7 +35,7 @@ defmodule Pleroma.Web.MastodonAPI.FollowRequestControllerTest do other_user = insert(:user) {:ok, _, _, _activity} = CommonAPI.follow(other_user, user) - {:ok, other_user} = User.follow(other_user, user, :follow_pending) + {:ok, other_user, user} = User.follow(other_user, user, :follow_pending) user = User.get_cached_by_id(user.id) other_user = User.get_cached_by_id(other_user.id) diff --git a/test/web/mastodon_api/controllers/instance_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/instance_controller_test.exs index 6a9ccd979..e76cbc75b 100644 --- a/test/web/mastodon_api/controllers/instance_controller_test.exs +++ b/test/pleroma/web/mastodon_api/controllers/instance_controller_test.exs @@ -1,8 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.MastodonAPI.InstanceControllerTest do + # TODO: Should not need Cachex use Pleroma.Web.ConnCase alias Pleroma.User @@ -13,6 +14,9 @@ defmodule Pleroma.Web.MastodonAPI.InstanceControllerTest do assert result = json_response_and_validate_schema(conn, 200) email = Pleroma.Config.get([:instance, :email]) + thumbnail = Pleroma.Web.Endpoint.url() <> Pleroma.Config.get([:instance, :instance_thumbnail]) + background = Pleroma.Web.Endpoint.url() <> Pleroma.Config.get([:instance, :background_image]) + # Note: not checking for "max_toot_chars" since it's optional assert %{ "uri" => _, @@ -24,7 +28,7 @@ defmodule Pleroma.Web.MastodonAPI.InstanceControllerTest do "streaming_api" => _ }, "stats" => _, - "thumbnail" => _, + "thumbnail" => from_config_thumbnail, "languages" => _, "registrations" => _, "approval_required" => _, @@ -33,8 +37,8 @@ defmodule Pleroma.Web.MastodonAPI.InstanceControllerTest do "avatar_upload_limit" => _, "background_upload_limit" => _, "banner_upload_limit" => _, - "background_image" => _, - "chat_limit" => _, + "background_image" => from_config_background, + "shout_limit" => _, "description_limit" => _ } = result @@ -43,15 +47,18 @@ defmodule Pleroma.Web.MastodonAPI.InstanceControllerTest do assert result["pleroma"]["metadata"]["federation"] assert result["pleroma"]["metadata"]["fields_limits"] assert result["pleroma"]["vapid_public_key"] + assert result["pleroma"]["stats"]["mau"] == 0 assert email == from_config_email + assert thumbnail == from_config_thumbnail + assert background == from_config_background end test "get instance stats", %{conn: conn} do user = insert(:user, %{local: true}) user2 = insert(:user, %{local: true}) - {:ok, _user2} = User.deactivate(user2, !user2.deactivated) + {:ok, _user2} = User.set_activation(user2, false) insert(:user, %{local: false, nickname: "u@peer1.com"}) insert(:user, %{local: false, nickname: "u@peer2.com"}) diff --git a/test/web/mastodon_api/controllers/list_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/list_controller_test.exs index 091ec006c..28099837e 100644 --- a/test/web/mastodon_api/controllers/list_controller_test.exs +++ b/test/pleroma/web/mastodon_api/controllers/list_controller_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.MastodonAPI.ListControllerTest do - use Pleroma.Web.ConnCase + use Pleroma.Web.ConnCase, async: true alias Pleroma.Repo @@ -55,30 +55,39 @@ defmodule Pleroma.Web.MastodonAPI.ListControllerTest do test "adding users to a list" do %{user: user, conn: conn} = oauth_access(["write:lists"]) other_user = insert(:user) + third_user = insert(:user) {:ok, list} = Pleroma.List.create("name", user) assert %{} == conn |> put_req_header("content-type", "application/json") - |> post("/api/v1/lists/#{list.id}/accounts", %{"account_ids" => [other_user.id]}) + |> post("/api/v1/lists/#{list.id}/accounts", %{ + "account_ids" => [other_user.id, third_user.id] + }) |> json_response_and_validate_schema(:ok) %Pleroma.List{following: following} = Pleroma.List.get(list.id, user) - assert following == [other_user.follower_address] + assert length(following) == 2 + assert other_user.follower_address in following + assert third_user.follower_address in following end test "removing users from a list, body params" do %{user: user, conn: conn} = oauth_access(["write:lists"]) other_user = insert(:user) third_user = insert(:user) + fourth_user = insert(:user) {:ok, list} = Pleroma.List.create("name", user) {:ok, list} = Pleroma.List.follow(list, other_user) {:ok, list} = Pleroma.List.follow(list, third_user) + {:ok, list} = Pleroma.List.follow(list, fourth_user) assert %{} == conn |> put_req_header("content-type", "application/json") - |> delete("/api/v1/lists/#{list.id}/accounts", %{"account_ids" => [other_user.id]}) + |> delete("/api/v1/lists/#{list.id}/accounts", %{ + "account_ids" => [other_user.id, fourth_user.id] + }) |> json_response_and_validate_schema(:ok) %Pleroma.List{following: following} = Pleroma.List.get(list.id, user) diff --git a/test/web/mastodon_api/controllers/marker_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/marker_controller_test.exs index 6dd40fb4a..53aebe8e4 100644 --- a/test/web/mastodon_api/controllers/marker_controller_test.exs +++ b/test/pleroma/web/mastodon_api/controllers/marker_controller_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.MastodonAPI.MarkerControllerTest do - use Pleroma.Web.ConnCase + use Pleroma.Web.ConnCase, async: true import Pleroma.Factory @@ -11,7 +11,7 @@ defmodule Pleroma.Web.MastodonAPI.MarkerControllerTest do test "gets markers with correct scopes", %{conn: conn} do user = insert(:user) token = insert(:oauth_token, user: user, scopes: ["read:statuses"]) - insert_list(7, :notification, user: user) + insert_list(7, :notification, user: user, activity: insert(:note_activity)) {:ok, %{"notifications" => marker}} = Pleroma.Marker.upsert( diff --git a/test/web/mastodon_api/controllers/media_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/media_controller_test.exs index 906fd940f..ff988a7fd 100644 --- a/test/web/mastodon_api/controllers/media_controller_test.exs +++ b/test/pleroma/web/mastodon_api/controllers/media_controller_test.exs @@ -1,10 +1,12 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.MastodonAPI.MediaControllerTest do use Pleroma.Web.ConnCase + import ExUnit.CaptureLog + alias Pleroma.Object alias Pleroma.User alias Pleroma.Web.ActivityPub.ActivityPub @@ -14,7 +16,7 @@ defmodule Pleroma.Web.MastodonAPI.MediaControllerTest do setup do image = %Plug.Upload{ - content_type: "image/jpg", + content_type: "image/jpeg", path: Path.absname("test/fixtures/image.jpg"), filename: "an_image.jpg" } @@ -67,6 +69,59 @@ defmodule Pleroma.Web.MastodonAPI.MediaControllerTest do object = Object.get_by_id(media["id"]) assert object.data["actor"] == user.ap_id end + + test "/api/v2/media, upload_limit", %{conn: conn, user: user} do + desc = "Description of the binary" + + upload_limit = Config.get([:instance, :upload_limit]) * 8 + 8 + + assert :ok == + File.write(Path.absname("test/tmp/large_binary.data"), <<0::size(upload_limit)>>) + + large_binary = %Plug.Upload{ + content_type: nil, + path: Path.absname("test/tmp/large_binary.data"), + filename: "large_binary.data" + } + + assert capture_log(fn -> + assert %{"error" => "file_too_large"} = + conn + |> put_req_header("content-type", "multipart/form-data") + |> post("/api/v2/media", %{ + "file" => large_binary, + "description" => desc + }) + |> json_response_and_validate_schema(400) + end) =~ + "[error] Elixir.Pleroma.Upload store (using Pleroma.Uploaders.Local) failed: :file_too_large" + + clear_config([:instance, :upload_limit], upload_limit) + + assert response = + conn + |> put_req_header("content-type", "multipart/form-data") + |> post("/api/v2/media", %{ + "file" => large_binary, + "description" => desc + }) + |> json_response_and_validate_schema(202) + + assert media_id = response["id"] + + %{conn: conn} = oauth_access(["read:media"], user: user) + + media = + conn + |> get("/api/v1/media/#{media_id}") + |> json_response_and_validate_schema(200) + + assert media["type"] == "unknown" + assert media["description"] == desc + assert media["id"] + + assert :ok == File.rm(Path.absname("test/tmp/large_binary.data")) + end end describe "Update media description" do @@ -74,7 +129,7 @@ defmodule Pleroma.Web.MastodonAPI.MediaControllerTest do setup %{user: actor} do file = %Plug.Upload{ - content_type: "image/jpg", + content_type: "image/jpeg", path: Path.absname("test/fixtures/image.jpg"), filename: "an_image.jpg" } @@ -106,7 +161,7 @@ defmodule Pleroma.Web.MastodonAPI.MediaControllerTest do setup %{user: actor} do file = %Plug.Upload{ - content_type: "image/jpg", + content_type: "image/jpeg", path: Path.absname("test/fixtures/image.jpg"), filename: "an_image.jpg" } @@ -140,7 +195,7 @@ defmodule Pleroma.Web.MastodonAPI.MediaControllerTest do conn |> get("/api/v1/media/#{object.id}") - |> json_response(403) + |> json_response_and_validate_schema(403) end end end diff --git a/test/web/mastodon_api/controllers/notification_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/notification_controller_test.exs index 70ef0e8b5..d991f284f 100644 --- a/test/web/mastodon_api/controllers/notification_controller_test.exs +++ b/test/pleroma/web/mastodon_api/controllers/notification_controller_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.MastodonAPI.NotificationControllerTest do @@ -44,9 +44,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationControllerTest do |> get("/api/v1/notifications") expected_response = - "hi <span class=\"h-card\"><a class=\"u-url mention\" data-user=\"#{user.id}\" href=\"#{ - user.ap_id - }\" rel=\"ugc\">@<span>#{user.nickname}</span></a></span>" + "hi <span class=\"h-card\"><a class=\"u-url mention\" data-user=\"#{user.id}\" href=\"#{user.ap_id}\" rel=\"ugc\">@<span>#{user.nickname}</span></a></span>" assert [%{"status" => %{"content" => response}} | _rest] = json_response_and_validate_schema(conn, 200) @@ -75,6 +73,53 @@ defmodule Pleroma.Web.MastodonAPI.NotificationControllerTest do assert [_] = result end + test "by default, does not contain pleroma:report" do + %{user: user, conn: conn} = oauth_access(["read:notifications"]) + other_user = insert(:user) + third_user = insert(:user) + + user + |> User.admin_api_update(%{is_moderator: true}) + + {:ok, activity} = CommonAPI.post(other_user, %{status: "hey"}) + + {:ok, _report} = + CommonAPI.report(third_user, %{account_id: other_user.id, status_ids: [activity.id]}) + + result = + conn + |> get("/api/v1/notifications") + |> json_response_and_validate_schema(200) + + assert [] == result + + result = + conn + |> get("/api/v1/notifications?include_types[]=pleroma:report") + |> json_response_and_validate_schema(200) + + assert [_] = result + end + + test "excludes mentions from blockers when blockers_visible is false" do + clear_config([:activitypub, :blockers_visible], false) + + %{user: user, conn: conn} = oauth_access(["read:notifications"]) + blocker = insert(:user) + + {:ok, _} = CommonAPI.block(blocker, user) + {:ok, activity} = CommonAPI.post(blocker, %{status: "hi @#{user.nickname}"}) + + {:ok, [_notification]} = Notification.create_notifications(activity) + + conn = + conn + |> assign(:user, user) + |> get("/api/v1/notifications") + + assert [] == json_response_and_validate_schema(conn, 200) + end + test "getting a single notification" do %{user: user, conn: conn} = oauth_access(["read:notifications"]) other_user = insert(:user) @@ -86,9 +131,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationControllerTest do conn = get(conn, "/api/v1/notifications/#{notification.id}") expected_response = - "hi <span class=\"h-card\"><a class=\"u-url mention\" data-user=\"#{user.id}\" href=\"#{ - user.ap_id - }\" rel=\"ugc\">@<span>#{user.nickname}</span></a></span>" + "hi <span class=\"h-card\"><a class=\"u-url mention\" data-user=\"#{user.id}\" href=\"#{user.ap_id}\" rel=\"ugc\">@<span>#{user.nickname}</span></a></span>" assert %{"status" => %{"content" => response}} = json_response_and_validate_schema(conn, 200) assert response == expected_response @@ -502,7 +545,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationControllerTest do assert length(json_response_and_validate_schema(ret_conn, 200)) == 1 - {:ok, _user_relationships} = User.mute(user, user2, false) + {:ok, _user_relationships} = User.mute(user, user2, %{notifications: false}) conn = get(conn, "/api/v1/notifications") @@ -527,24 +570,11 @@ defmodule Pleroma.Web.MastodonAPI.NotificationControllerTest do assert length(json_response_and_validate_schema(conn, 200)) == 1 end - @tag capture_log: true test "see move notifications" do old_user = insert(:user) new_user = insert(:user, also_known_as: [old_user.ap_id]) %{user: follower, conn: conn} = oauth_access(["read:notifications"]) - old_user_url = old_user.ap_id - - body = - File.read!("test/fixtures/users_mock/localhost.json") - |> String.replace("{{nickname}}", old_user.nickname) - |> Jason.encode!() - - Tesla.Mock.mock(fn - %{method: :get, url: ^old_user_url} -> - %Tesla.Env{status: 200, body: body} - end) - User.follow(follower, old_user) Pleroma.Web.ActivityPub.ActivityPub.move(old_user, new_user) Pleroma.Tests.ObanHelpers.perform_all() diff --git a/test/web/mastodon_api/controllers/poll_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/poll_controller_test.exs index f41de6448..da0a631a9 100644 --- a/test/web/mastodon_api/controllers/poll_controller_test.exs +++ b/test/pleroma/web/mastodon_api/controllers/poll_controller_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.MastodonAPI.PollControllerTest do - use Pleroma.Web.ConnCase + use Pleroma.Web.ConnCase, async: true alias Pleroma.Object alias Pleroma.Web.CommonAPI @@ -20,7 +20,7 @@ defmodule Pleroma.Web.MastodonAPI.PollControllerTest do poll: %{options: ["what Mastodon't", "n't what Mastodoes"], expires_in: 20} }) - object = Object.normalize(activity) + object = Object.normalize(activity, fetch: false) conn = get(conn, "/api/v1/polls/#{object.id}") @@ -39,7 +39,7 @@ defmodule Pleroma.Web.MastodonAPI.PollControllerTest do visibility: "private" }) - object = Object.normalize(activity) + object = Object.normalize(activity, fetch: false) conn = get(conn, "/api/v1/polls/#{object.id}") @@ -47,6 +47,78 @@ defmodule Pleroma.Web.MastodonAPI.PollControllerTest do end end + test "own_votes" do + %{conn: conn} = oauth_access(["write:statuses", "read:statuses"]) + + other_user = insert(:user) + + {:ok, activity} = + CommonAPI.post(other_user, %{ + status: "A very delicious sandwich", + poll: %{ + options: ["Lettuce", "Grilled Bacon", "Tomato"], + expires_in: 20, + multiple: true + } + }) + + object = Object.normalize(activity, fetch: false) + + conn + |> put_req_header("content-type", "application/json") + |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0, 2]}) + |> json_response_and_validate_schema(200) + + object = Object.get_by_id(object.id) + + assert [ + %{ + "name" => "Lettuce", + "replies" => %{"totalItems" => 1, "type" => "Collection"}, + "type" => "Note" + }, + %{ + "name" => "Grilled Bacon", + "replies" => %{"totalItems" => 0, "type" => "Collection"}, + "type" => "Note" + }, + %{ + "name" => "Tomato", + "replies" => %{"totalItems" => 1, "type" => "Collection"}, + "type" => "Note" + } + ] == object.data["anyOf"] + + assert %{"replies" => %{"totalItems" => 0}} = + Enum.find(object.data["anyOf"], fn %{"name" => name} -> name == "Grilled Bacon" end) + + Enum.each(["Lettuce", "Tomato"], fn title -> + %{"replies" => %{"totalItems" => total_items}} = + Enum.find(object.data["anyOf"], fn %{"name" => name} -> name == title end) + + assert total_items == 1 + end) + + assert %{ + "own_votes" => own_votes, + "voted" => true + } = + conn + |> get("/api/v1/polls/#{object.id}") + |> json_response_and_validate_schema(200) + + assert 0 in own_votes + assert 2 in own_votes + # for non authenticated user + response = + build_conn() + |> get("/api/v1/polls/#{object.id}") + |> json_response_and_validate_schema(200) + + refute Map.has_key?(response, "own_votes") + refute Map.has_key?(response, "voted") + end + describe "POST /api/v1/polls/:id/votes" do setup do: oauth_access(["write:statuses"]) @@ -63,14 +135,13 @@ defmodule Pleroma.Web.MastodonAPI.PollControllerTest do } }) - object = Object.normalize(activity) + object = Object.normalize(activity, fetch: false) - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0, 1, 2]}) + conn + |> put_req_header("content-type", "application/json") + |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0, 1, 2]}) + |> json_response_and_validate_schema(200) - assert json_response_and_validate_schema(conn, 200) object = Object.get_by_id(object.id) assert Enum.all?(object.data["anyOf"], fn %{"replies" => %{"totalItems" => total_items}} -> @@ -85,7 +156,7 @@ defmodule Pleroma.Web.MastodonAPI.PollControllerTest do poll: %{options: ["Yes", "No"], expires_in: 20} }) - object = Object.normalize(activity) + object = Object.normalize(activity, fetch: false) assert conn |> put_req_header("content-type", "application/json") @@ -106,7 +177,7 @@ defmodule Pleroma.Web.MastodonAPI.PollControllerTest do poll: %{options: ["half empty", "half full"], expires_in: 20} }) - object = Object.normalize(activity) + object = Object.normalize(activity, fetch: false) assert conn |> put_req_header("content-type", "application/json") @@ -129,7 +200,7 @@ defmodule Pleroma.Web.MastodonAPI.PollControllerTest do poll: %{options: ["Yes", "No"], expires_in: 20} }) - object = Object.normalize(activity) + object = Object.normalize(activity, fetch: false) conn = conn @@ -158,7 +229,7 @@ defmodule Pleroma.Web.MastodonAPI.PollControllerTest do visibility: "private" }) - object = Object.normalize(activity) + object = Object.normalize(activity, fetch: false) conn = conn diff --git a/test/web/mastodon_api/controllers/report_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/report_controller_test.exs index 6636cff96..fcfc4a48a 100644 --- a/test/web/mastodon_api/controllers/report_controller_test.exs +++ b/test/pleroma/web/mastodon_api/controllers/report_controller_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.MastodonAPI.ReportControllerTest do - use Pleroma.Web.ConnCase + use Pleroma.Web.ConnCase, async: true alias Pleroma.Web.CommonAPI diff --git a/test/web/mastodon_api/controllers/scheduled_activity_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/scheduled_activity_controller_test.exs index 1ff871c89..b28e3df56 100644 --- a/test/web/mastodon_api/controllers/scheduled_activity_controller_test.exs +++ b/test/pleroma/web/mastodon_api/controllers/scheduled_activity_controller_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.MastodonAPI.ScheduledActivityControllerTest do @@ -55,7 +55,7 @@ defmodule Pleroma.Web.MastodonAPI.ScheduledActivityControllerTest do end test "updates a scheduled activity" do - Pleroma.Config.put([ScheduledActivity, :enabled], true) + clear_config([ScheduledActivity, :enabled], true) %{user: user, conn: conn} = oauth_access(["write:statuses"]) scheduled_at = Timex.shift(NaiveDateTime.utc_now(), minutes: 60) @@ -103,7 +103,7 @@ defmodule Pleroma.Web.MastodonAPI.ScheduledActivityControllerTest do end test "deletes a scheduled activity" do - Pleroma.Config.put([ScheduledActivity, :enabled], true) + clear_config([ScheduledActivity, :enabled], true) %{user: user, conn: conn} = oauth_access(["write:statuses"]) scheduled_at = Timex.shift(NaiveDateTime.utc_now(), minutes: 60) diff --git a/test/web/mastodon_api/controllers/search_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/search_controller_test.exs index 24d1959f8..e31cd0291 100644 --- a/test/web/mastodon_api/controllers/search_controller_test.exs +++ b/test/pleroma/web/mastodon_api/controllers/search_controller_test.exs @@ -1,13 +1,13 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.MastodonAPI.SearchControllerTest do use Pleroma.Web.ConnCase alias Pleroma.Object - alias Pleroma.Web alias Pleroma.Web.CommonAPI + alias Pleroma.Web.Endpoint import Pleroma.Factory import ExUnit.CaptureLog import Tesla.Mock @@ -61,7 +61,7 @@ defmodule Pleroma.Web.MastodonAPI.SearchControllerTest do assert account["id"] == to_string(user_three.id) assert results["hashtags"] == [ - %{"name" => "private", "url" => "#{Web.base_url()}/tag/private"} + %{"name" => "private", "url" => "#{Endpoint.url()}/tag/private"} ] [status] = results["statuses"] @@ -72,7 +72,7 @@ defmodule Pleroma.Web.MastodonAPI.SearchControllerTest do |> json_response_and_validate_schema(200) assert results["hashtags"] == [ - %{"name" => "天子", "url" => "#{Web.base_url()}/tag/天子"} + %{"name" => "天子", "url" => "#{Endpoint.url()}/tag/天子"} ] [status] = results["statuses"] @@ -87,8 +87,8 @@ defmodule Pleroma.Web.MastodonAPI.SearchControllerTest do |> json_response_and_validate_schema(200) assert results["hashtags"] == [ - %{"name" => "explicit", "url" => "#{Web.base_url()}/tag/explicit"}, - %{"name" => "hashtags", "url" => "#{Web.base_url()}/tag/hashtags"} + %{"name" => "explicit", "url" => "#{Endpoint.url()}/tag/explicit"}, + %{"name" => "hashtags", "url" => "#{Endpoint.url()}/tag/hashtags"} ] results = @@ -97,9 +97,9 @@ defmodule Pleroma.Web.MastodonAPI.SearchControllerTest do |> json_response_and_validate_schema(200) assert results["hashtags"] == [ - %{"name" => "john", "url" => "#{Web.base_url()}/tag/john"}, - %{"name" => "doe", "url" => "#{Web.base_url()}/tag/doe"}, - %{"name" => "JohnDoe", "url" => "#{Web.base_url()}/tag/JohnDoe"} + %{"name" => "john", "url" => "#{Endpoint.url()}/tag/john"}, + %{"name" => "doe", "url" => "#{Endpoint.url()}/tag/doe"}, + %{"name" => "JohnDoe", "url" => "#{Endpoint.url()}/tag/JohnDoe"} ] results = @@ -108,9 +108,9 @@ defmodule Pleroma.Web.MastodonAPI.SearchControllerTest do |> json_response_and_validate_schema(200) assert results["hashtags"] == [ - %{"name" => "accident", "url" => "#{Web.base_url()}/tag/accident"}, - %{"name" => "prone", "url" => "#{Web.base_url()}/tag/prone"}, - %{"name" => "AccidentProne", "url" => "#{Web.base_url()}/tag/AccidentProne"} + %{"name" => "accident", "url" => "#{Endpoint.url()}/tag/accident"}, + %{"name" => "prone", "url" => "#{Endpoint.url()}/tag/prone"}, + %{"name" => "AccidentProne", "url" => "#{Endpoint.url()}/tag/AccidentProne"} ] results = @@ -119,35 +119,29 @@ defmodule Pleroma.Web.MastodonAPI.SearchControllerTest do |> json_response_and_validate_schema(200) assert results["hashtags"] == [ - %{"name" => "shpuld", "url" => "#{Web.base_url()}/tag/shpuld"} + %{"name" => "shpuld", "url" => "#{Endpoint.url()}/tag/shpuld"} ] results = conn |> get( - "/api/v2/search?#{ - URI.encode_query(%{ - q: - "https://www.washingtonpost.com/sports/2020/06/10/" <> - "nascar-ban-display-confederate-flag-all-events-properties/" - }) - }" + "/api/v2/search?#{URI.encode_query(%{q: "https://www.washingtonpost.com/sports/2020/06/10/" <> "nascar-ban-display-confederate-flag-all-events-properties/"})}" ) |> json_response_and_validate_schema(200) assert results["hashtags"] == [ - %{"name" => "nascar", "url" => "#{Web.base_url()}/tag/nascar"}, - %{"name" => "ban", "url" => "#{Web.base_url()}/tag/ban"}, - %{"name" => "display", "url" => "#{Web.base_url()}/tag/display"}, - %{"name" => "confederate", "url" => "#{Web.base_url()}/tag/confederate"}, - %{"name" => "flag", "url" => "#{Web.base_url()}/tag/flag"}, - %{"name" => "all", "url" => "#{Web.base_url()}/tag/all"}, - %{"name" => "events", "url" => "#{Web.base_url()}/tag/events"}, - %{"name" => "properties", "url" => "#{Web.base_url()}/tag/properties"}, + %{"name" => "nascar", "url" => "#{Endpoint.url()}/tag/nascar"}, + %{"name" => "ban", "url" => "#{Endpoint.url()}/tag/ban"}, + %{"name" => "display", "url" => "#{Endpoint.url()}/tag/display"}, + %{"name" => "confederate", "url" => "#{Endpoint.url()}/tag/confederate"}, + %{"name" => "flag", "url" => "#{Endpoint.url()}/tag/flag"}, + %{"name" => "all", "url" => "#{Endpoint.url()}/tag/all"}, + %{"name" => "events", "url" => "#{Endpoint.url()}/tag/events"}, + %{"name" => "properties", "url" => "#{Endpoint.url()}/tag/properties"}, %{ "name" => "NascarBanDisplayConfederateFlagAllEventsProperties", "url" => - "#{Web.base_url()}/tag/NascarBanDisplayConfederateFlagAllEventsProperties" + "#{Endpoint.url()}/tag/NascarBanDisplayConfederateFlagAllEventsProperties" } ] end @@ -156,15 +150,13 @@ defmodule Pleroma.Web.MastodonAPI.SearchControllerTest do results = conn |> get( - "/api/v2/search?#{ - URI.encode_query(%{q: "#some #text #with #hashtags", limit: 2, offset: 1}) - }" + "/api/v2/search?#{URI.encode_query(%{q: "#some #text #with #hashtags", limit: 2, offset: 1})}" ) |> json_response_and_validate_schema(200) assert results["hashtags"] == [ - %{"name" => "text", "url" => "#{Web.base_url()}/tag/text"}, - %{"name" => "with", "url" => "#{Web.base_url()}/tag/with"} + %{"name" => "text", "url" => "#{Endpoint.url()}/tag/text"}, + %{"name" => "with", "url" => "#{Endpoint.url()}/tag/with"} ] end @@ -279,21 +271,25 @@ defmodule Pleroma.Web.MastodonAPI.SearchControllerTest do end test "search fetches remote statuses and prefers them over other results", %{conn: conn} do + old_version = :persistent_term.get({Pleroma.Repo, :postgres_version}) + :persistent_term.put({Pleroma.Repo, :postgres_version}, 10.0) + on_exit(fn -> :persistent_term.put({Pleroma.Repo, :postgres_version}, old_version) end) + capture_log(fn -> {:ok, %{id: activity_id}} = CommonAPI.post(insert(:user), %{ - status: "check out https://shitposter.club/notice/2827873" + status: "check out http://mastodon.example.org/@admin/99541947525187367" }) results = conn - |> get("/api/v1/search?q=https://shitposter.club/notice/2827873") + |> get("/api/v1/search?q=http://mastodon.example.org/@admin/99541947525187367") |> json_response_and_validate_schema(200) - [status, %{"id" => ^activity_id}] = results["statuses"] - - assert status["uri"] == - "tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment" + assert [ + %{"url" => "http://mastodon.example.org/@admin/99541947525187367"}, + %{"id" => ^activity_id} + ] = results["statuses"] end) end @@ -305,7 +301,7 @@ defmodule Pleroma.Web.MastodonAPI.SearchControllerTest do }) capture_log(fn -> - q = Object.normalize(activity).data["id"] + q = Object.normalize(activity, fetch: false).data["id"] results = conn diff --git a/test/web/mastodon_api/controllers/status_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/status_controller_test.exs index f221884e7..ed66d370a 100644 --- a/test/web/mastodon_api/controllers/status_controller_test.exs +++ b/test/pleroma/web/mastodon_api/controllers/status_controller_test.exs @@ -1,13 +1,12 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do use Pleroma.Web.ConnCase + use Oban.Testing, repo: Pleroma.Repo alias Pleroma.Activity - alias Pleroma.ActivityExpiration - alias Pleroma.Config alias Pleroma.Conversation.Participation alias Pleroma.Object alias Pleroma.Repo @@ -15,7 +14,9 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do alias Pleroma.Tests.ObanHelpers alias Pleroma.User alias Pleroma.Web.ActivityPub.ActivityPub + alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.CommonAPI + alias Pleroma.Workers.ScheduledActivityWorker import Pleroma.Factory @@ -29,8 +30,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do setup do: oauth_access(["write:statuses"]) test "posting a status does not increment reblog_count when relaying", %{conn: conn} do - Pleroma.Config.put([:instance, :federating], true) - Pleroma.Config.get([:instance, :allow_relay], true) + clear_config([:instance, :federating], true) + Config.get([:instance, :allow_relay], true) response = conn @@ -67,10 +68,6 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do "sensitive" => "0" }) - {:ok, ttl} = Cachex.ttl(:idempotency_cache, idempotency_key) - # Six hours - assert ttl > :timer.seconds(6 * 60 * 60 - 1) - assert %{"content" => "cofe", "id" => id, "spoiler_text" => "2hu", "sensitive" => false} = json_response_and_validate_schema(conn_one, 200) @@ -86,6 +83,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do "sensitive" => 0 }) + # Idempotency plug response means detection fail assert %{"id" => second_id} = json_response(conn_two, 200) assert id == second_id @@ -103,7 +101,9 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do # An activity that will expire: # 2 hours - expires_in = 120 * 60 + expires_in = 2 * 60 * 60 + + expires_at = DateTime.add(DateTime.utc_now(), expires_in) conn_four = conn @@ -113,29 +113,22 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do "expires_in" => expires_in }) - assert fourth_response = - %{"id" => fourth_id} = json_response_and_validate_schema(conn_four, 200) - - assert activity = Activity.get_by_id(fourth_id) - assert expiration = ActivityExpiration.get_by_activity_id(fourth_id) + assert %{"id" => fourth_id} = json_response_and_validate_schema(conn_four, 200) - estimated_expires_at = - NaiveDateTime.utc_now() - |> NaiveDateTime.add(expires_in) - |> NaiveDateTime.truncate(:second) - - # This assert will fail if the test takes longer than a minute. I sure hope it never does: - assert abs(NaiveDateTime.diff(expiration.scheduled_at, estimated_expires_at, :second)) < 60 + assert Activity.get_by_id(fourth_id) - assert fourth_response["pleroma"]["expires_at"] == - NaiveDateTime.to_iso8601(expiration.scheduled_at) + assert_enqueued( + worker: Pleroma.Workers.PurgeExpiredActivity, + args: %{activity_id: fourth_id}, + scheduled_at: expires_at + ) end test "it fails to create a status if `expires_in` is less or equal than an hour", %{ conn: conn } do - # 1 hour - expires_in = 60 * 60 + # 1 minute + expires_in = 1 * 60 assert %{"error" => "Expiry date is too soon"} = conn @@ -146,8 +139,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do }) |> json_response_and_validate_schema(422) - # 30 minutes - expires_in = 30 * 60 + # 5 minutes + expires_in = 5 * 60 assert %{"error" => "Expiry date is too soon"} = conn @@ -160,8 +153,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do end test "Get MRF reason when posting a status is rejected by one", %{conn: conn} do - Pleroma.Config.put([:mrf_keyword, :reject], ["GNO"]) - Pleroma.Config.put([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.KeywordPolicy]) + clear_config([:mrf_keyword, :reject], ["GNO"]) + clear_config([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.KeywordPolicy]) assert %{"error" => "[KeywordPolicy] Matches with rejected keyword"} = conn @@ -172,7 +165,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do test "posting an undefined status with an attachment", %{user: user, conn: conn} do file = %Plug.Upload{ - content_type: "image/jpg", + content_type: "image/jpeg", path: Path.absname("test/fixtures/image.jpg"), filename: "an_image.jpg" } @@ -273,6 +266,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do fake_conn = conn + |> assign(:user, refresh_record(conn.assigns.user)) |> put_req_header("content-type", "application/json") |> post("/api/v1/statuses", %{ "status" => @@ -333,7 +327,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do end test "posting a status with OGP link preview", %{conn: conn} do - Tesla.Mock.mock(fn env -> apply(HttpRequestMock, :request, [env]) end) + Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) clear_config([:rich_media, :enabled], true) conn = @@ -366,6 +360,69 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do assert activity.data["to"] == [user2.ap_id] assert activity.data["cc"] == [] end + + test "discloses application metadata when enabled" do + user = insert(:user, disclose_client: true) + %{user: _user, token: token, conn: conn} = oauth_access(["write:statuses"], user: user) + + %Pleroma.Web.OAuth.Token{ + app: %Pleroma.Web.OAuth.App{ + client_name: app_name, + website: app_website + } + } = token + + result = + conn + |> put_req_header("content-type", "application/json") + |> post("/api/v1/statuses", %{ + "status" => "cofe is my copilot" + }) + + assert %{ + "content" => "cofe is my copilot" + } = json_response_and_validate_schema(result, 200) + + activity = result.assigns.activity.id + + result = + conn + |> get("api/v1/statuses/#{activity}") + + assert %{ + "content" => "cofe is my copilot", + "application" => %{ + "name" => ^app_name, + "website" => ^app_website + } + } = json_response_and_validate_schema(result, 200) + end + + test "hides application metadata when disabled" do + user = insert(:user, disclose_client: false) + %{user: _user, token: _token, conn: conn} = oauth_access(["write:statuses"], user: user) + + result = + conn + |> put_req_header("content-type", "application/json") + |> post("/api/v1/statuses", %{ + "status" => "club mate is my wingman" + }) + + assert %{"content" => "club mate is my wingman"} = + json_response_and_validate_schema(result, 200) + + activity = result.assigns.activity.id + + result = + conn + |> get("api/v1/statuses/#{activity}") + + assert %{ + "content" => "club mate is my wingman", + "application" => nil + } = json_response_and_validate_schema(result, 200) + end end describe "posting scheduled statuses" do @@ -392,6 +449,31 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do assert [] == Repo.all(Activity) end + test "with expiration" do + %{conn: conn} = oauth_access(["write:statuses", "read:statuses"]) + + scheduled_at = + NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(6), :millisecond) + |> NaiveDateTime.to_iso8601() + |> Kernel.<>("Z") + + assert %{"id" => status_id, "params" => %{"expires_in" => 300}} = + conn + |> put_req_header("content-type", "application/json") + |> post("/api/v1/statuses", %{ + "status" => "scheduled", + "scheduled_at" => scheduled_at, + "expires_in" => 300 + }) + |> json_response_and_validate_schema(200) + + assert %{"id" => ^status_id, "params" => %{"expires_in" => 300}} = + conn + |> put_req_header("content-type", "application/json") + |> get("/api/v1/scheduled_statuses/#{status_id}") + |> json_response_and_validate_schema(200) + end + test "ignores nil values", %{conn: conn} do conn = conn @@ -413,7 +495,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do |> Kernel.<>("Z") file = %Plug.Upload{ - content_type: "image/jpg", + content_type: "image/jpeg", path: Path.absname("test/fixtures/image.jpg"), filename: "an_image.jpg" } @@ -525,7 +607,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do end) assert NaiveDateTime.diff(NaiveDateTime.from_iso8601!(response["poll"]["expires_at"]), time) in 420..430 - refute response["poll"]["expred"] + assert response["poll"]["expired"] == false question = Object.get_by_id(response["poll"]["id"]) @@ -601,6 +683,44 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do %{"error" => error} = json_response_and_validate_schema(conn, 422) assert error == "Expiration date is too far in the future" end + + test "scheduled poll", %{conn: conn} do + clear_config([ScheduledActivity, :enabled], true) + + scheduled_at = + NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(6), :millisecond) + |> NaiveDateTime.to_iso8601() + |> Kernel.<>("Z") + + %{"id" => scheduled_id} = + conn + |> put_req_header("content-type", "application/json") + |> post("/api/v1/statuses", %{ + "status" => "very cool poll", + "poll" => %{ + "options" => ~w(a b c), + "expires_in" => 420 + }, + "scheduled_at" => scheduled_at + }) + |> json_response_and_validate_schema(200) + + assert {:ok, %{id: activity_id}} = + perform_job(ScheduledActivityWorker, %{ + activity_id: scheduled_id + }) + + refute_enqueued(worker: ScheduledActivityWorker) + + object = + Activity + |> Repo.get(activity_id) + |> Object.normalize() + + assert object.data["content"] == "very cool poll" + assert object.data["type"] == "Question" + assert length(object.data["oneOf"]) == 3 + end end test "get a status" do @@ -809,7 +929,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do test "when you created it" do %{user: author, conn: conn} = oauth_access(["write:statuses"]) activity = insert(:note_activity, user: author) - object = Object.normalize(activity) + object = Object.normalize(activity, fetch: false) content = object.data["content"] source = object.data["source"] @@ -942,7 +1062,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do |> get("/api/v1/statuses/#{reblog_activity1.id}") assert %{ - "reblog" => %{"id" => id, "reblogged" => false, "reblogs_count" => 2}, + "reblog" => %{"id" => _id, "reblogged" => false, "reblogs_count" => 2}, "reblogged" => false, "favourited" => false, "bookmarked" => false @@ -963,6 +1083,23 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do assert to_string(activity.id) == id end + + test "author can reblog own private status", %{conn: conn, user: user} do + {:ok, activity} = CommonAPI.post(user, %{status: "cofe", visibility: "private"}) + + conn = + conn + |> put_req_header("content-type", "application/json") + |> post("/api/v1/statuses/#{activity.id}/reblog") + + assert %{ + "reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1}, + "reblogged" => true, + "visibility" => "private" + } = json_response_and_validate_schema(conn, 200) + + assert to_string(activity.id) == id + end end describe "unreblogging" do @@ -1075,20 +1212,27 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do setup do: clear_config([:instance, :max_pinned_statuses], 1) test "pin status", %{conn: conn, user: user, activity: activity} do - id_str = to_string(activity.id) + id = activity.id - assert %{"id" => ^id_str, "pinned" => true} = + assert %{"id" => ^id, "pinned" => true} = conn |> put_req_header("content-type", "application/json") |> post("/api/v1/statuses/#{activity.id}/pin") |> json_response_and_validate_schema(200) - assert [%{"id" => ^id_str, "pinned" => true}] = + assert [%{"id" => ^id, "pinned" => true}] = conn |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true") |> json_response_and_validate_schema(200) end + test "non authenticated user", %{activity: activity} do + assert build_conn() + |> put_req_header("content-type", "application/json") + |> post("/api/v1/statuses/#{activity.id}/pin") + |> json_response(403) == %{"error" => "Invalid credentials."} + end + test "/pin: returns 400 error when activity is not public", %{conn: conn, user: user} do {:ok, dm} = CommonAPI.post(user, %{status: "test", visibility: "direct"}) @@ -1097,7 +1241,18 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do |> put_req_header("content-type", "application/json") |> post("/api/v1/statuses/#{dm.id}/pin") - assert json_response_and_validate_schema(conn, 400) == %{"error" => "Could not pin"} + assert json_response_and_validate_schema(conn, 422) == %{ + "error" => "Non-public status cannot be pinned" + } + end + + test "pin by another user", %{activity: activity} do + %{conn: conn} = oauth_access(["write:accounts"]) + + assert conn + |> put_req_header("content-type", "application/json") + |> post("/api/v1/statuses/#{activity.id}/pin") + |> json_response(422) == %{"error" => "Someone else's status cannot be pinned"} end test "unpin status", %{conn: conn, user: user, activity: activity} do @@ -1118,13 +1273,11 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do |> json_response_and_validate_schema(200) end - test "/unpin: returns 400 error when activity is not exist", %{conn: conn} do - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/statuses/1/unpin") - - assert json_response_and_validate_schema(conn, 400) == %{"error" => "Could not unpin"} + test "/unpin: returns 404 error when activity doesn't exist", %{conn: conn} do + assert conn + |> put_req_header("content-type", "application/json") + |> post("/api/v1/statuses/1/unpin") + |> json_response_and_validate_schema(404) == %{"error" => "Record not found"} end test "max pinned statuses", %{conn: conn, user: user, activity: activity_one} do @@ -1146,17 +1299,63 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do |> post("/api/v1/statuses/#{activity_two.id}/pin") |> json_response_and_validate_schema(400) end + + test "on pin removes deletion job, on unpin reschedule deletion" do + %{conn: conn} = oauth_access(["write:accounts", "write:statuses"]) + expires_in = 2 * 60 * 60 + + expires_at = DateTime.add(DateTime.utc_now(), expires_in) + + assert %{"id" => id} = + conn + |> put_req_header("content-type", "application/json") + |> post("api/v1/statuses", %{ + "status" => "oolong", + "expires_in" => expires_in + }) + |> json_response_and_validate_schema(200) + + assert_enqueued( + worker: Pleroma.Workers.PurgeExpiredActivity, + args: %{activity_id: id}, + scheduled_at: expires_at + ) + + assert %{"id" => ^id, "pinned" => true} = + conn + |> put_req_header("content-type", "application/json") + |> post("/api/v1/statuses/#{id}/pin") + |> json_response_and_validate_schema(200) + + refute_enqueued( + worker: Pleroma.Workers.PurgeExpiredActivity, + args: %{activity_id: id}, + scheduled_at: expires_at + ) + + assert %{"id" => ^id, "pinned" => false} = + conn + |> put_req_header("content-type", "application/json") + |> post("/api/v1/statuses/#{id}/unpin") + |> json_response_and_validate_schema(200) + + assert_enqueued( + worker: Pleroma.Workers.PurgeExpiredActivity, + args: %{activity_id: id}, + scheduled_at: expires_at + ) + end end describe "cards" do setup do - Config.put([:rich_media, :enabled], true) + clear_config([:rich_media, :enabled], true) oauth_access(["read:statuses"]) end test "returns rich-media card", %{conn: conn, user: user} do - Tesla.Mock.mock(fn env -> apply(HttpRequestMock, :request, [env]) end) + Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) {:ok, activity} = CommonAPI.post(user, %{status: "https://example.com/ogp"}) @@ -1201,7 +1400,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do end test "replaces missing description with an empty string", %{conn: conn, user: user} do - Tesla.Mock.mock(fn env -> apply(HttpRequestMock, :request, [env]) end) + Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) {:ok, activity} = CommonAPI.post(user, %{status: "https://example.com/ogp-missing-data"}) @@ -1337,7 +1536,9 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do activity = Activity.get_by_id_with_object(id) - assert Object.normalize(activity).data["inReplyTo"] == Object.normalize(replied_to).data["id"] + assert Object.normalize(activity, fetch: false).data["inReplyTo"] == + Object.normalize(replied_to, fetch: false).data["id"] + assert Activity.get_in_reply_to_activity(activity).id == replied_to.id # Reblog from the third user @@ -1360,7 +1561,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do |> assign(:token, insert(:oauth_token, user: user3, scopes: ["read:statuses"])) |> get("api/v1/timelines/home") - [reblogged_activity] = json_response(conn3, 200) + [reblogged_activity] = json_response_and_validate_schema(conn3, 200) assert reblogged_activity["reblog"]["in_reply_to_id"] == replied_to.id @@ -1681,19 +1882,17 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do test "expires_at is nil for another user" do %{conn: conn, user: user} = oauth_access(["read:statuses"]) + expires_at = DateTime.add(DateTime.utc_now(), 1_000_000) {:ok, activity} = CommonAPI.post(user, %{status: "foobar", expires_in: 1_000_000}) - expires_at = - activity.id - |> ActivityExpiration.get_by_activity_id() - |> Map.get(:scheduled_at) - |> NaiveDateTime.to_iso8601() - - assert %{"pleroma" => %{"expires_at" => ^expires_at}} = + assert %{"pleroma" => %{"expires_at" => a_expires_at}} = conn |> get("/api/v1/statuses/#{activity.id}") |> json_response_and_validate_schema(:ok) + {:ok, a_expires_at, 0} = DateTime.from_iso8601(a_expires_at) + assert DateTime.diff(expires_at, a_expires_at) == 0 + %{conn: conn} = oauth_access(["read:statuses"]) assert %{"pleroma" => %{"expires_at" => nil}} = @@ -1701,4 +1900,94 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do |> get("/api/v1/statuses/#{activity.id}") |> json_response_and_validate_schema(:ok) end + + test "posting a local only status" do + %{user: _user, conn: conn} = oauth_access(["write:statuses"]) + + conn_one = + conn + |> put_req_header("content-type", "application/json") + |> post("/api/v1/statuses", %{ + "status" => "cofe", + "visibility" => "local" + }) + + local = Utils.as_local_public() + + assert %{"content" => "cofe", "id" => id, "visibility" => "local"} = + json_response_and_validate_schema(conn_one, 200) + + assert %Activity{id: ^id, data: %{"to" => [^local]}} = Activity.get_by_id(id) + end + + describe "muted reactions" do + test "index" do + %{conn: conn, user: user} = oauth_access(["read:statuses"]) + + other_user = insert(:user) + {:ok, activity} = CommonAPI.post(user, %{status: "test"}) + + {:ok, _} = CommonAPI.react_with_emoji(activity.id, other_user, "🎅") + User.mute(user, other_user) + + result = + conn + |> get("/api/v1/statuses/?ids[]=#{activity.id}") + |> json_response_and_validate_schema(200) + + assert [ + %{ + "pleroma" => %{ + "emoji_reactions" => [] + } + } + ] = result + + result = + conn + |> get("/api/v1/statuses/?ids[]=#{activity.id}&with_muted=true") + |> json_response_and_validate_schema(200) + + assert [ + %{ + "pleroma" => %{ + "emoji_reactions" => [%{"count" => 1, "me" => false, "name" => "🎅"}] + } + } + ] = result + end + + test "show" do + # %{conn: conn, user: user, token: token} = oauth_access(["read:statuses"]) + %{conn: conn, user: user, token: _token} = oauth_access(["read:statuses"]) + + other_user = insert(:user) + {:ok, activity} = CommonAPI.post(user, %{status: "test"}) + + {:ok, _} = CommonAPI.react_with_emoji(activity.id, other_user, "🎅") + User.mute(user, other_user) + + result = + conn + |> get("/api/v1/statuses/#{activity.id}") + |> json_response_and_validate_schema(200) + + assert %{ + "pleroma" => %{ + "emoji_reactions" => [] + } + } = result + + result = + conn + |> get("/api/v1/statuses/#{activity.id}?with_muted=true") + |> json_response_and_validate_schema(200) + + assert %{ + "pleroma" => %{ + "emoji_reactions" => [%{"count" => 1, "me" => false, "name" => "🎅"}] + } + } = result + end + end end diff --git a/test/web/mastodon_api/controllers/subscription_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/subscription_controller_test.exs index d36bb1ae8..5a3f93d2d 100644 --- a/test/web/mastodon_api/controllers/subscription_controller_test.exs +++ b/test/pleroma/web/mastodon_api/controllers/subscription_controller_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.MastodonAPI.SubscriptionControllerTest do - use Pleroma.Web.ConnCase + use Pleroma.Web.ConnCase, async: true import Pleroma.Factory @@ -45,21 +45,77 @@ defmodule Pleroma.Web.MastodonAPI.SubscriptionControllerTest do end end - describe "creates push subscription" do - test "returns error when push disabled ", %{conn: conn} do + describe "when disabled" do + test "POST returns error", %{conn: conn} do + assert_error_when_disable_push do + conn + |> post("/api/v1/push/subscription", %{ + "data" => %{"alerts" => %{"mention" => true}}, + "subscription" => @sub + }) + |> json_response_and_validate_schema(403) + end + end + + test "GET returns error", %{conn: conn} do assert_error_when_disable_push do conn - |> post("/api/v1/push/subscription", %{subscription: @sub}) + |> get("/api/v1/push/subscription", %{}) |> json_response_and_validate_schema(403) end end + test "PUT returns error", %{conn: conn} do + assert_error_when_disable_push do + conn + |> put("/api/v1/push/subscription", %{data: %{"alerts" => %{"mention" => false}}}) + |> json_response_and_validate_schema(403) + end + end + + test "DELETE returns error", %{conn: conn} do + assert_error_when_disable_push do + conn + |> delete("/api/v1/push/subscription", %{}) + |> json_response_and_validate_schema(403) + end + end + end + + describe "creates push subscription" do + test "ignores unsupported types", %{conn: conn} do + result = + conn + |> post("/api/v1/push/subscription", %{ + "data" => %{ + "alerts" => %{ + "fake_unsupported_type" => true + } + }, + "subscription" => @sub + }) + |> json_response_and_validate_schema(200) + + refute %{ + "alerts" => %{ + "fake_unsupported_type" => true + } + } == result + end + test "successful creation", %{conn: conn} do result = conn |> post("/api/v1/push/subscription", %{ "data" => %{ - "alerts" => %{"mention" => true, "test" => true, "pleroma:chat_mention" => true} + "alerts" => %{ + "mention" => true, + "favourite" => true, + "follow" => true, + "reblog" => true, + "pleroma:chat_mention" => true, + "pleroma:emoji_reaction" => true + } }, "subscription" => @sub }) @@ -68,7 +124,14 @@ defmodule Pleroma.Web.MastodonAPI.SubscriptionControllerTest do [subscription] = Pleroma.Repo.all(Subscription) assert %{ - "alerts" => %{"mention" => true, "pleroma:chat_mention" => true}, + "alerts" => %{ + "mention" => true, + "favourite" => true, + "follow" => true, + "reblog" => true, + "pleroma:chat_mention" => true, + "pleroma:emoji_reaction" => true + }, "endpoint" => subscription.endpoint, "id" => to_string(subscription.id), "server_key" => @server_key @@ -77,14 +140,6 @@ defmodule Pleroma.Web.MastodonAPI.SubscriptionControllerTest do end describe "gets a user subscription" do - test "returns error when push disabled ", %{conn: conn} do - assert_error_when_disable_push do - conn - |> get("/api/v1/push/subscription", %{}) - |> json_response_and_validate_schema(403) - end - end - test "returns error when user hasn't subscription", %{conn: conn} do res = conn @@ -124,30 +179,47 @@ defmodule Pleroma.Web.MastodonAPI.SubscriptionControllerTest do insert(:push_subscription, user: user, token: token, - data: %{"alerts" => %{"mention" => true}} + data: %{ + "alerts" => %{ + "mention" => true, + "favourite" => true, + "follow" => true, + "reblog" => true, + "pleroma:chat_mention" => true, + "pleroma:emoji_reaction" => true + } + } ) %{conn: conn, user: user, token: token, subscription: subscription} end - test "returns error when push disabled ", %{conn: conn} do - assert_error_when_disable_push do - conn - |> put("/api/v1/push/subscription", %{data: %{"alerts" => %{"mention" => false}}}) - |> json_response_and_validate_schema(403) - end - end - test "returns updated subsciption", %{conn: conn, subscription: subscription} do res = conn |> put("/api/v1/push/subscription", %{ - data: %{"alerts" => %{"mention" => false, "follow" => true}} + data: %{ + "alerts" => %{ + "mention" => false, + "favourite" => false, + "follow" => false, + "reblog" => false, + "pleroma:chat_mention" => false, + "pleroma:emoji_reaction" => false + } + } }) |> json_response_and_validate_schema(200) expect = %{ - "alerts" => %{"follow" => true, "mention" => false}, + "alerts" => %{ + "mention" => false, + "favourite" => false, + "follow" => false, + "reblog" => false, + "pleroma:chat_mention" => false, + "pleroma:emoji_reaction" => false + }, "endpoint" => "https://example.com/example/1234", "id" => to_string(subscription.id), "server_key" => @server_key @@ -158,14 +230,6 @@ defmodule Pleroma.Web.MastodonAPI.SubscriptionControllerTest do end describe "deletes the user subscription" do - test "returns error when push disabled ", %{conn: conn} do - assert_error_when_disable_push do - conn - |> delete("/api/v1/push/subscription", %{}) - |> json_response_and_validate_schema(403) - end - end - test "returns error when user hasn't subscription", %{conn: conn} do res = conn diff --git a/test/pleroma/web/mastodon_api/controllers/suggestion_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/suggestion_controller_test.exs new file mode 100644 index 000000000..89273e67b --- /dev/null +++ b/test/pleroma/web/mastodon_api/controllers/suggestion_controller_test.exs @@ -0,0 +1,83 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.SuggestionControllerTest do + use Pleroma.Web.ConnCase, async: true + alias Pleroma.UserRelationship + alias Pleroma.Web.CommonAPI + import Pleroma.Factory + + setup do: oauth_access(["read", "write"]) + + test "returns empty result", %{conn: conn} do + res = + conn + |> get("/api/v1/suggestions") + |> json_response_and_validate_schema(200) + + assert res == [] + end + + test "returns v2 suggestions", %{conn: conn} do + %{id: user_id} = insert(:user, is_suggested: true) + + res = + conn + |> get("/api/v2/suggestions") + |> json_response_and_validate_schema(200) + + assert [%{"source" => "staff", "account" => %{"id" => ^user_id}}] = res + end + + test "returns v2 suggestions excluding dismissed accounts", %{conn: conn} do + %{id: user_id} = insert(:user, is_suggested: true) + + conn + |> delete("/api/v1/suggestions/#{user_id}") + |> json_response_and_validate_schema(200) + + res = + conn + |> get("/api/v2/suggestions") + |> json_response_and_validate_schema(200) + + assert [] = res + end + + test "returns v2 suggestions excluding blocked accounts", %{conn: conn, user: blocker} do + blocked = insert(:user, is_suggested: true) + {:ok, _} = CommonAPI.block(blocker, blocked) + + res = + conn + |> get("/api/v2/suggestions") + |> json_response_and_validate_schema(200) + + assert [] = res + end + + test "returns v2 suggestions excluding followed accounts", %{conn: conn, user: follower} do + followed = insert(:user, is_suggested: true) + {:ok, _, _, _} = CommonAPI.follow(follower, followed) + + res = + conn + |> get("/api/v2/suggestions") + |> json_response_and_validate_schema(200) + + assert [] = res + end + + test "dismiss suggestion", %{conn: conn, user: source} do + target = insert(:user, is_suggested: true) + + res = + conn + |> delete("/api/v1/suggestions/#{target.id}") + |> json_response_and_validate_schema(200) + + assert res == %{} + assert UserRelationship.exists?(:suggestion_dismiss, source, target) + end +end diff --git a/test/web/mastodon_api/controllers/timeline_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/timeline_controller_test.exs index 517cabcff..187982d92 100644 --- a/test/web/mastodon_api/controllers/timeline_controller_test.exs +++ b/test/pleroma/web/mastodon_api/controllers/timeline_controller_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do @@ -8,7 +8,6 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do import Pleroma.Factory import Tesla.Mock - alias Pleroma.Config alias Pleroma.User alias Pleroma.Web.CommonAPI @@ -55,6 +54,101 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do assert private_activity.id in status_ids refute direct_activity.id in status_ids end + + test "muted emotions", %{user: user, conn: conn} do + other_user = insert(:user) + {:ok, activity} = CommonAPI.post(user, %{status: "."}) + + {:ok, _} = CommonAPI.react_with_emoji(activity.id, other_user, "🎅") + User.mute(user, other_user) + + result = + conn + |> assign(:user, user) + |> get("/api/v1/timelines/home") + |> json_response_and_validate_schema(200) + + assert [ + %{ + "pleroma" => %{ + "emoji_reactions" => [] + } + } + ] = result + + result = + conn + |> assign(:user, user) + |> get("/api/v1/timelines/home?with_muted=true") + |> json_response_and_validate_schema(200) + + assert [ + %{ + "pleroma" => %{ + "emoji_reactions" => [%{"count" => 1, "me" => false, "name" => "🎅"}] + } + } + ] = result + end + + test "filtering", %{conn: conn, user: user} do + local_user = insert(:user) + {:ok, user, local_user} = User.follow(user, local_user) + {:ok, local_activity} = CommonAPI.post(local_user, %{status: "Status"}) + with_media = create_with_media_activity(local_user) + + remote_user = insert(:user, local: false) + {:ok, _user, remote_user} = User.follow(user, remote_user) + remote_activity = create_remote_activity(remote_user) + + without_filter_ids = + conn + |> get("/api/v1/timelines/home") + |> json_response_and_validate_schema(200) + |> Enum.map(& &1["id"]) + + assert local_activity.id in without_filter_ids + assert remote_activity.id in without_filter_ids + assert with_media.id in without_filter_ids + + only_local_ids = + conn + |> get("/api/v1/timelines/home?local=true") + |> json_response_and_validate_schema(200) + |> Enum.map(& &1["id"]) + + assert local_activity.id in only_local_ids + refute remote_activity.id in only_local_ids + assert with_media.id in only_local_ids + + only_local_media_ids = + conn + |> get("/api/v1/timelines/home?local=true&only_media=true") + |> json_response_and_validate_schema(200) + |> Enum.map(& &1["id"]) + + refute local_activity.id in only_local_media_ids + refute remote_activity.id in only_local_media_ids + assert with_media.id in only_local_media_ids + + remote_ids = + conn + |> get("/api/v1/timelines/home?remote=true") + |> json_response_and_validate_schema(200) + |> Enum.map(& &1["id"]) + + refute local_activity.id in remote_ids + assert remote_activity.id in remote_ids + refute with_media.id in remote_ids + + assert conn + |> get("/api/v1/timelines/home?remote=true&only_media=true") + |> json_response_and_validate_schema(200) == [] + + assert conn + |> get("/api/v1/timelines/home?remote=true&local=true") + |> json_response_and_validate_schema(200) == [] + end end describe "public" do @@ -63,27 +157,80 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do user = insert(:user) {:ok, activity} = CommonAPI.post(user, %{status: "test"}) + with_media = create_with_media_activity(user) - _activity = insert(:note_activity, local: false) + remote = insert(:note_activity, local: false) - conn = get(conn, "/api/v1/timelines/public?local=False") + assert conn + |> get("/api/v1/timelines/public?local=False") + |> json_response_and_validate_schema(:ok) + |> length == 3 - assert length(json_response_and_validate_schema(conn, :ok)) == 2 + local_ids = + conn + |> get("/api/v1/timelines/public?local=True") + |> json_response_and_validate_schema(:ok) + |> Enum.map(& &1["id"]) - conn = get(build_conn(), "/api/v1/timelines/public?local=True") + assert activity.id in local_ids + assert with_media.id in local_ids + refute remote.id in local_ids - assert [%{"content" => "test"}] = json_response_and_validate_schema(conn, :ok) + local_ids = + conn + |> get("/api/v1/timelines/public?local=True") + |> json_response_and_validate_schema(:ok) + |> Enum.map(& &1["id"]) - conn = get(build_conn(), "/api/v1/timelines/public?local=1") + assert activity.id in local_ids + assert with_media.id in local_ids + refute remote.id in local_ids - assert [%{"content" => "test"}] = json_response_and_validate_schema(conn, :ok) + local_ids = + conn + |> get("/api/v1/timelines/public?local=True&only_media=true") + |> json_response_and_validate_schema(:ok) + |> Enum.map(& &1["id"]) + + refute activity.id in local_ids + assert with_media.id in local_ids + refute remote.id in local_ids + + local_ids = + conn + |> get("/api/v1/timelines/public?local=1") + |> json_response_and_validate_schema(:ok) + |> Enum.map(& &1["id"]) + + assert activity.id in local_ids + assert with_media.id in local_ids + refute remote.id in local_ids + + remote_id = remote.id + + assert [%{"id" => ^remote_id}] = + conn + |> get("/api/v1/timelines/public?remote=true") + |> json_response_and_validate_schema(:ok) + + with_media_id = with_media.id + + assert [%{"id" => ^with_media_id}] = + conn + |> get("/api/v1/timelines/public?only_media=true") + |> json_response_and_validate_schema(:ok) + + assert conn + |> get("/api/v1/timelines/public?remote=true&only_media=true") + |> json_response_and_validate_schema(:ok) == [] # does not contain repeats {:ok, _} = CommonAPI.repeat(activity.id, user) - conn = get(build_conn(), "/api/v1/timelines/public?local=true") - - assert [_] = json_response_and_validate_schema(conn, :ok) + assert [_, _] = + conn + |> get("/api/v1/timelines/public?local=true") + |> json_response_and_validate_schema(:ok) end test "the public timeline includes only public statuses for an authenticated user" do @@ -101,7 +248,7 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do test "doesn't return replies if follower is posting with blocked user" do %{conn: conn, user: blocker} = oauth_access(["read:statuses"]) [blockee, friend] = insert_list(2, :user) - {:ok, blocker} = User.follow(blocker, friend) + {:ok, blocker, friend} = User.follow(blocker, friend) {:ok, _} = User.block(blocker, blockee) conn = assign(conn, :user, blocker) @@ -114,15 +261,41 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do {:ok, _reply_from_friend} = CommonAPI.post(friend, %{status: "status", in_reply_to_status_id: reply_from_blockee}) - res_conn = get(conn, "/api/v1/timelines/public") - [%{"id" => ^activity_id}] = json_response_and_validate_schema(res_conn, 200) + # Still shows replies from yourself + {:ok, %{id: reply_from_me}} = + CommonAPI.post(blocker, %{status: "status", in_reply_to_status_id: reply_from_blockee}) + + response = + get(conn, "/api/v1/timelines/public") + |> json_response_and_validate_schema(200) + + assert length(response) == 2 + [%{"id" => ^reply_from_me}, %{"id" => ^activity_id}] = response + end + + test "doesn't return posts from users who blocked you when :blockers_visible is disabled" do + clear_config([:activitypub, :blockers_visible], false) + + %{conn: conn, user: blockee} = oauth_access(["read:statuses"]) + blocker = insert(:user) + {:ok, _} = User.block(blocker, blockee) + + conn = assign(conn, :user, blockee) + + {:ok, _} = CommonAPI.post(blocker, %{status: "hey!"}) + + response = + get(conn, "/api/v1/timelines/public") + |> json_response_and_validate_schema(200) + + assert length(response) == 0 end test "doesn't return replies if follow is posting with users from blocked domain" do %{conn: conn, user: blocker} = oauth_access(["read:statuses"]) friend = insert(:user) blockee = insert(:user, ap_id: "https://example.com/users/blocked") - {:ok, blocker} = User.follow(blocker, friend) + {:ok, blocker, friend} = User.follow(blocker, friend) {:ok, blocker} = User.block_domain(blocker, "example.com") conn = assign(conn, :user, blocker) @@ -140,6 +313,60 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do activities = json_response_and_validate_schema(res_conn, 200) [%{"id" => ^activity_id}] = activities end + + test "can be filtered by instance", %{conn: conn} do + user = insert(:user, ap_id: "https://lain.com/users/lain") + insert(:note_activity, local: false) + insert(:note_activity, local: false) + + {:ok, _} = CommonAPI.post(user, %{status: "test"}) + + conn = get(conn, "/api/v1/timelines/public?instance=lain.com") + + assert length(json_response_and_validate_schema(conn, :ok)) == 1 + end + + test "muted emotions", %{conn: conn} do + user = insert(:user) + token = insert(:oauth_token, user: user, scopes: ["read:statuses"]) + + conn = + conn + |> assign(:user, user) + |> assign(:token, token) + + other_user = insert(:user) + {:ok, activity} = CommonAPI.post(user, %{status: "."}) + + {:ok, _} = CommonAPI.react_with_emoji(activity.id, other_user, "🎅") + User.mute(user, other_user) + + result = + conn + |> get("/api/v1/timelines/public") + |> json_response_and_validate_schema(200) + + assert [ + %{ + "pleroma" => %{ + "emoji_reactions" => [] + } + } + ] = result + + result = + conn + |> get("/api/v1/timelines/public?with_muted=true") + |> json_response_and_validate_schema(200) + + assert [ + %{ + "pleroma" => %{ + "emoji_reactions" => [%{"count" => 1, "me" => false, "name" => "🎅"}] + } + } + ] = result + end end defp local_and_remote_activities do @@ -239,7 +466,7 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do user_one = insert(:user) user_two = insert(:user) - {:ok, user_two} = User.follow(user_two, user_one) + {:ok, user_two, user_one} = User.follow(user_two, user_one) {:ok, direct} = CommonAPI.post(user_one, %{ @@ -409,6 +636,115 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do assert id == to_string(activity_one.id) end + + test "muted emotions", %{user: user, conn: conn} do + user2 = insert(:user) + user3 = insert(:user) + {:ok, activity} = CommonAPI.post(user2, %{status: "."}) + + {:ok, _} = CommonAPI.react_with_emoji(activity.id, user3, "🎅") + User.mute(user, user3) + + {:ok, list} = Pleroma.List.create("name", user) + {:ok, list} = Pleroma.List.follow(list, user2) + + result = + conn + |> get("/api/v1/timelines/list/#{list.id}") + |> json_response_and_validate_schema(200) + + assert [ + %{ + "pleroma" => %{ + "emoji_reactions" => [] + } + } + ] = result + + result = + conn + |> get("/api/v1/timelines/list/#{list.id}?with_muted=true") + |> json_response_and_validate_schema(200) + + assert [ + %{ + "pleroma" => %{ + "emoji_reactions" => [%{"count" => 1, "me" => false, "name" => "🎅"}] + } + } + ] = result + end + + test "filtering", %{user: user, conn: conn} do + {:ok, list} = Pleroma.List.create("name", user) + + local_user = insert(:user) + {:ok, local_activity} = CommonAPI.post(local_user, %{status: "Marisa is stupid."}) + with_media = create_with_media_activity(local_user) + {:ok, list} = Pleroma.List.follow(list, local_user) + + remote_user = insert(:user, local: false) + remote_activity = create_remote_activity(remote_user) + {:ok, list} = Pleroma.List.follow(list, remote_user) + + all_ids = + conn + |> get("/api/v1/timelines/list/#{list.id}") + |> json_response_and_validate_schema(200) + |> Enum.map(& &1["id"]) + + assert local_activity.id in all_ids + assert with_media.id in all_ids + assert remote_activity.id in all_ids + + only_local_ids = + conn + |> get("/api/v1/timelines/list/#{list.id}?local=true") + |> json_response_and_validate_schema(200) + |> Enum.map(& &1["id"]) + + assert local_activity.id in only_local_ids + assert with_media.id in only_local_ids + refute remote_activity.id in only_local_ids + + only_local_media_ids = + conn + |> get("/api/v1/timelines/list/#{list.id}?local=true&only_media=true") + |> json_response_and_validate_schema(200) + |> Enum.map(& &1["id"]) + + refute local_activity.id in only_local_media_ids + assert with_media.id in only_local_media_ids + refute remote_activity.id in only_local_media_ids + + remote_ids = + conn + |> get("/api/v1/timelines/list/#{list.id}?remote=true") + |> json_response_and_validate_schema(200) + |> Enum.map(& &1["id"]) + + refute local_activity.id in remote_ids + refute with_media.id in remote_ids + assert remote_activity.id in remote_ids + + assert conn + |> get("/api/v1/timelines/list/#{list.id}?remote=true&only_media=true") + |> json_response_and_validate_schema(200) == [] + + only_media_ids = + conn + |> get("/api/v1/timelines/list/#{list.id}?only_media=true") + |> json_response_and_validate_schema(200) + |> Enum.map(& &1["id"]) + + refute local_activity.id in only_media_ids + assert with_media.id in only_media_ids + refute remote_activity.id in only_media_ids + + assert conn + |> get("/api/v1/timelines/list/#{list.id}?only_media=true&local=true&remote=true") + |> json_response_and_validate_schema(200) == [] + end end describe "hashtag" do @@ -419,19 +755,85 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do following = insert(:user) {:ok, activity} = CommonAPI.post(following, %{status: "test #2hu"}) + with_media = create_with_media_activity(following) - nconn = get(conn, "/api/v1/timelines/tag/2hu") + remote = insert(:user, local: false) + remote_activity = create_remote_activity(remote) - assert [%{"id" => id}] = json_response_and_validate_schema(nconn, :ok) + all_ids = + conn + |> get("/api/v1/timelines/tag/2hu") + |> json_response_and_validate_schema(:ok) + |> Enum.map(& &1["id"]) - assert id == to_string(activity.id) + assert activity.id in all_ids + assert with_media.id in all_ids + assert remote_activity.id in all_ids # works for different capitalization too - nconn = get(conn, "/api/v1/timelines/tag/2HU") + all_ids = + conn + |> get("/api/v1/timelines/tag/2HU") + |> json_response_and_validate_schema(:ok) + |> Enum.map(& &1["id"]) - assert [%{"id" => id}] = json_response_and_validate_schema(nconn, :ok) + assert activity.id in all_ids + assert with_media.id in all_ids + assert remote_activity.id in all_ids - assert id == to_string(activity.id) + local_ids = + conn + |> get("/api/v1/timelines/tag/2hu?local=true") + |> json_response_and_validate_schema(:ok) + |> Enum.map(& &1["id"]) + + assert activity.id in local_ids + assert with_media.id in local_ids + refute remote_activity.id in local_ids + + remote_ids = + conn + |> get("/api/v1/timelines/tag/2hu?remote=true") + |> json_response_and_validate_schema(:ok) + |> Enum.map(& &1["id"]) + + refute activity.id in remote_ids + refute with_media.id in remote_ids + assert remote_activity.id in remote_ids + + media_ids = + conn + |> get("/api/v1/timelines/tag/2hu?only_media=true") + |> json_response_and_validate_schema(:ok) + |> Enum.map(& &1["id"]) + + refute activity.id in media_ids + assert with_media.id in media_ids + refute remote_activity.id in media_ids + + media_local_ids = + conn + |> get("/api/v1/timelines/tag/2hu?only_media=true&local=true") + |> json_response_and_validate_schema(:ok) + |> Enum.map(& &1["id"]) + + refute activity.id in media_local_ids + assert with_media.id in media_local_ids + refute remote_activity.id in media_local_ids + + ids = + conn + |> get("/api/v1/timelines/tag/2hu?only_media=true&local=true&remote=true") + |> json_response_and_validate_schema(:ok) + |> Enum.map(& &1["id"]) + + refute activity.id in ids + refute with_media.id in ids + refute remote_activity.id in ids + + assert conn + |> get("/api/v1/timelines/tag/2hu?only_media=true&remote=true") + |> json_response_and_validate_schema(:ok) == [] end test "multi-hashtag timeline", %{conn: conn} do @@ -457,6 +859,48 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do assert [status_none] == json_response_and_validate_schema(all_test, :ok) end + + test "muted emotions", %{conn: conn} do + user = insert(:user) + token = insert(:oauth_token, user: user, scopes: ["read:statuses"]) + + conn = + conn + |> assign(:user, user) + |> assign(:token, token) + + other_user = insert(:user) + {:ok, activity} = CommonAPI.post(user, %{status: "test #2hu"}) + + {:ok, _} = CommonAPI.react_with_emoji(activity.id, other_user, "🎅") + User.mute(user, other_user) + + result = + conn + |> get("/api/v1/timelines/tag/2hu") + |> json_response_and_validate_schema(200) + + assert [ + %{ + "pleroma" => %{ + "emoji_reactions" => [] + } + } + ] = result + + result = + conn + |> get("/api/v1/timelines/tag/2hu?with_muted=true") + |> json_response_and_validate_schema(200) + + assert [ + %{ + "pleroma" => %{ + "emoji_reactions" => [%{"count" => 1, "me" => false, "name" => "🎅"}] + } + } + ] = result + end end describe "hashtag timeline handling of :restrict_unauthenticated setting" do @@ -479,10 +923,10 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do %{conn: auth_conn} = oauth_access(["read:statuses"]) res_conn = get(auth_conn, "#{base_uri}?local=true") - assert length(json_response(res_conn, 200)) == 1 + assert length(json_response_and_validate_schema(res_conn, 200)) == 1 res_conn = get(auth_conn, "#{base_uri}?local=false") - assert length(json_response(res_conn, 200)) == 2 + assert length(json_response_and_validate_schema(res_conn, 200)) == 2 end test "with default settings on private instances, returns 403 for unauthenticated users", %{ @@ -496,7 +940,7 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do for local <- [true, false] do res_conn = get(conn, "#{base_uri}?local=#{local}") - assert json_response(res_conn, :unauthorized) == error_response + assert json_response_and_validate_schema(res_conn, :unauthorized) == error_response end ensure_authenticated_access(base_uri) @@ -513,7 +957,7 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do for local <- [true, false] do res_conn = get(conn, "#{base_uri}?local=#{local}") - assert json_response(res_conn, :unauthorized) == error_response + assert json_response_and_validate_schema(res_conn, :unauthorized) == error_response end ensure_authenticated_access(base_uri) @@ -525,10 +969,10 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do clear_config([:restrict_unauthenticated, :timelines, :federated], true) res_conn = get(conn, "#{base_uri}?local=true") - assert length(json_response(res_conn, 200)) == 1 + assert length(json_response_and_validate_schema(res_conn, 200)) == 1 res_conn = get(conn, "#{base_uri}?local=false") - assert json_response(res_conn, :unauthorized) == error_response + assert json_response_and_validate_schema(res_conn, :unauthorized) == error_response ensure_authenticated_access(base_uri) end @@ -540,13 +984,46 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do clear_config([:restrict_unauthenticated, :timelines, :federated], false) res_conn = get(conn, "#{base_uri}?local=true") - assert json_response(res_conn, :unauthorized) == error_response + assert json_response_and_validate_schema(res_conn, :unauthorized) == error_response # Note: local activities get delivered as part of federated timeline res_conn = get(conn, "#{base_uri}?local=false") - assert length(json_response(res_conn, 200)) == 2 + assert length(json_response_and_validate_schema(res_conn, 200)) == 2 ensure_authenticated_access(base_uri) end end + + defp create_remote_activity(user) do + obj = + insert(:note, %{ + data: %{ + "to" => [ + "https://www.w3.org/ns/activitystreams#Public", + User.ap_followers(user) + ] + }, + user: user + }) + + insert(:note_activity, %{ + note: obj, + recipients: [ + "https://www.w3.org/ns/activitystreams#Public", + User.ap_followers(user) + ], + user: user, + local: false + }) + end + + defp create_with_media_activity(user) do + obj = insert(:attachment_note, user: user) + + insert(:note_activity, %{ + note: obj, + recipients: ["https://www.w3.org/ns/activitystreams#Public", User.ap_followers(user)], + user: user + }) + end end diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/pleroma/web/mastodon_api/mastodon_api_controller_test.exs index bb4bc4396..c6332bd3e 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/pleroma/web/mastodon_api/mastodon_api_controller_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do - use Pleroma.Web.ConnCase + use Pleroma.Web.ConnCase, async: true describe "empty_array/2 (stubs)" do test "GET /api/v1/accounts/:id/identity_proofs" do diff --git a/test/web/mastodon_api/mastodon_api_test.exs b/test/pleroma/web/mastodon_api/mastodon_api_test.exs index 0c5a38bf6..402bfd76f 100644 --- a/test/web/mastodon_api/mastodon_api_test.exs +++ b/test/pleroma/web/mastodon_api/mastodon_api_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.MastodonAPI.MastodonAPITest do - use Pleroma.Web.ConnCase + use Pleroma.Web.ConnCase, async: true alias Pleroma.Notification alias Pleroma.ScheduledActivity @@ -16,7 +16,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPITest do describe "follow/3" do test "returns error when followed user is deactivated" do follower = insert(:user) - user = insert(:user, local: true, deactivated: true) + user = insert(:user, local: true, is_active: false) assert {:error, _error} = MastodonAPI.follow(follower, user) end @@ -30,7 +30,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPITest do test "returns ok if user already followed" do follower = insert(:user) user = insert(:user) - {:ok, follower} = User.follow(follower, user) + {:ok, follower, user} = User.follow(follower, user) {:ok, follower} = MastodonAPI.follow(follower, refresh_record(user)) assert User.following?(follower, user) end @@ -41,8 +41,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPITest 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) + {:ok, _follower1_user, _user} = User.follow(follower1_user, user) + {:ok, follower2_user, _user} = User.follow(follower2_user, user) assert MastodonAPI.get_followers(user, %{"limit" => 1}) == [follower2_user] end @@ -55,9 +55,9 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPITest do 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) + {:ok, user, followed_one} = User.follow(user, followed_one) + {:ok, user, followed_two} = User.follow(user, followed_two) + {:ok, user, followed_three} = User.follow(user, followed_three) res = MastodonAPI.get_friends(user) assert length(res) == 3 diff --git a/test/web/mastodon_api/controllers/account_controller/update_credentials_test.exs b/test/pleroma/web/mastodon_api/update_credentials_test.exs index 2e6704726..1d2027899 100644 --- a/test/web/mastodon_api/controllers/account_controller/update_credentials_test.exs +++ b/test/pleroma/web/mastodon_api/update_credentials_test.exs @@ -1,8 +1,8 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.Web.MastodonAPI.MastodonAPIController.UpdateCredentialsTest do +defmodule Pleroma.Web.MastodonAPI.UpdateCredentialsTest do alias Pleroma.Repo alias Pleroma.User @@ -11,8 +11,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController.UpdateCredentialsTest do import Mock import Pleroma.Factory - setup do: clear_config([:instance, :max_account_fields]) - describe "updating credentials" do setup do: oauth_access(["write:accounts"]) setup :request_content_type @@ -37,8 +35,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController.UpdateCredentialsTest do |> assign(:user, user) |> patch("/api/v1/accounts/update_credentials", %{ "pleroma_settings_store" => %{ - masto_fe: %{ - theme: "bla" + soapbox_fe: %{ + themeMode: "bla" } } }) @@ -48,7 +46,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController.UpdateCredentialsTest do assert user_data["pleroma"]["settings_store"] == %{ "pleroma_fe" => %{"theme" => "bla"}, - "masto_fe" => %{"theme" => "bla"} + "soapbox_fe" => %{"themeMode" => "bla"} } user = Repo.get(User, user_data["id"]) @@ -62,8 +60,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController.UpdateCredentialsTest do |> assign(:user, user) |> patch("/api/v1/accounts/update_credentials", %{ "pleroma_settings_store" => %{ - masto_fe: %{ - theme: "blub" + soapbox_fe: %{ + themeMode: "blub" } } }) @@ -73,7 +71,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController.UpdateCredentialsTest do assert user_data["pleroma"]["settings_store"] == %{ "pleroma_fe" => %{"theme" => "bla"}, - "masto_fe" => %{"theme" => "blub"} + "soapbox_fe" => %{"themeMode" => "blub"} } assert_called(Pleroma.Web.Federator.publish(:_)) @@ -90,9 +88,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController.UpdateCredentialsTest do assert user_data = json_response_and_validate_schema(conn, 200) assert user_data["note"] == - ~s(I drink <a class="hashtag" data-tag="cofe" href="http://localhost:4001/tag/cofe">#cofe</a> with <span class="h-card"><a class="u-url mention" data-user="#{ - user2.id - }" href="#{user2.ap_id}" rel="ugc">@<span>#{user2.nickname}</span></a></span><br/><br/>suya..) + ~s(I drink <a class="hashtag" data-tag="cofe" href="http://localhost:4001/tag/cofe">#cofe</a> with <span class="h-card"><a class="u-url mention" data-user="#{user2.id}" href="#{user2.ap_id}" rel="ugc">@<span>#{user2.nickname}</span></a></span><br/><br/>suya..) assert user_data["source"]["note"] == raw_bio @@ -220,9 +216,28 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController.UpdateCredentialsTest do assert update_activity.data["object"]["name"] == "markorepairs" end + test "updates the user's AKAs", %{conn: conn} do + conn = + patch(conn, "/api/v1/accounts/update_credentials", %{ + "also_known_as" => ["https://mushroom.kingdom/users/mario"] + }) + + assert user_data = json_response_and_validate_schema(conn, 200) + assert user_data["pleroma"]["also_known_as"] == ["https://mushroom.kingdom/users/mario"] + end + + test "doesn't update non-url akas", %{conn: conn} do + conn = + patch(conn, "/api/v1/accounts/update_credentials", %{ + "also_known_as" => ["aReallyCoolGuy"] + }) + + assert json_response_and_validate_schema(conn, 403) + end + test "updates the user's avatar", %{user: user, conn: conn} do new_avatar = %Plug.Upload{ - content_type: "image/jpg", + content_type: "image/jpeg", path: Path.absname("test/fixtures/image.jpg"), filename: "an_image.jpg" } @@ -246,7 +261,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController.UpdateCredentialsTest do test "updates the user's banner", %{user: user, conn: conn} do new_header = %Plug.Upload{ - content_type: "image/jpg", + content_type: "image/jpeg", path: Path.absname("test/fixtures/image.jpg"), filename: "an_image.jpg" } @@ -265,7 +280,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController.UpdateCredentialsTest do test "updates the user's background", %{conn: conn, user: user} do new_header = %Plug.Upload{ - content_type: "image/jpg", + content_type: "image/jpeg", path: Path.absname("test/fixtures/image.jpg"), filename: "an_image.jpg" } @@ -446,7 +461,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController.UpdateCredentialsTest do |> patch("/api/v1/accounts/update_credentials", %{"fields_attributes" => fields}) |> json_response_and_validate_schema(403) - Pleroma.Config.put([:instance, :max_account_fields], 1) + clear_config([:instance, :max_account_fields], 1) fields = [ %{"name" => "foo", "value" => "bar"}, diff --git a/test/web/mastodon_api/views/account_view_test.exs b/test/pleroma/web/mastodon_api/views/account_view_test.exs index 8f37efa3c..c23ffb966 100644 --- a/test/web/mastodon_api/views/account_view_test.exs +++ b/test/pleroma/web/mastodon_api/views/account_view_test.exs @@ -1,11 +1,10 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.MastodonAPI.AccountViewTest do use Pleroma.DataCase - alias Pleroma.Config alias Pleroma.User alias Pleroma.UserRelationship alias Pleroma.Web.CommonAPI @@ -19,8 +18,6 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do :ok end - setup do: clear_config([:instances_favicons, :enabled]) - test "Represent a user account" do background_image = %{ "url" => [%{"href" => "https://example.com/images/asuka_hospital.png"}] @@ -37,7 +34,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do "<script src=\"invalid-html\"></script><span>valid html</span>. a<br>b<br/>c<br >d<br />f '&<>\"", inserted_at: ~N[2017-08-15 15:47:06.597036], emoji: %{"karjalanpiirakka" => "/file.png"}, - raw_bio: "valid html. a\nb\nc\nd\nf '&<>\"" + raw_bio: "valid html. a\nb\nc\nd\nf '&<>\"", + also_known_as: ["https://shitposter.zone/users/shp"] }) expected = %{ @@ -71,19 +69,22 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do sensitive: false, pleroma: %{ actor_type: "Person", - discoverable: false + discoverable: true }, fields: [] }, + fqn: "shp@shitposter.club", + last_status_at: nil, pleroma: %{ ap_id: user.ap_id, + also_known_as: ["https://shitposter.zone/users/shp"], background_image: "https://example.com/images/asuka_hospital.png", - favicon: - "https://shitposter.club/plugins/Qvitter/img/gnusocial-favicons/favicon-16x16.png", - confirmation_pending: false, + favicon: nil, + is_confirmed: true, tags: [], is_admin: false, is_moderator: false, + is_suggested: false, hide_favorites: true, hide_followers: false, hide_follows: false, @@ -98,22 +99,26 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do assert expected == AccountView.render("show.json", %{user: user, skip_visibility_check: true}) end - test "Favicon is nil when :instances_favicons is disabled" do - user = insert(:user) + describe "favicon" do + setup do + [user: insert(:user)] + end - Config.put([:instances_favicons, :enabled], true) + test "is parsed when :instance_favicons is enabled", %{user: user} do + clear_config([:instances_favicons, :enabled], true) - assert %{ - pleroma: %{ - favicon: - "https://shitposter.club/plugins/Qvitter/img/gnusocial-favicons/favicon-16x16.png" - } - } = AccountView.render("show.json", %{user: user, skip_visibility_check: true}) - - Config.put([:instances_favicons, :enabled], false) + assert %{ + pleroma: %{ + favicon: + "https://shitposter.club/plugins/Qvitter/img/gnusocial-favicons/favicon-16x16.png" + } + } = AccountView.render("show.json", %{user: user, skip_visibility_check: true}) + end - assert %{pleroma: %{favicon: nil}} = - AccountView.render("show.json", %{user: user, skip_visibility_check: true}) + test "is nil when :instances_favicons is disabled", %{user: user} do + assert %{pleroma: %{favicon: nil}} = + AccountView.render("show.json", %{user: user, skip_visibility_check: true}) + end end test "Represent the user account for the account owner" do @@ -166,19 +171,22 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do sensitive: false, pleroma: %{ actor_type: "Service", - discoverable: false + discoverable: true }, fields: [] }, + fqn: "shp@shitposter.club", + last_status_at: nil, pleroma: %{ ap_id: user.ap_id, + also_known_as: [], background_image: nil, - favicon: - "https://shitposter.club/plugins/Qvitter/img/gnusocial-favicons/favicon-16x16.png", - confirmation_pending: false, + favicon: nil, + is_confirmed: true, tags: [], is_admin: false, is_moderator: false, + is_suggested: false, hide_favorites: true, hide_followers: false, hide_follows: false, @@ -208,7 +216,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do test "Represent a deactivated user for an admin" do admin = insert(:user, is_admin: true) - deactivated_user = insert(:user, deactivated: true) + deactivated_user = insert(:user, is_active: false) represented = AccountView.render("show.json", %{user: deactivated_user, for: admin}) assert represented[:pleroma][:deactivated] == true end @@ -264,20 +272,22 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do muting: false, muting_notifications: false, subscribing: false, + notifying: false, requested: false, domain_blocking: false, showing_reblogs: true, - endorsed: false + endorsed: false, + note: "" } test "represent a relationship for the following and followed user" do user = insert(:user) other_user = insert(:user) - {:ok, user} = User.follow(user, other_user) - {:ok, other_user} = User.follow(other_user, user) + {:ok, user, other_user} = User.follow(user, other_user) + {:ok, other_user, user} = User.follow(other_user, user) {:ok, _subscription} = User.subscribe(user, other_user) - {:ok, _user_relationships} = User.mute(user, other_user, true) + {:ok, _user_relationships} = User.mute(user, other_user, %{notifications: true}) {:ok, _reblog_mute} = CommonAPI.hide_reblogs(user, other_user) expected = @@ -289,6 +299,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do muting: true, muting_notifications: true, subscribing: true, + notifying: true, showing_reblogs: false, id: to_string(other_user.id) } @@ -301,7 +312,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do user = insert(:user) other_user = insert(:user) - {:ok, user} = User.follow(user, other_user) + {:ok, user, other_user} = User.follow(user, other_user) {:ok, _subscription} = User.subscribe(user, other_user) {:ok, _user_relationship} = User.block(user, other_user) {:ok, _user_relationship} = User.block(other_user, user) @@ -332,7 +343,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do test "represent a relationship for the user with a pending follow request" do user = insert(:user) - other_user = insert(:user, locked: true) + other_user = insert(:user, is_locked: true) {:ok, user, other_user, _} = CommonAPI.follow(user, other_user) user = User.get_cached_by_id(user.id) @@ -449,7 +460,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do test "shows unread_count only to the account owner" do user = insert(:user) - insert_list(7, :notification, user: user) + insert_list(7, :notification, user: user, activity: insert(:note_activity)) other_user = insert(:user) user = User.get_cached_by_ap_id(user.ap_id) @@ -464,6 +475,23 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do %{user: user, for: user} )[:pleroma][:unread_notifications_count] == 7 end + + test "shows email only to the account owner" do + user = insert(:user) + other_user = insert(:user) + + user = User.get_cached_by_ap_id(user.ap_id) + + assert AccountView.render( + "show.json", + %{user: user, for: other_user} + )[:pleroma][:email] == nil + + assert AccountView.render( + "show.json", + %{user: user, for: user} + )[:pleroma][:email] == user.email + end end describe "follow requests counter" do @@ -481,7 +509,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do end test "shows non-zero when follow requests are pending" do - user = insert(:user, locked: true) + user = insert(:user, is_locked: true) assert %{locked: true} = AccountView.render("show.json", %{user: user, for: user}) @@ -493,7 +521,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do end test "decreases when accepting a follow request" do - user = insert(:user, locked: true) + user = insert(:user, is_locked: true) assert %{locked: true} = AccountView.render("show.json", %{user: user, for: user}) @@ -510,7 +538,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do end test "decreases when rejecting a follow request" do - user = insert(:user, locked: true) + user = insert(:user, is_locked: true) assert %{locked: true} = AccountView.render("show.json", %{user: user, for: user}) @@ -527,22 +555,23 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do end test "shows non-zero when historical unapproved requests are present" do - user = insert(:user, locked: true) + user = insert(:user, is_locked: true) assert %{locked: true} = AccountView.render("show.json", %{user: user, for: user}) other_user = insert(:user) {:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user) - {:ok, user} = User.update_and_set_cache(user, %{locked: false}) + {:ok, user} = User.update_and_set_cache(user, %{is_locked: false}) assert %{locked: false, follow_requests_count: 1} = AccountView.render("show.json", %{user: user, for: user}) end end - test "uses mediaproxy urls when it's enabled" do + test "uses mediaproxy urls when it's enabled (regardless of media preview proxy state)" do clear_config([:media_proxy, :enabled], true) + clear_config([:media_preview_proxy, :enabled]) user = insert(:user, @@ -551,20 +580,24 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do emoji: %{"joker_smile" => "https://evil.website/society.png"} ) - AccountView.render("show.json", %{user: user, skip_visibility_check: true}) - |> Enum.all?(fn - {key, url} when key in [:avatar, :avatar_static, :header, :header_static] -> - String.starts_with?(url, Pleroma.Web.base_url()) - - {:emojis, emojis} -> - Enum.all?(emojis, fn %{url: url, static_url: static_url} -> - String.starts_with?(url, Pleroma.Web.base_url()) && - String.starts_with?(static_url, Pleroma.Web.base_url()) - end) - - _ -> - true - end) - |> assert() + with media_preview_enabled <- [false, true] do + clear_config([:media_preview_proxy, :enabled], media_preview_enabled) + + AccountView.render("show.json", %{user: user, skip_visibility_check: true}) + |> Enum.all?(fn + {key, url} when key in [:avatar, :avatar_static, :header, :header_static] -> + String.starts_with?(url, Pleroma.Web.Endpoint.url()) + + {:emojis, emojis} -> + Enum.all?(emojis, fn %{url: url, static_url: static_url} -> + String.starts_with?(url, Pleroma.Web.Endpoint.url()) && + String.starts_with?(static_url, Pleroma.Web.Endpoint.url()) + end) + + _ -> + true + end) + |> assert() + end end end diff --git a/test/web/mastodon_api/views/conversation_view_test.exs b/test/pleroma/web/mastodon_api/views/conversation_view_test.exs index 2e8203c9b..9639e95d2 100644 --- a/test/web/mastodon_api/views/conversation_view_test.exs +++ b/test/pleroma/web/mastodon_api/views/conversation_view_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.MastodonAPI.ConversationViewTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true alias Pleroma.Conversation.Participation alias Pleroma.Web.CommonAPI @@ -36,9 +36,11 @@ defmodule Pleroma.Web.MastodonAPI.ConversationViewTest do assert conversation.id == participation.id |> to_string() assert conversation.last_status.id == activity.id + assert conversation.last_status.account.id == user.id assert [account] = conversation.accounts assert account.id == other_user.id + assert conversation.last_status.pleroma.direct_conversation_id == participation.id end end diff --git a/test/web/mastodon_api/views/list_view_test.exs b/test/pleroma/web/mastodon_api/views/list_view_test.exs index ca99242cb..a62495ebb 100644 --- a/test/web/mastodon_api/views/list_view_test.exs +++ b/test/pleroma/web/mastodon_api/views/list_view_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.MastodonAPI.ListViewTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true import Pleroma.Factory alias Pleroma.Web.MastodonAPI.ListView diff --git a/test/web/mastodon_api/views/marker_view_test.exs b/test/pleroma/web/mastodon_api/views/marker_view_test.exs index 48a0a6d33..8d8c16f6c 100644 --- a/test/web/mastodon_api/views/marker_view_test.exs +++ b/test/pleroma/web/mastodon_api/views/marker_view_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.MastodonAPI.MarkerViewTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true alias Pleroma.Web.MastodonAPI.MarkerView import Pleroma.Factory diff --git a/test/web/mastodon_api/views/notification_view_test.exs b/test/pleroma/web/mastodon_api/views/notification_view_test.exs index 2f6a808f1..8070c03c9 100644 --- a/test/web/mastodon_api/views/notification_view_test.exs +++ b/test/pleroma/web/mastodon_api/views/notification_view_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do @@ -12,6 +12,8 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do alias Pleroma.Object alias Pleroma.Repo alias Pleroma.User + alias Pleroma.Web.AdminAPI.Report + alias Pleroma.Web.AdminAPI.ReportView alias Pleroma.Web.CommonAPI alias Pleroma.Web.CommonAPI.Utils alias Pleroma.Web.MastodonAPI.AccountView @@ -42,7 +44,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do {:ok, [notification]} = Notification.create_notifications(activity) - object = Object.normalize(activity) + object = Object.normalize(activity, fetch: false) chat = Chat.get(recipient.id, user.ap_id) cm_ref = MessageReference.for_chat_and_object(chat, object) @@ -142,24 +144,11 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do refute Repo.one(Notification) end - @tag capture_log: true test "Move notification" do old_user = insert(:user) new_user = insert(:user, also_known_as: [old_user.ap_id]) follower = insert(:user) - old_user_url = old_user.ap_id - - body = - File.read!("test/fixtures/users_mock/localhost.json") - |> String.replace("{{nickname}}", old_user.nickname) - |> Jason.encode!() - - Tesla.Mock.mock(fn - %{method: :get, url: ^old_user_url} -> - %Tesla.Env{status: 200, body: body} - end) - User.follow(follower, old_user) Pleroma.Web.ActivityPub.ActivityPub.move(old_user, new_user) Pleroma.Tests.ObanHelpers.perform_all() @@ -207,6 +196,47 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do test_notifications_rendering([notification], user, [expected]) end + test "Poll notification" do + user = insert(:user) + activity = insert(:question_activity, user: user) + {:ok, [notification]} = Notification.create_poll_notifications(activity) + + expected = %{ + id: to_string(notification.id), + pleroma: %{is_seen: false, is_muted: false}, + type: "poll", + account: + AccountView.render("show.json", %{ + user: user, + for: user + }), + status: StatusView.render("show.json", %{activity: activity, for: user}), + created_at: Utils.to_masto_date(notification.inserted_at) + } + + test_notifications_rendering([notification], user, [expected]) + end + + test "Report notification" do + reporting_user = insert(:user) + reported_user = insert(:user) + {:ok, moderator_user} = insert(:user) |> User.admin_api_update(%{is_moderator: true}) + + {:ok, activity} = CommonAPI.report(reporting_user, %{account_id: reported_user.id}) + {:ok, [notification]} = Notification.create_notifications(activity) + + expected = %{ + id: to_string(notification.id), + pleroma: %{is_seen: false, is_muted: false}, + type: "pleroma:report", + account: AccountView.render("show.json", %{user: reporting_user, for: moderator_user}), + created_at: Utils.to_masto_date(notification.inserted_at), + report: ReportView.render("show.json", Report.extract_report_info(activity)) + } + + test_notifications_rendering([notification], moderator_user, [expected]) + end + test "muted notification" do user = insert(:user) another_user = insert(:user) diff --git a/test/web/mastodon_api/views/poll_view_test.exs b/test/pleroma/web/mastodon_api/views/poll_view_test.exs index b7e2f17ef..224b26cb9 100644 --- a/test/web/mastodon_api/views/poll_view_test.exs +++ b/test/pleroma/web/mastodon_api/views/poll_view_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.MastodonAPI.PollViewTest do @@ -29,7 +29,7 @@ defmodule Pleroma.Web.MastodonAPI.PollViewTest do } }) - object = Object.normalize(activity) + object = Object.normalize(activity, fetch: false) expected = %{ emojis: [], @@ -42,9 +42,8 @@ defmodule Pleroma.Web.MastodonAPI.PollViewTest do %{title: "yes", votes_count: 0}, %{title: "why are you even asking?", votes_count: 0} ], - voted: false, votes_count: 0, - voters_count: nil + voters_count: 0 } result = PollView.render("show.json", %{object: object}) @@ -72,7 +71,7 @@ defmodule Pleroma.Web.MastodonAPI.PollViewTest do voter = insert(:user) - object = Object.normalize(activity) + object = Object.normalize(activity, fetch: false) {:ok, _votes, object} = CommonAPI.vote(voter, object, [0, 1]) @@ -98,7 +97,7 @@ defmodule Pleroma.Web.MastodonAPI.PollViewTest do } }) - object = Object.normalize(activity) + object = Object.normalize(activity, fetch: false) assert %{emojis: [%{shortcode: "blank"}]} = PollView.render("show.json", %{object: object}) end @@ -117,19 +116,21 @@ defmodule Pleroma.Web.MastodonAPI.PollViewTest do } }) - object = Object.normalize(activity) + object = Object.normalize(activity, fetch: false) {:ok, _, object} = CommonAPI.vote(other_user, object, [1, 2]) result = PollView.render("show.json", %{object: object, for: other_user}) assert result[:voted] == true + assert 1 in result[:own_votes] + assert 2 in result[:own_votes] assert Enum.at(result[:options], 1)[:votes_count] == 1 assert Enum.at(result[:options], 2)[:votes_count] == 1 end test "does not crash on polls with no end date" do - object = Object.normalize("https://skippers-bin.com/notes/7x9tmrp97i") + object = Object.normalize("https://skippers-bin.com/notes/7x9tmrp97i", fetch: true) result = PollView.render("show.json", %{object: object}) assert result[:expires_at] == nil @@ -153,7 +154,7 @@ defmodule Pleroma.Web.MastodonAPI.PollViewTest do } }) - object = Object.normalize(activity) + object = Object.normalize(activity, fetch: false) assert %{ options: [ diff --git a/test/web/mastodon_api/views/scheduled_activity_view_test.exs b/test/pleroma/web/mastodon_api/views/scheduled_activity_view_test.exs index fbfd873ef..e323f3a1f 100644 --- a/test/web/mastodon_api/views/scheduled_activity_view_test.exs +++ b/test/pleroma/web/mastodon_api/views/scheduled_activity_view_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.MastodonAPI.ScheduledActivityViewTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true alias Pleroma.ScheduledActivity alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.CommonAPI @@ -22,7 +22,7 @@ defmodule Pleroma.Web.MastodonAPI.ScheduledActivityViewTest do |> NaiveDateTime.to_iso8601() file = %Plug.Upload{ - content_type: "image/jpg", + content_type: "image/jpeg", path: Path.absname("test/fixtures/image.jpg"), filename: "an_image.jpg" } @@ -58,7 +58,8 @@ defmodule Pleroma.Web.MastodonAPI.ScheduledActivityViewTest do sensitive: true, spoiler_text: "spoiler", text: "hi", - visibility: "unlisted" + visibility: "unlisted", + expires_in: nil }, scheduled_at: Utils.to_masto_date(scheduled_activity.scheduled_at) } diff --git a/test/web/mastodon_api/views/status_view_test.exs b/test/pleroma/web/mastodon_api/views/status_view_test.exs index 70d829979..9dfdf8bf0 100644 --- a/test/web/mastodon_api/views/status_view_test.exs +++ b/test/pleroma/web/mastodon_api/views/status_view_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.MastodonAPI.StatusViewTest do @@ -61,7 +61,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do {:ok, activity} = CommonAPI.post(user, %{status: "yo"}) activity - |> Object.normalize(false) + |> Object.normalize(fetch: false) |> Object.update_data(%{"reactions" => %{"☕" => [user.ap_id], "x" => 1}}) activity = Activity.get_by_id(activity.id) @@ -73,6 +73,50 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do ] end + test "doesn't show reactions from muted and blocked users" do + user = insert(:user) + other_user = insert(:user) + third_user = insert(:user) + + {:ok, activity} = CommonAPI.post(user, %{status: "dae cofe??"}) + + {:ok, _} = User.mute(user, other_user) + {:ok, _} = User.block(other_user, third_user) + + {:ok, _} = CommonAPI.react_with_emoji(activity.id, other_user, "☕") + + activity = Repo.get(Activity, activity.id) + status = StatusView.render("show.json", activity: activity) + + assert status[:pleroma][:emoji_reactions] == [ + %{name: "☕", count: 1, me: false} + ] + + status = StatusView.render("show.json", activity: activity, for: user) + + assert status[:pleroma][:emoji_reactions] == [] + + {:ok, _} = CommonAPI.react_with_emoji(activity.id, third_user, "☕") + + status = StatusView.render("show.json", activity: activity) + + assert status[:pleroma][:emoji_reactions] == [ + %{name: "☕", count: 2, me: false} + ] + + status = StatusView.render("show.json", activity: activity, for: user) + + assert status[:pleroma][:emoji_reactions] == [ + %{name: "☕", count: 1, me: false} + ] + + status = StatusView.render("show.json", activity: activity, for: other_user) + + assert status[:pleroma][:emoji_reactions] == [ + %{name: "☕", count: 1, me: true} + ] + end + test "loads and returns the direct conversation id when given the `with_direct_conversation_id` option" do user = insert(:user) @@ -116,7 +160,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do {:ok, activity} = CommonAPI.post(user, %{status: "Hey @shp!", visibility: "direct"}) Repo.delete(user) - Cachex.clear(:user_cache) + User.invalidate_cache(user) finger_url = "https://localhost/.well-known/webfinger?resource=acct:#{user.nickname}@localhost" @@ -150,7 +194,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do |> Ecto.Changeset.change(%{ap_id: "#{user.ap_id}/extension/#{user.nickname}"}) |> Repo.update() - Cachex.clear(:user_cache) + User.invalidate_cache(user) result = StatusView.render("show.json", activity: activity) @@ -160,7 +204,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do test "a note with null content" do note = insert(:note_activity) - note_object = Object.normalize(note) + note_object = Object.normalize(note, fetch: false) data = note_object.data @@ -179,7 +223,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do test "a note activity" do note = insert(:note_activity) - object_data = Object.normalize(note).data + object_data = Object.normalize(note, fetch: false).data user = User.get_cached_by_ap_id(note.data["actor"]) convo_id = Utils.context_to_conversation_id(object_data["context"]) @@ -218,14 +262,11 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do mentions: [], tags: [ %{ - name: "#{object_data["tag"]}", - url: "/tag/#{object_data["tag"]}" + name: "#{hd(object_data["tag"])}", + url: "http://localhost:4001/tag/#{hd(object_data["tag"])}" } ], - application: %{ - name: "Web", - website: nil - }, + application: nil, language: nil, emojis: [ %{ @@ -245,7 +286,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do direct_conversation_id: nil, thread_muted: false, emoji_reactions: [], - parent_visible: false + parent_visible: false, + pinned_at: nil } } @@ -417,9 +459,12 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do "url" => [ %{ "mediaType" => "image/png", - "href" => "someurl" + "href" => "someurl", + "width" => 200, + "height" => 100 } ], + "blurhash" => "UJJ8X[xYW,%Jtq%NNFbXB5j]IVM|9GV=WHRn", "uuid" => 6 } @@ -431,7 +476,9 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do preview_url: "someurl", text_url: "someurl", description: nil, - pleroma: %{mime_type: "image/png"} + pleroma: %{mime_type: "image/png"}, + meta: %{original: %{width: 200, height: 100, aspect: 2}}, + blurhash: "UJJ8X[xYW,%Jtq%NNFbXB5j]IVM|9GV=WHRn" } api_spec = Pleroma.Web.ApiSpec.spec() @@ -539,9 +586,9 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do ] assert StatusView.build_tags(object_tags) == [ - %{name: "fediverse", url: "/tag/fediverse"}, - %{name: "mastodon", url: "/tag/mastodon"}, - %{name: "nextcloud", url: "/tag/nextcloud"} + %{name: "fediverse", url: "http://localhost:4001/tag/fediverse"}, + %{name: "mastodon", url: "http://localhost:4001/tag/mastodon"}, + %{name: "nextcloud", url: "http://localhost:4001/tag/nextcloud"} ] end end diff --git a/test/web/mastodon_api/views/subscription_view_test.exs b/test/pleroma/web/mastodon_api/views/subscription_view_test.exs index 981524c0e..04b440389 100644 --- a/test/web/mastodon_api/views/subscription_view_test.exs +++ b/test/pleroma/web/mastodon_api/views/subscription_view_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.MastodonAPI.SubscriptionViewTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true import Pleroma.Factory alias Pleroma.Web.MastodonAPI.SubscriptionView, as: View alias Pleroma.Web.Push diff --git a/test/pleroma/web/mastodon_api/views/suggestion_view_test.exs b/test/pleroma/web/mastodon_api/views/suggestion_view_test.exs new file mode 100644 index 000000000..5aae36ce9 --- /dev/null +++ b/test/pleroma/web/mastodon_api/views/suggestion_view_test.exs @@ -0,0 +1,34 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.SuggestionViewTest do + use Pleroma.DataCase, async: true + import Pleroma.Factory + alias Pleroma.Web.MastodonAPI.SuggestionView, as: View + + test "show.json" do + user = insert(:user, is_suggested: true) + json = View.render("show.json", %{user: user, source: :staff, skip_visibility_check: true}) + + assert json.source == :staff + assert json.account.id == user.id + end + + test "index.json" do + user1 = insert(:user, is_suggested: true) + user2 = insert(:user, is_suggested: true) + user3 = insert(:user, is_suggested: true) + + [suggestion1, suggestion2, suggestion3] = + View.render("index.json", %{ + users: [user1, user2, user3], + source: :staff, + skip_visibility_check: true + }) + + assert suggestion1.source == :staff + assert suggestion2.account.id == user2.id + assert suggestion3.account.url == user3.ap_id + end +end diff --git a/test/web/matrix_controller_test.exs b/test/pleroma/web/matrix_controller_test.exs index c8273641b..c8273641b 100644 --- a/test/web/matrix_controller_test.exs +++ b/test/pleroma/web/matrix_controller_test.exs diff --git a/test/web/media_proxy/invalidations/http_test.exs b/test/pleroma/web/media_proxy/invalidation/http_test.exs index a1bef5237..a15103c89 100644 --- a/test/web/media_proxy/invalidations/http_test.exs +++ b/test/pleroma/web/media_proxy/invalidation/http_test.exs @@ -1,3 +1,7 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + defmodule Pleroma.Web.MediaProxy.Invalidation.HttpTest do use ExUnit.Case alias Pleroma.Web.MediaProxy.Invalidation @@ -5,10 +9,6 @@ defmodule Pleroma.Web.MediaProxy.Invalidation.HttpTest do import ExUnit.CaptureLog import Tesla.Mock - setup do - on_exit(fn -> Cachex.clear(:banned_urls_cache) end) - end - test "logs hasn't error message when request is valid" do mock(fn %{method: :purge, url: "http://example.com/media/example.jpg"} -> diff --git a/test/pleroma/web/media_proxy/invalidation/script_test.exs b/test/pleroma/web/media_proxy/invalidation/script_test.exs new file mode 100644 index 000000000..e9629b72b --- /dev/null +++ b/test/pleroma/web/media_proxy/invalidation/script_test.exs @@ -0,0 +1,52 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MediaProxy.Invalidation.ScriptTest do + use ExUnit.Case, async: true + alias Pleroma.Web.MediaProxy.Invalidation + + import ExUnit.CaptureLog + + test "it logs error when script is not found" do + assert capture_log(fn -> + assert Invalidation.Script.purge( + ["http://example.com/media/example.jpg"], + script_path: "./example" + ) == {:error, "%ErlangError{original: :enoent}"} + end) =~ "Error while cache purge: %ErlangError{original: :enoent}" + + capture_log(fn -> + assert Invalidation.Script.purge( + ["http://example.com/media/example.jpg"], + [] + ) == {:error, "\"not found script path\""} + end) + end + + describe "url formatting" do + setup do + urls = [ + "https://bikeshed.party/media/foo.png", + "http://safe.millennial.space/proxy/wheeeee.gif", + "https://lain.com/proxy/mediafile.mp4?foo&bar=true", + "http://localhost:4000/media/upload.jpeg" + ] + + [urls: urls] + end + + test "with invalid formatter", %{urls: urls} do + assert urls == Invalidation.Script.maybe_format_urls(urls, nil) + end + + test "with :htcacheclean formatter", %{urls: urls} do + assert [ + "https://bikeshed.party:443/media/foo.png?", + "http://safe.millennial.space:80/proxy/wheeeee.gif?", + "https://lain.com:443/proxy/mediafile.mp4?foo&bar=true", + "http://localhost:4000/media/upload.jpeg?" + ] == Invalidation.Script.maybe_format_urls(urls, :htcacheclean) + end + end +end diff --git a/test/web/media_proxy/invalidation_test.exs b/test/pleroma/web/media_proxy/invalidation_test.exs index 926ae74ca..c77b8c94a 100644 --- a/test/web/media_proxy/invalidation_test.exs +++ b/test/pleroma/web/media_proxy/invalidation_test.exs @@ -1,8 +1,10 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + defmodule Pleroma.Web.MediaProxy.InvalidationTest do - use ExUnit.Case - use Pleroma.Tests.Helpers + use Pleroma.DataCase - alias Pleroma.Config alias Pleroma.Web.MediaProxy.Invalidation import ExUnit.CaptureLog @@ -11,17 +13,13 @@ defmodule Pleroma.Web.MediaProxy.InvalidationTest do setup do: clear_config([:media_proxy]) - setup do - on_exit(fn -> Cachex.clear(:banned_urls_cache) end) - end - describe "Invalidation.Http" do test "perform request to clear cache" do - Config.put([:media_proxy, :enabled], false) - Config.put([:media_proxy, :invalidation, :enabled], true) - Config.put([:media_proxy, :invalidation, :provider], Invalidation.Http) + clear_config([:media_proxy, :enabled], false) + clear_config([:media_proxy, :invalidation, :enabled], true) + clear_config([:media_proxy, :invalidation, :provider], Invalidation.Http) - Config.put([Invalidation.Http], method: :purge, headers: [{"x-refresh", 1}]) + clear_config([Invalidation.Http], method: :purge, headers: [{"x-refresh", 1}]) image_url = "http://example.com/media/example.jpg" Pleroma.Web.MediaProxy.put_in_banned_urls(image_url) @@ -44,10 +42,10 @@ defmodule Pleroma.Web.MediaProxy.InvalidationTest do describe "Invalidation.Script" do test "run script to clear cache" do - Config.put([:media_proxy, :enabled], false) - Config.put([:media_proxy, :invalidation, :enabled], true) - Config.put([:media_proxy, :invalidation, :provider], Invalidation.Script) - Config.put([Invalidation.Script], script_path: "purge-nginx") + clear_config([:media_proxy, :enabled], false) + clear_config([:media_proxy, :invalidation, :enabled], true) + clear_config([:media_proxy, :invalidation, :provider], Invalidation.Script) + clear_config([Invalidation.Script], script_path: "purge-nginx") image_url = "http://example.com/media/example.jpg" Pleroma.Web.MediaProxy.put_in_banned_urls(image_url) diff --git a/test/pleroma/web/media_proxy/media_proxy_controller_test.exs b/test/pleroma/web/media_proxy/media_proxy_controller_test.exs new file mode 100644 index 000000000..1f2e54194 --- /dev/null +++ b/test/pleroma/web/media_proxy/media_proxy_controller_test.exs @@ -0,0 +1,336 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MediaProxy.MediaProxyControllerTest do + use Pleroma.Web.ConnCase + + import Mock + + alias Pleroma.Web.MediaProxy + alias Plug.Conn + + describe "Media Proxy" do + setup do + clear_config([:media_proxy, :enabled], true) + clear_config([Pleroma.Web.Endpoint, :secret_key_base], "00000000000") + + [url: MediaProxy.encode_url("https://google.fn/test.png")] + end + + test "it returns 404 when disabled", %{conn: conn} do + clear_config([:media_proxy, :enabled], false) + + assert %Conn{ + status: 404, + resp_body: "Not Found" + } = get(conn, "/proxy/hhgfh/eeeee") + + assert %Conn{ + status: 404, + resp_body: "Not Found" + } = get(conn, "/proxy/hhgfh/eeee/fff") + end + + test "it returns 403 for invalid signature", %{conn: conn, url: url} do + clear_config([Pleroma.Web.Endpoint, :secret_key_base], "000") + %{path: path} = URI.parse(url) + + assert %Conn{ + status: 403, + resp_body: "Forbidden" + } = get(conn, path) + + assert %Conn{ + status: 403, + resp_body: "Forbidden" + } = get(conn, "/proxy/hhgfh/eeee") + + assert %Conn{ + status: 403, + resp_body: "Forbidden" + } = get(conn, "/proxy/hhgfh/eeee/fff") + end + + test "redirects to valid url when filename is invalidated", %{conn: conn, url: url} do + invalid_url = String.replace(url, "test.png", "test-file.png") + response = get(conn, invalid_url) + assert response.status == 302 + assert redirected_to(response) == url + end + + test "it performs ReverseProxy.call with valid signature", %{conn: conn, url: url} do + with_mock Pleroma.ReverseProxy, + call: fn _conn, _url, _opts -> %Conn{status: :success} end do + assert %Conn{status: :success} = get(conn, url) + end + end + + test "it returns 404 when url is in banned_urls cache", %{conn: conn, url: url} do + MediaProxy.put_in_banned_urls("https://google.fn/test.png") + + with_mock Pleroma.ReverseProxy, + call: fn _conn, _url, _opts -> %Conn{status: :success} end do + assert %Conn{status: 404, resp_body: "Not Found"} = get(conn, url) + end + end + end + + describe "Media Preview Proxy" do + def assert_dependencies_installed do + missing_dependencies = Pleroma.Helpers.MediaHelper.missing_dependencies() + + assert missing_dependencies == [], + "Error: missing dependencies (please refer to `docs/installation`): #{inspect(missing_dependencies)}" + end + + setup do + clear_config([:media_proxy, :enabled], true) + clear_config([:media_preview_proxy, :enabled], true) + clear_config([Pleroma.Web.Endpoint, :secret_key_base], "00000000000") + + original_url = "https://google.fn/test.png" + + [ + url: MediaProxy.encode_preview_url(original_url), + media_proxy_url: MediaProxy.encode_url(original_url) + ] + end + + test "returns 404 when media proxy is disabled", %{conn: conn} do + clear_config([:media_proxy, :enabled], false) + + assert %Conn{ + status: 404, + resp_body: "Not Found" + } = get(conn, "/proxy/preview/hhgfh/eeeee") + + assert %Conn{ + status: 404, + resp_body: "Not Found" + } = get(conn, "/proxy/preview/hhgfh/fff") + end + + test "returns 404 when disabled", %{conn: conn} do + clear_config([:media_preview_proxy, :enabled], false) + + assert %Conn{ + status: 404, + resp_body: "Not Found" + } = get(conn, "/proxy/preview/hhgfh/eeeee") + + assert %Conn{ + status: 404, + resp_body: "Not Found" + } = get(conn, "/proxy/preview/hhgfh/fff") + end + + test "it returns 403 for invalid signature", %{conn: conn, url: url} do + clear_config([Pleroma.Web.Endpoint, :secret_key_base], "000") + %{path: path} = URI.parse(url) + + assert %Conn{ + status: 403, + resp_body: "Forbidden" + } = get(conn, path) + + assert %Conn{ + status: 403, + resp_body: "Forbidden" + } = get(conn, "/proxy/preview/hhgfh/eeee") + + assert %Conn{ + status: 403, + resp_body: "Forbidden" + } = get(conn, "/proxy/preview/hhgfh/eeee/fff") + end + + test "redirects to valid url when filename is invalidated", %{conn: conn, url: url} do + invalid_url = String.replace(url, "test.png", "test-file.png") + response = get(conn, invalid_url) + assert response.status == 302 + assert redirected_to(response) == url + end + + test "responds with 424 Failed Dependency if HEAD request to media proxy fails", %{ + conn: conn, + url: url, + media_proxy_url: media_proxy_url + } do + Tesla.Mock.mock(fn + %{method: "head", url: ^media_proxy_url} -> + %Tesla.Env{status: 500, body: ""} + end) + + response = get(conn, url) + assert response.status == 424 + assert response.resp_body == "Can't fetch HTTP headers (HTTP 500)." + end + + test "redirects to media proxy URI on unsupported content type", %{ + conn: conn, + url: url, + media_proxy_url: media_proxy_url + } do + Tesla.Mock.mock(fn + %{method: "head", url: ^media_proxy_url} -> + %Tesla.Env{status: 200, body: "", headers: [{"content-type", "application/pdf"}]} + end) + + response = get(conn, url) + assert response.status == 302 + assert redirected_to(response) == media_proxy_url + end + + test "with `static=true` and GIF image preview requested, responds with JPEG image", %{ + conn: conn, + url: url, + media_proxy_url: media_proxy_url + } do + assert_dependencies_installed() + + # Setting a high :min_content_length to ensure this scenario is not affected by its logic + clear_config([:media_preview_proxy, :min_content_length], 1_000_000_000) + + Tesla.Mock.mock(fn + %{method: "head", url: ^media_proxy_url} -> + %Tesla.Env{ + status: 200, + body: "", + headers: [{"content-type", "image/gif"}, {"content-length", "1001718"}] + } + + %{method: :get, url: ^media_proxy_url} -> + %Tesla.Env{status: 200, body: File.read!("test/fixtures/image.gif")} + end) + + response = get(conn, url <> "?static=true") + + assert response.status == 200 + assert Conn.get_resp_header(response, "content-type") == ["image/jpeg"] + assert response.resp_body != "" + end + + test "with GIF image preview requested and no `static` param, redirects to media proxy URI", + %{ + conn: conn, + url: url, + media_proxy_url: media_proxy_url + } do + Tesla.Mock.mock(fn + %{method: "head", url: ^media_proxy_url} -> + %Tesla.Env{status: 200, body: "", headers: [{"content-type", "image/gif"}]} + end) + + response = get(conn, url) + + assert response.status == 302 + assert redirected_to(response) == media_proxy_url + end + + test "with `static` param and non-GIF image preview requested, " <> + "redirects to media preview proxy URI without `static` param", + %{ + conn: conn, + url: url, + media_proxy_url: media_proxy_url + } do + Tesla.Mock.mock(fn + %{method: "head", url: ^media_proxy_url} -> + %Tesla.Env{status: 200, body: "", headers: [{"content-type", "image/jpeg"}]} + end) + + response = get(conn, url <> "?static=true") + + assert response.status == 302 + assert redirected_to(response) == url + end + + test "with :min_content_length setting not matched by Content-Length header, " <> + "redirects to media proxy URI", + %{ + conn: conn, + url: url, + media_proxy_url: media_proxy_url + } do + clear_config([:media_preview_proxy, :min_content_length], 100_000) + + Tesla.Mock.mock(fn + %{method: "head", url: ^media_proxy_url} -> + %Tesla.Env{ + status: 200, + body: "", + headers: [{"content-type", "image/gif"}, {"content-length", "5000"}] + } + end) + + response = get(conn, url) + + assert response.status == 302 + assert redirected_to(response) == media_proxy_url + end + + test "thumbnails PNG images into PNG", %{ + conn: conn, + url: url, + media_proxy_url: media_proxy_url + } do + assert_dependencies_installed() + + Tesla.Mock.mock(fn + %{method: "head", url: ^media_proxy_url} -> + %Tesla.Env{status: 200, body: "", headers: [{"content-type", "image/png"}]} + + %{method: :get, url: ^media_proxy_url} -> + %Tesla.Env{status: 200, body: File.read!("test/fixtures/image.png")} + end) + + response = get(conn, url) + + assert response.status == 200 + assert Conn.get_resp_header(response, "content-type") == ["image/png"] + assert response.resp_body != "" + end + + test "thumbnails JPEG images into JPEG", %{ + conn: conn, + url: url, + media_proxy_url: media_proxy_url + } do + assert_dependencies_installed() + + Tesla.Mock.mock(fn + %{method: "head", url: ^media_proxy_url} -> + %Tesla.Env{status: 200, body: "", headers: [{"content-type", "image/jpeg"}]} + + %{method: :get, url: ^media_proxy_url} -> + %Tesla.Env{status: 200, body: File.read!("test/fixtures/image.jpg")} + end) + + response = get(conn, url) + + assert response.status == 200 + assert Conn.get_resp_header(response, "content-type") == ["image/jpeg"] + assert response.resp_body != "" + end + + test "redirects to media proxy URI in case of thumbnailing error", %{ + conn: conn, + url: url, + media_proxy_url: media_proxy_url + } do + Tesla.Mock.mock(fn + %{method: "head", url: ^media_proxy_url} -> + %Tesla.Env{status: 200, body: "", headers: [{"content-type", "image/jpeg"}]} + + %{method: :get, url: ^media_proxy_url} -> + %Tesla.Env{status: 200, body: "<html><body>error</body></html>"} + end) + + response = get(conn, url) + + assert response.status == 302 + assert redirected_to(response) == media_proxy_url + end + end +end diff --git a/test/web/media_proxy/media_proxy_test.exs b/test/pleroma/web/media_proxy_test.exs index 72885cfdd..d97874f3a 100644 --- a/test/web/media_proxy/media_proxy_test.exs +++ b/test/pleroma/web/media_proxy_test.exs @@ -1,14 +1,20 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.MediaProxyTest do use ExUnit.Case use Pleroma.Tests.Helpers + alias Pleroma.Config alias Pleroma.Web.Endpoint alias Pleroma.Web.MediaProxy + defp decode_result(encoded) do + {:ok, decoded} = MediaProxy.decode_url(encoded) + decoded + end + describe "when enabled" do setup do: clear_config([:media_proxy, :enabled], true) @@ -35,7 +41,7 @@ defmodule Pleroma.Web.MediaProxyTest do assert String.starts_with?( encoded, - Pleroma.Config.get([:media_proxy, :base_url], Pleroma.Web.base_url()) + Config.get([:media_proxy, :base_url], Pleroma.Web.Endpoint.url()) ) assert String.ends_with?(encoded, "/logo.png") @@ -75,6 +81,64 @@ defmodule Pleroma.Web.MediaProxyTest do assert MediaProxy.decode_url(sig, base64) == {:error, :invalid_signature} end + def test_verify_request_path_and_url(request_path, url, expected_result) do + assert MediaProxy.verify_request_path_and_url(request_path, url) == expected_result + + assert MediaProxy.verify_request_path_and_url( + %Plug.Conn{ + params: %{"filename" => Path.basename(request_path)}, + request_path: request_path + }, + url + ) == expected_result + end + + test "if first arg of `verify_request_path_and_url/2` is a Plug.Conn without \"filename\" " <> + "parameter, `verify_request_path_and_url/2` returns :ok " do + assert MediaProxy.verify_request_path_and_url( + %Plug.Conn{params: %{}, request_path: "/some/path"}, + "https://instance.com/file.jpg" + ) == :ok + + assert MediaProxy.verify_request_path_and_url( + %Plug.Conn{params: %{}, request_path: "/path/to/file.jpg"}, + "https://instance.com/file.jpg" + ) == :ok + end + + test "`verify_request_path_and_url/2` preserves the encoded or decoded path" do + test_verify_request_path_and_url( + "/Hello world.jpg", + "http://pleroma.social/Hello world.jpg", + :ok + ) + + test_verify_request_path_and_url( + "/Hello%20world.jpg", + "http://pleroma.social/Hello%20world.jpg", + :ok + ) + + test_verify_request_path_and_url( + "/my%2Flong%2Furl%2F2019%2F07%2FS.jpg", + "http://pleroma.social/my%2Flong%2Furl%2F2019%2F07%2FS.jpg", + :ok + ) + + test_verify_request_path_and_url( + # Note: `conn.request_path` returns encoded url + "/ANALYSE-DAI-_-LE-STABLECOIN-100-D%C3%89CENTRALIS%C3%89-BQ.jpg", + "https://mydomain.com/uploads/2019/07/ANALYSE-DAI-_-LE-STABLECOIN-100-DÉCENTRALISÉ-BQ.jpg", + :ok + ) + + test_verify_request_path_and_url( + "/my%2Flong%2Furl%2F2019%2F07%2FS", + "http://pleroma.social/my%2Flong%2Furl%2F2019%2F07%2FS.jpg", + {:wrong_filename, "my%2Flong%2Furl%2F2019%2F07%2FS.jpg"} + ) + end + test "uses the configured base_url" do base_url = "https://cache.pleroma.social" clear_config([:media_proxy, :base_url], base_url) @@ -124,12 +188,6 @@ defmodule Pleroma.Web.MediaProxyTest do end end - defp decode_result(encoded) do - [_, "proxy", sig, base64 | _] = URI.parse(encoded).path |> String.split("/") - {:ok, decoded} = MediaProxy.decode_url(sig, base64) - decoded - end - describe "whitelist" do setup do: clear_config([:media_proxy, :enabled], true) diff --git a/test/web/metadata/player_view_test.exs b/test/pleroma/web/metadata/player_view_test.exs index e6c990242..58caf6efd 100644 --- a/test/web/metadata/player_view_test.exs +++ b/test/pleroma/web/metadata/player_view_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.Metadata.PlayerViewTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true alias Pleroma.Web.Metadata.PlayerView diff --git a/test/web/metadata/feed_test.exs b/test/pleroma/web/metadata/providers/feed_test.exs index e6e5cc5ed..013d42498 100644 --- a/test/web/metadata/feed_test.exs +++ b/test/pleroma/web/metadata/providers/feed_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.Metadata.Providers.FeedTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true import Pleroma.Factory alias Pleroma.Web.Metadata.Providers.Feed diff --git a/test/pleroma/web/metadata/providers/open_graph_test.exs b/test/pleroma/web/metadata/providers/open_graph_test.exs new file mode 100644 index 000000000..28ca8839c --- /dev/null +++ b/test/pleroma/web/metadata/providers/open_graph_test.exs @@ -0,0 +1,190 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.Metadata.Providers.OpenGraphTest do + use Pleroma.DataCase + import Pleroma.Factory + alias Pleroma.Web.Metadata.Providers.OpenGraph + + setup do: clear_config([Pleroma.Web.Metadata, :unfurl_nsfw]) + + test "it renders all supported types of attachments and skips unknown types" do + user = insert(:user) + + note = + insert(:note, %{ + data: %{ + "actor" => user.ap_id, + "tag" => [], + "id" => "https://pleroma.gov/objects/whatever", + "content" => "pleroma in a nutshell", + "attachment" => [ + %{ + "url" => [ + %{ + "mediaType" => "image/png", + "href" => "https://pleroma.gov/tenshi.png", + "height" => 1024, + "width" => 1280 + } + ] + }, + %{ + "url" => [ + %{ + "mediaType" => "application/octet-stream", + "href" => "https://pleroma.gov/fqa/badapple.sfc" + } + ] + }, + %{ + "url" => [ + %{ + "mediaType" => "video/webm", + "href" => "https://pleroma.gov/about/juche.webm", + "height" => 600, + "width" => 800 + } + ] + }, + %{ + "url" => [ + %{ + "mediaType" => "audio/basic", + "href" => "http://www.gnu.org/music/free-software-song.au" + } + ] + } + ] + } + }) + + result = OpenGraph.build_tags(%{object: note, url: note.data["id"], user: user}) + + assert Enum.all?( + [ + {:meta, [property: "og:image", content: "https://pleroma.gov/tenshi.png"], []}, + {:meta, [property: "og:image:width", content: "1280"], []}, + {:meta, [property: "og:image:height", content: "1024"], []}, + {:meta, + [property: "og:audio", content: "http://www.gnu.org/music/free-software-song.au"], + []}, + {:meta, [property: "og:video", content: "https://pleroma.gov/about/juche.webm"], + []}, + {:meta, [property: "og:video:width", content: "800"], []}, + {:meta, [property: "og:video:height", content: "600"], []} + ], + fn element -> element in result end + ) + end + + test "it does not render attachments if post is nsfw" do + clear_config([Pleroma.Web.Metadata, :unfurl_nsfw], false) + user = insert(:user, avatar: %{"url" => [%{"href" => "https://pleroma.gov/tenshi.png"}]}) + + note = + insert(:note, %{ + data: %{ + "actor" => user.ap_id, + "id" => "https://pleroma.gov/objects/whatever", + "content" => "#cuteposting #nsfw #hambaga", + "tag" => ["cuteposting", "nsfw", "hambaga"], + "sensitive" => true, + "attachment" => [ + %{ + "url" => [ + %{"mediaType" => "image/png", "href" => "https://misskey.microsoft/corndog.png"} + ] + } + ] + } + }) + + result = OpenGraph.build_tags(%{object: note, url: note.data["id"], user: user}) + + assert {:meta, [property: "og:image", content: "https://pleroma.gov/tenshi.png"], []} in result + + refute {:meta, [property: "og:image", content: "https://misskey.microsoft/corndog.png"], []} in result + end + + test "video attachments have image thumbnail with WxH metadata with Preview Proxy enabled" do + clear_config([:media_proxy, :enabled], true) + clear_config([:media_preview_proxy, :enabled], true) + user = insert(:user) + + note = + insert(:note, %{ + data: %{ + "actor" => user.ap_id, + "id" => "https://pleroma.gov/objects/whatever", + "content" => "test video post", + "sensitive" => false, + "attachment" => [ + %{ + "url" => [ + %{ + "mediaType" => "video/webm", + "href" => "https://pleroma.gov/about/juche.webm", + "height" => 600, + "width" => 800 + } + ] + } + ] + } + }) + + result = OpenGraph.build_tags(%{object: note, url: note.data["id"], user: user}) + + assert {:meta, [property: "og:image:width", content: "800"], []} in result + assert {:meta, [property: "og:image:height", content: "600"], []} in result + + assert {:meta, + [ + property: "og:image", + content: + "http://localhost:4001/proxy/preview/LzAnlke-l5oZbNzWsrHfprX1rGw/aHR0cHM6Ly9wbGVyb21hLmdvdi9hYm91dC9qdWNoZS53ZWJt/juche.webm" + ], []} in result + end + + test "video attachments have no image thumbnail with Preview Proxy disabled" do + clear_config([:media_proxy, :enabled], true) + clear_config([:media_preview_proxy, :enabled], false) + user = insert(:user) + + note = + insert(:note, %{ + data: %{ + "actor" => user.ap_id, + "id" => "https://pleroma.gov/objects/whatever", + "content" => "test video post", + "sensitive" => false, + "attachment" => [ + %{ + "url" => [ + %{ + "mediaType" => "video/webm", + "href" => "https://pleroma.gov/about/juche.webm", + "height" => 600, + "width" => 800 + } + ] + } + ] + } + }) + + result = OpenGraph.build_tags(%{object: note, url: note.data["id"], user: user}) + + refute {:meta, [property: "og:image:width", content: "800"], []} in result + refute {:meta, [property: "og:image:height", content: "600"], []} in result + + refute {:meta, + [ + property: "og:image", + content: + "http://localhost:4001/proxy/preview/LzAnlke-l5oZbNzWsrHfprX1rGw/aHR0cHM6Ly9wbGVyb21hLmdvdi9hYm91dC9qdWNoZS53ZWJt/juche.webm" + ], []} in result + end +end diff --git a/test/web/metadata/rel_me_test.exs b/test/pleroma/web/metadata/providers/rel_me_test.exs index 2293d6e13..0db6e7d22 100644 --- a/test/web/metadata/rel_me_test.exs +++ b/test/pleroma/web/metadata/providers/rel_me_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.Metadata.Providers.RelMeTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true import Pleroma.Factory alias Pleroma.Web.Metadata.Providers.RelMe diff --git a/test/web/metadata/restrict_indexing_test.exs b/test/pleroma/web/metadata/providers/restrict_indexing_test.exs index aad0bac42..aa253e5e2 100644 --- a/test/web/metadata/restrict_indexing_test.exs +++ b/test/pleroma/web/metadata/providers/restrict_indexing_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.Metadata.Providers.RestrictIndexingTest do @@ -14,8 +14,14 @@ defmodule Pleroma.Web.Metadata.Providers.RestrictIndexingTest do test "for local user" do assert Pleroma.Web.Metadata.Providers.RestrictIndexing.build_tags(%{ - user: %Pleroma.User{local: true} + user: %Pleroma.User{local: true, is_discoverable: true} }) == [] end + + test "for local user when `is_discoverable` is false" do + assert Pleroma.Web.Metadata.Providers.RestrictIndexing.build_tags(%{ + user: %Pleroma.User{local: true, is_discoverable: false} + }) == [{:meta, [name: "robots", content: "noindex, noarchive"], []}] + end end end diff --git a/test/web/metadata/twitter_card_test.exs b/test/pleroma/web/metadata/providers/twitter_card_test.exs index 10931b5ba..1b8d27cda 100644 --- a/test/web/metadata/twitter_card_test.exs +++ b/test/pleroma/web/metadata/providers/twitter_card_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.Metadata.Providers.TwitterCardTest do @@ -9,6 +9,7 @@ defmodule Pleroma.Web.Metadata.Providers.TwitterCardTest do alias Pleroma.User alias Pleroma.Web.CommonAPI alias Pleroma.Web.Endpoint + alias Pleroma.Web.MediaProxy alias Pleroma.Web.Metadata.Providers.TwitterCard alias Pleroma.Web.Metadata.Utils alias Pleroma.Web.Router @@ -17,7 +18,7 @@ defmodule Pleroma.Web.Metadata.Providers.TwitterCardTest do test "it renders twitter card for user info" do user = insert(:user, name: "Jimmy Hendriks", bio: "born 19 March 1994") - avatar_url = Utils.attachment_url(User.avatar_url(user)) + avatar_url = MediaProxy.preview_url(User.avatar_url(user)) res = TwitterCard.build_tags(%{user: user}) assert res == [ @@ -46,7 +47,7 @@ defmodule Pleroma.Web.Metadata.Providers.TwitterCardTest do assert [ {:meta, [property: "twitter:title", content: Utils.user_name_string(user)], []}, - {:meta, [property: "twitter:description", content: "“pleroma in a nutshell”"], []}, + {:meta, [property: "twitter:description", content: "pleroma in a nutshell"], []}, {:meta, [property: "twitter:image", content: "http://localhost:4001/images/avi.png"], []}, {:meta, [property: "twitter:card", content: "summary"], []} @@ -54,7 +55,7 @@ defmodule Pleroma.Web.Metadata.Providers.TwitterCardTest do end test "it renders avatar not attachment if post is nsfw and unfurl_nsfw is disabled" do - Pleroma.Config.put([Pleroma.Web.Metadata, :unfurl_nsfw], false) + clear_config([Pleroma.Web.Metadata, :unfurl_nsfw], false) user = insert(:user, name: "Jimmy Hendriks", bio: "born 19 March 1994") {:ok, activity} = CommonAPI.post(user, %{status: "HI"}) @@ -91,7 +92,7 @@ defmodule Pleroma.Web.Metadata.Providers.TwitterCardTest do assert [ {:meta, [property: "twitter:title", content: Utils.user_name_string(user)], []}, - {:meta, [property: "twitter:description", content: "“pleroma in a nutshell”"], []}, + {:meta, [property: "twitter:description", content: "pleroma in a nutshell"], []}, {:meta, [property: "twitter:image", content: "http://localhost:4001/images/avi.png"], []}, {:meta, [property: "twitter:card", content: "summary"], []} @@ -111,7 +112,14 @@ defmodule Pleroma.Web.Metadata.Providers.TwitterCardTest do "content" => "pleroma in a nutshell", "attachment" => [ %{ - "url" => [%{"mediaType" => "image/png", "href" => "https://pleroma.gov/tenshi.png"}] + "url" => [ + %{ + "mediaType" => "image/png", + "href" => "https://pleroma.gov/tenshi.png", + "height" => 1024, + "width" => 1280 + } + ] }, %{ "url" => [ @@ -123,7 +131,12 @@ defmodule Pleroma.Web.Metadata.Providers.TwitterCardTest do }, %{ "url" => [ - %{"mediaType" => "video/webm", "href" => "https://pleroma.gov/about/juche.webm"} + %{ + "mediaType" => "video/webm", + "href" => "https://pleroma.gov/about/juche.webm", + "height" => 600, + "width" => 800 + } ] } ] @@ -134,17 +147,25 @@ defmodule Pleroma.Web.Metadata.Providers.TwitterCardTest do assert [ {:meta, [property: "twitter:title", content: Utils.user_name_string(user)], []}, - {:meta, [property: "twitter:description", content: "“pleroma in a nutshell”"], []}, + {:meta, [property: "twitter:description", content: "pleroma in a nutshell"], []}, {:meta, [property: "twitter:card", content: "summary_large_image"], []}, {:meta, [property: "twitter:player", content: "https://pleroma.gov/tenshi.png"], []}, + {:meta, [property: "twitter:player:width", content: "1280"], []}, + {:meta, [property: "twitter:player:height", content: "1024"], []}, {:meta, [property: "twitter:card", content: "player"], []}, {:meta, [ property: "twitter:player", content: Router.Helpers.o_status_url(Endpoint, :notice_player, activity.id) ], []}, - {:meta, [property: "twitter:player:width", content: "480"], []}, - {:meta, [property: "twitter:player:height", content: "480"], []} + {:meta, [property: "twitter:player:width", content: "800"], []}, + {:meta, [property: "twitter:player:height", content: "600"], []}, + {:meta, + [ + property: "twitter:player:stream", + content: "https://pleroma.gov/about/juche.webm" + ], []}, + {:meta, [property: "twitter:player:stream:content_type", content: "video/webm"], []} ] == result end end diff --git a/test/web/metadata/utils_test.exs b/test/pleroma/web/metadata/utils_test.exs index 8183256d8..074bd2e2f 100644 --- a/test/web/metadata/utils_test.exs +++ b/test/pleroma/web/metadata/utils_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.Metadata.UtilsTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true import Pleroma.Factory alias Pleroma.Web.Metadata.Utils diff --git a/test/web/mongooseim/mongoose_im_controller_test.exs b/test/pleroma/web/mongoose_im_controller_test.exs index 5176cde84..43c4dfa33 100644 --- a/test/web/mongooseim/mongoose_im_controller_test.exs +++ b/test/pleroma/web/mongoose_im_controller_test.exs @@ -1,15 +1,15 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.Web.MongooseIMController do - use Pleroma.Web.ConnCase +defmodule Pleroma.Web.MongooseIMControllerTest do + use Pleroma.Web.ConnCase, async: true import Pleroma.Factory test "/user_exists", %{conn: conn} do _user = insert(:user, nickname: "lain") _remote_user = insert(:user, nickname: "alice", local: false) - _deactivated_user = insert(:user, nickname: "konata", deactivated: true) + _deactivated_user = insert(:user, nickname: "konata", is_active: false) res = conn @@ -41,13 +41,13 @@ defmodule Pleroma.Web.MongooseIMController do end test "/check_password", %{conn: conn} do - user = insert(:user, password_hash: Pbkdf2.hash_pwd_salt("cool")) + user = insert(:user, password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt("cool")) _deactivated_user = insert(:user, nickname: "konata", - deactivated: true, - password_hash: Pbkdf2.hash_pwd_salt("cool") + is_active: false, + password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt("cool") ) res = diff --git a/test/web/node_info_test.exs b/test/pleroma/web/node_info_test.exs index 06b33607f..9deceb1b5 100644 --- a/test/web/node_info_test.exs +++ b/test/pleroma/web/node_info_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.NodeInfoTest do @@ -7,8 +7,6 @@ defmodule Pleroma.Web.NodeInfoTest do import Pleroma.Factory - alias Pleroma.Config - setup do: clear_config([:mrf_simple]) setup do: clear_config(:instance) @@ -93,7 +91,7 @@ defmodule Pleroma.Web.NodeInfoTest do assert "safe_dm_mentions" in response["metadata"]["features"] - Config.put([:instance, :safe_dm_mentions], false) + clear_config([:instance, :safe_dm_mentions], false) response = conn @@ -107,7 +105,7 @@ defmodule Pleroma.Web.NodeInfoTest do setup do: clear_config([:instance, :federating]) test "it shows if federation is enabled/disabled", %{conn: conn} do - Config.put([:instance, :federating], true) + clear_config([:instance, :federating], true) response = conn @@ -116,7 +114,7 @@ defmodule Pleroma.Web.NodeInfoTest do assert response["metadata"]["federation"]["enabled"] == true - Config.put([:instance, :federating], false) + clear_config([:instance, :federating], false) response = conn @@ -152,37 +150,127 @@ defmodule Pleroma.Web.NodeInfoTest do ) end - test "it shows MRF transparency data if enabled", %{conn: conn} do - clear_config([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.SimplePolicy]) - clear_config([:mrf, :transparency], true) + describe "Quarantined instances" do + setup do + clear_config([:mrf, :transparency], true) + quarantined_instances = [{"example.com", "reason to quarantine"}] + clear_config([:instance, :quarantined_instances], quarantined_instances) + end - simple_config = %{"reject" => ["example.com"]} - clear_config(:mrf_simple, simple_config) + test "shows quarantined instances data if enabled", %{conn: conn} do + expected_config = ["example.com"] - response = - conn - |> get("/nodeinfo/2.1.json") - |> json_response(:ok) + response = + conn + |> get("/nodeinfo/2.1.json") + |> json_response(:ok) + + assert response["metadata"]["federation"]["quarantined_instances"] == expected_config + end - assert response["metadata"]["federation"]["mrf_simple"] == simple_config + test "shows extra information in the quarantined_info field for relevant entries", %{ + conn: conn + } do + clear_config([:mrf, :transparency], true) + + expected_config = %{ + "quarantined_instances" => %{ + "example.com" => %{"reason" => "reason to quarantine"} + } + } + + response = + conn + |> get("/nodeinfo/2.1.json") + |> json_response(:ok) + + assert response["metadata"]["federation"]["quarantined_instances_info"] == expected_config + end end - test "it performs exclusions from MRF transparency data if configured", %{conn: conn} do - clear_config([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.SimplePolicy]) - clear_config([:mrf, :transparency], true) - clear_config([:mrf, :transparency_exclusions], ["other.site"]) + describe "MRF SimplePolicy" do + setup do + clear_config([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.SimplePolicy]) + clear_config([:mrf, :transparency], true) + end - simple_config = %{"reject" => ["example.com", "other.site"]} - clear_config(:mrf_simple, simple_config) + test "shows MRF transparency data if enabled", %{conn: conn} do + simple_config = %{"reject" => [{"example.com", ""}]} + clear_config(:mrf_simple, simple_config) - expected_config = %{"reject" => ["example.com"]} + expected_config = %{"reject" => ["example.com"]} - response = - conn - |> get("/nodeinfo/2.1.json") - |> json_response(:ok) + response = + conn + |> get("/nodeinfo/2.1.json") + |> json_response(:ok) + + assert response["metadata"]["federation"]["mrf_simple"] == expected_config + end + + test "performs exclusions from MRF transparency data if configured", %{conn: conn} do + clear_config([:mrf, :transparency_exclusions], [ + {"other.site", "We don't want them to know"} + ]) + + simple_config = %{"reject" => [{"example.com", ""}, {"other.site", ""}]} + clear_config(:mrf_simple, simple_config) + + expected_config = %{"reject" => ["example.com"]} + + response = + conn + |> get("/nodeinfo/2.1.json") + |> json_response(:ok) + + assert response["metadata"]["federation"]["mrf_simple"] == expected_config + assert response["metadata"]["federation"]["exclusions"] == true + end + + test "shows extra information in the mrf_simple_info field for relevant entries", %{ + conn: conn + } do + simple_config = %{ + media_removal: [{"no.media", "LEEWWWDD >//<"}], + media_nsfw: [], + federated_timeline_removal: [{"no.ftl", ""}], + report_removal: [], + reject: [ + {"example.instance", "Some reason"}, + {"uwu.owo", "awoo to much"}, + {"no.reason", ""} + ], + followers_only: [], + accept: [], + avatar_removal: [], + banner_removal: [], + reject_deletes: [ + {"peak.me", "I want to peak at what they don't want me to see, eheh"} + ] + } + + clear_config(:mrf_simple, simple_config) + + clear_config([:mrf, :transparency_exclusions], [ + {"peak.me", "I don't want them to know"} + ]) + + expected_config = %{ + "media_removal" => %{ + "no.media" => %{"reason" => "LEEWWWDD >//<"} + }, + "reject" => %{ + "example.instance" => %{"reason" => "Some reason"}, + "uwu.owo" => %{"reason" => "awoo to much"} + } + } - assert response["metadata"]["federation"]["mrf_simple"] == expected_config - assert response["metadata"]["federation"]["exclusions"] == true + response = + conn + |> get("/nodeinfo/2.1.json") + |> json_response(:ok) + + assert response["metadata"]["federation"]["mrf_simple_info"] == expected_config + end end end diff --git a/test/web/oauth/app_test.exs b/test/pleroma/web/o_auth/app_test.exs index 993a490e0..a5223b0a5 100644 --- a/test/web/oauth/app_test.exs +++ b/test/pleroma/web/o_auth/app_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.OAuth.AppTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true alias Pleroma.Web.OAuth.App import Pleroma.Factory @@ -41,4 +41,16 @@ defmodule Pleroma.Web.OAuth.AppTest do assert error.type == :unique end end + + test "get_user_apps/1" do + user = insert(:user) + + apps = [ + insert(:oauth_app, user_id: user.id), + insert(:oauth_app, user_id: user.id), + insert(:oauth_app, user_id: user.id) + ] + + assert App.get_user_apps(user) == apps + end end diff --git a/test/web/oauth/authorization_test.exs b/test/pleroma/web/o_auth/authorization_test.exs index d74b26cf8..fc1c04c4c 100644 --- a/test/web/oauth/authorization_test.exs +++ b/test/pleroma/web/o_auth/authorization_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.OAuth.AuthorizationTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true alias Pleroma.Web.OAuth.App alias Pleroma.Web.OAuth.Authorization import Pleroma.Factory diff --git a/test/web/oauth/ldap_authorization_test.exs b/test/pleroma/web/o_auth/ldap_authorization_test.exs index 63b1c0eb8..61b9ce6b7 100644 --- a/test/web/oauth/ldap_authorization_test.exs +++ b/test/pleroma/web/o_auth/ldap_authorization_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.OAuth.LDAPAuthorizationTest do @@ -18,7 +18,7 @@ defmodule Pleroma.Web.OAuth.LDAPAuthorizationTest do @tag @skip test "authorizes the existing user using LDAP credentials" do password = "testpassword" - user = insert(:user, password_hash: Pbkdf2.hash_pwd_salt(password)) + user = insert(:user, password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt(password)) app = insert(:oauth_app, scopes: ["read", "write"]) host = Pleroma.Config.get([:ldap, :host]) |> to_charlist @@ -101,7 +101,7 @@ defmodule Pleroma.Web.OAuth.LDAPAuthorizationTest do @tag @skip test "disallow authorization for wrong LDAP credentials" do password = "testpassword" - user = insert(:user, password_hash: Pbkdf2.hash_pwd_salt(password)) + user = insert(:user, password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt(password)) app = insert(:oauth_app, scopes: ["read", "write"]) host = Pleroma.Config.get([:ldap, :host]) |> to_charlist diff --git a/test/web/oauth/mfa_controller_test.exs b/test/pleroma/web/o_auth/mfa_controller_test.exs index 3c341facd..17bbde85b 100644 --- a/test/web/oauth/mfa_controller_test.exs +++ b/test/pleroma/web/o_auth/mfa_controller_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.OAuth.MFAControllerTest do - use Pleroma.Web.ConnCase + use Pleroma.Web.ConnCase, async: true import Pleroma.Factory alias Pleroma.MFA @@ -20,7 +20,7 @@ defmodule Pleroma.Web.OAuth.MFAControllerTest do insert(:user, multi_factor_authentication_settings: %MFA.Settings{ enabled: true, - backup_codes: [Pbkdf2.hash_pwd_salt("test-code")], + backup_codes: [Pleroma.Password.Pbkdf2.hash_pwd_salt("test-code")], totp: %MFA.Settings.TOTP{secret: otp_secret, confirmed: true} } ) @@ -171,7 +171,6 @@ defmodule Pleroma.Web.OAuth.MFAControllerTest do assert match?( %{ "access_token" => _, - "expires_in" => 600, "me" => ^ap_id, "refresh_token" => _, "scope" => "write", @@ -247,7 +246,7 @@ defmodule Pleroma.Web.OAuth.MFAControllerTest do hashed_codes = backup_codes - |> Enum.map(&Pbkdf2.hash_pwd_salt(&1)) + |> Enum.map(&Pleroma.Password.Pbkdf2.hash_pwd_salt(&1)) user = insert(:user, @@ -280,7 +279,6 @@ defmodule Pleroma.Web.OAuth.MFAControllerTest do assert match?( %{ "access_token" => _, - "expires_in" => 600, "me" => ^ap_id, "refresh_token" => _, "scope" => "write", diff --git a/test/web/oauth/oauth_controller_test.exs b/test/pleroma/web/o_auth/o_auth_controller_test.exs index 1200126b8..0fdd5b8e9 100644 --- a/test/web/oauth/oauth_controller_test.exs +++ b/test/pleroma/web/o_auth/o_auth_controller_test.exs @@ -1,11 +1,13 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.OAuth.OAuthControllerTest do use Pleroma.Web.ConnCase + import Pleroma.Factory + alias Pleroma.Helpers.AuthHelper alias Pleroma.MFA alias Pleroma.MFA.TOTP alias Pleroma.Repo @@ -77,11 +79,11 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do } ) - assert response = html_response(conn, 302) + assert html_response(conn, 302) redirect_query = URI.parse(redirected_to(conn)).query assert %{"state" => state_param} = URI.decode_query(redirect_query) - assert {:ok, state_components} = Poison.decode(state_param) + assert {:ok, state_components} = Jason.decode(state_param) expected_client_id = app.client_id expected_redirect_uri = app.redirect_uris @@ -115,11 +117,11 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do "oauth_token" => "G-5a3AAAAAAAwMH9AAABaektfSM", "oauth_verifier" => "QZl8vUqNvXMTKpdmUnGejJxuHG75WWWs", "provider" => "twitter", - "state" => Poison.encode!(state_params) + "state" => Jason.encode!(state_params) } ) - assert response = html_response(conn, 302) + assert html_response(conn, 302) assert redirected_to(conn) =~ ~r/#{redirect_uri}\?code=.+/ end @@ -147,7 +149,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do "oauth_token" => "G-5a3AAAAAAAwMH9AAABaektfSM", "oauth_verifier" => "QZl8vUqNvXMTKpdmUnGejJxuHG75WWWs", "provider" => "twitter", - "state" => Poison.encode!(state_params) + "state" => Jason.encode!(state_params) } ) @@ -178,11 +180,11 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do "oauth_token" => "G-5a3AAAAAAAwMH9AAABaektfSM", "oauth_verifier" => "QZl8vUqNvXMTKpdmUnGejJxuHG75WWWs", "provider" => "twitter", - "state" => Poison.encode!(state_params) + "state" => Jason.encode!(state_params) } ) - assert response = html_response(conn, 302) + assert html_response(conn, 302) assert redirected_to(conn) == app.redirect_uris assert get_flash(conn, :error) == "Failed to authenticate: (error description)." end @@ -238,7 +240,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do } ) - assert response = html_response(conn, 302) + assert html_response(conn, 302) assert redirected_to(conn) =~ ~r/#{redirect_uri}\?code=.+/ end @@ -268,7 +270,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do } ) - assert response = html_response(conn, 401) + assert html_response(conn, 401) end test "with invalid params, POST /oauth/register?op=register renders registration_details page", @@ -314,7 +316,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do app: app, conn: conn } do - user = insert(:user, password_hash: Pbkdf2.hash_pwd_salt("testpassword")) + user = insert(:user, password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt("testpassword")) registration = insert(:registration, user: nil) redirect_uri = OAuthController.default_redirect_uri(app) @@ -336,7 +338,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do } ) - assert response = html_response(conn, 302) + assert html_response(conn, 302) assert redirected_to(conn) =~ ~r/#{redirect_uri}\?code=.+/ end @@ -345,7 +347,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do app: app, conn: conn } do - user = insert(:user, password_hash: Pbkdf2.hash_pwd_salt("testpassword")) + user = insert(:user, password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt("testpassword")) registration = insert(:registration, user: nil) unlisted_redirect_uri = "http://cross-site-request.com" @@ -367,7 +369,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do } ) - assert response = html_response(conn, 401) + assert html_response(conn, 401) end test "with invalid params, POST /oauth/register?op=connect renders registration_details page", @@ -454,7 +456,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do conn = conn - |> put_session(:oauth_token, token.token) + |> AuthHelper.put_session_token(token.token) |> get( "/oauth/authorize", %{ @@ -478,7 +480,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do conn = conn - |> put_session(:oauth_token, token.token) + |> AuthHelper.put_session_token(token.token) |> get( "/oauth/authorize", %{ @@ -501,7 +503,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do conn = conn - |> put_session(:oauth_token, token.token) + |> AuthHelper.put_session_token(token.token) |> get( "/oauth/authorize", %{ @@ -527,7 +529,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do conn = conn - |> put_session(:oauth_token, token.token) + |> AuthHelper.put_session_token(token.token) |> get( "/oauth/authorize", %{ @@ -551,7 +553,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do conn = conn - |> put_session(:oauth_token, token.token) + |> AuthHelper.put_session_token(token.token) |> get( "/oauth/authorize", %{ @@ -609,6 +611,41 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do end end + test "authorize from cookie" do + user = insert(:user) + app = insert(:oauth_app) + oauth_token = insert(:oauth_token, user: user, app: app) + redirect_uri = OAuthController.default_redirect_uri(app) + + conn = + build_conn() + |> Plug.Session.call(Plug.Session.init(@session_opts)) + |> fetch_session() + |> AuthHelper.put_session_token(oauth_token.token) + |> post( + "/oauth/authorize", + %{ + "authorization" => %{ + "name" => user.nickname, + "client_id" => app.client_id, + "redirect_uri" => redirect_uri, + "scope" => app.scopes, + "state" => "statepassed" + } + } + ) + + target = redirected_to(conn) + assert target =~ redirect_uri + + query = URI.parse(target).query |> URI.query_decoder() |> Map.new() + + assert %{"state" => "statepassed", "code" => code} = query + auth = Repo.get_by(Authorization, token: code) + assert auth + assert auth.scopes == app.scopes + end + test "redirect to on two-factor auth page" do otp_secret = TOTP.generate_secret() @@ -753,7 +790,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do test "issues a token for `password` grant_type with valid credentials, with full permissions by default" do password = "testpassword" - user = insert(:user, password_hash: Pbkdf2.hash_pwd_salt(password)) + user = insert(:user, password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt(password)) app = insert(:oauth_app, scopes: ["read", "write"]) @@ -768,10 +805,12 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do "client_secret" => app.client_secret }) - assert %{"access_token" => token} = json_response(conn, 200) + assert %{"id" => id, "access_token" => access_token} = json_response(conn, 200) - token = Repo.get_by(Token, token: token) + token = Repo.get_by(Token, token: access_token) assert token + assert token.id == id + assert token.token == access_token assert token.scopes == app.scopes end @@ -781,7 +820,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do user = insert(:user, - password_hash: Pbkdf2.hash_pwd_salt(password), + password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt(password), multi_factor_authentication_settings: %MFA.Settings{ enabled: true, totp: %MFA.Settings.TOTP{secret: otp_secret, confirmed: true} @@ -886,12 +925,12 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do end test "rejects token exchange for valid credentials belonging to unconfirmed user and confirmation is required" do - Pleroma.Config.put([:instance, :account_activation_required], true) + clear_config([:instance, :account_activation_required], true) password = "testpassword" {:ok, user} = - insert(:user, password_hash: Pbkdf2.hash_pwd_salt(password)) - |> User.confirmation_changeset(need_confirmation: true) + insert(:user, password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt(password)) + |> User.confirmation_changeset(set_confirmation: false) |> User.update_and_set_cache() refute Pleroma.User.account_status(user) == :active @@ -918,8 +957,8 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do user = insert(:user, - password_hash: Pbkdf2.hash_pwd_salt(password), - deactivated: true + password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt(password), + is_active: false ) app = insert(:oauth_app) @@ -946,7 +985,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do user = insert(:user, - password_hash: Pbkdf2.hash_pwd_salt(password), + password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt(password), password_reset_pending: true ) @@ -970,13 +1009,13 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do end test "rejects token exchange for user with confirmation_pending set to true" do - Pleroma.Config.put([:instance, :account_activation_required], true) + clear_config([:instance, :account_activation_required], true) password = "testpassword" user = insert(:user, - password_hash: Pbkdf2.hash_pwd_salt(password), - confirmation_pending: true + password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt(password), + is_confirmed: false ) app = insert(:oauth_app, scopes: ["read", "write"]) @@ -1001,7 +1040,11 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do test "rejects token exchange for valid credentials belonging to an unapproved user" do password = "testpassword" - user = insert(:user, password_hash: Pbkdf2.hash_pwd_salt(password), approval_pending: true) + user = + insert(:user, + password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt(password), + is_approved: false + ) refute Pleroma.User.account_status(user) == :active @@ -1045,7 +1088,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do setup do: clear_config([:oauth2, :issue_new_refresh_token]) test "issues a new access token with keep fresh token" do - Pleroma.Config.put([:oauth2, :issue_new_refresh_token], true) + clear_config([:oauth2, :issue_new_refresh_token], true) user = insert(:user) app = insert(:oauth_app, scopes: ["read", "write"]) @@ -1068,7 +1111,6 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do %{ "scope" => "write", "token_type" => "Bearer", - "expires_in" => 600, "access_token" => _, "refresh_token" => _, "me" => ^ap_id @@ -1085,7 +1127,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do end test "issues a new access token with new fresh token" do - Pleroma.Config.put([:oauth2, :issue_new_refresh_token], false) + clear_config([:oauth2, :issue_new_refresh_token], false) user = insert(:user) app = insert(:oauth_app, scopes: ["read", "write"]) @@ -1108,7 +1150,6 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do %{ "scope" => "write", "token_type" => "Bearer", - "expires_in" => 600, "access_token" => _, "refresh_token" => _, "me" => ^ap_id @@ -1191,7 +1232,6 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do %{ "scope" => "write", "token_type" => "Bearer", - "expires_in" => 600, "access_token" => _, "refresh_token" => _, "me" => ^ap_id @@ -1219,8 +1259,43 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do end end - describe "POST /oauth/revoke - bad request" do - test "returns 500" do + describe "POST /oauth/revoke" do + test "when authenticated with request token, revokes it and clears it from session" do + oauth_token = insert(:oauth_token) + + conn = + build_conn() + |> Plug.Session.call(Plug.Session.init(@session_opts)) + |> fetch_session() + |> AuthHelper.put_session_token(oauth_token.token) + |> post("/oauth/revoke", %{"token" => oauth_token.token}) + + assert json_response(conn, 200) + + refute AuthHelper.get_session_token(conn) + assert Token.get_by_token(oauth_token.token) == {:error, :not_found} + end + + test "if request is authenticated with a different token, " <> + "revokes requested token but keeps session token" do + user = insert(:user) + oauth_token = insert(:oauth_token, user: user) + other_app_oauth_token = insert(:oauth_token, user: user) + + conn = + build_conn() + |> Plug.Session.call(Plug.Session.init(@session_opts)) + |> fetch_session() + |> AuthHelper.put_session_token(oauth_token.token) + |> post("/oauth/revoke", %{"token" => other_app_oauth_token.token}) + + assert json_response(conn, 200) + + assert AuthHelper.get_session_token(conn) == oauth_token.token + assert Token.get_by_token(other_app_oauth_token.token) == {:error, :not_found} + end + + test "returns 500 on bad request" do response = build_conn() |> post("/oauth/revoke", %{}) diff --git a/test/web/oauth/token/utils_test.exs b/test/pleroma/web/o_auth/token/utils_test.exs index a610d92f8..d2e7a0904 100644 --- a/test/web/oauth/token/utils_test.exs +++ b/test/pleroma/web/o_auth/token/utils_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.OAuth.Token.UtilsTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true alias Pleroma.Web.OAuth.Token.Utils import Pleroma.Factory diff --git a/test/web/oauth/token_test.exs b/test/pleroma/web/o_auth/token_test.exs index 40d71eb59..8c0858ebc 100644 --- a/test/web/oauth/token_test.exs +++ b/test/pleroma/web/o_auth/token_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.OAuth.TokenTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true alias Pleroma.Repo alias Pleroma.Web.OAuth.App alias Pleroma.Web.OAuth.Authorization @@ -69,17 +69,4 @@ defmodule Pleroma.Web.OAuth.TokenTest do assert tokens == 2 end - - test "deletes expired tokens" do - insert(:oauth_token, valid_until: Timex.shift(Timex.now(), days: -3)) - insert(:oauth_token, valid_until: Timex.shift(Timex.now(), days: -3)) - t3 = insert(:oauth_token) - t4 = insert(:oauth_token, valid_until: Timex.shift(Timex.now(), minutes: 10)) - {tokens, _} = Token.delete_expired_tokens() - assert tokens == 2 - available_tokens = Pleroma.Repo.all(Token) - - token_ids = available_tokens |> Enum.map(& &1.id) - assert token_ids == [t3.id, t4.id] - end end diff --git a/test/web/ostatus/ostatus_controller_test.exs b/test/pleroma/web/o_status/o_status_controller_test.exs index ee498f4b5..41aef98b1 100644 --- a/test/web/ostatus/ostatus_controller_test.exs +++ b/test/pleroma/web/o_status/o_status_controller_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.OStatus.OStatusControllerTest do @@ -7,7 +7,6 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do import Pleroma.Factory - alias Pleroma.Config alias Pleroma.Object alias Pleroma.User alias Pleroma.Web.ActivityPub.ActivityPub @@ -21,7 +20,7 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do :ok end - setup do: clear_config([:instance, :federating], true) + setup do: clear_config([:static_fe, :enabled], false) describe "Mastodon compatibility routes" do setup %{conn: conn} do @@ -73,7 +72,7 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do test "redirects to /notice/id for html format", %{conn: conn} do note_activity = insert(:note_activity) - object = Object.normalize(note_activity) + object = Object.normalize(note_activity, fetch: false) [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, object.data["id"])) url = "/objects/#{uuid}" @@ -83,7 +82,7 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do test "404s on private objects", %{conn: conn} do note_activity = insert(:direct_note_activity) - object = Object.normalize(note_activity) + object = Object.normalize(note_activity, fetch: false) [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, object.data["id"])) conn @@ -134,7 +133,7 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do conn: conn } do note_activity = insert(:note_activity) - expected_redirect_url = Object.normalize(note_activity).data["id"] + expected_redirect_url = Object.normalize(note_activity, fetch: false).data["id"] redirect_url = conn @@ -145,13 +144,19 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do assert redirect_url == expected_redirect_url end - test "returns a 404 on remote notice when json requested", %{conn: conn} do + test "redirects to a proper object URL when json requested and the object is remote", %{ + conn: conn + } do note_activity = insert(:note_activity, local: false) + expected_redirect_url = Object.normalize(note_activity, fetch: false).data["id"] - conn - |> put_req_header("accept", "application/activity+json") - |> get("/notice/#{note_activity.id}") - |> response(404) + redirect_url = + conn + |> put_req_header("accept", "application/activity+json") + |> get("/notice/#{note_activity.id}") + |> redirected_to() + + assert redirect_url == expected_redirect_url end test "500s when actor not found", %{conn: conn} do @@ -177,7 +182,7 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do |> response(200) assert resp =~ - "<meta content=\"#{Pleroma.Web.base_url()}/notice/#{note_activity.id}\" property=\"og:url\">" + "<meta content=\"#{Pleroma.Web.Endpoint.url()}/notice/#{note_activity.id}\" property=\"og:url\">" user = insert(:user) @@ -215,22 +220,23 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do assert response(conn, 404) end - test "it requires authentication if instance is NOT federating", %{ + test "does not require authentication on non-federating instances", %{ conn: conn } do - user = insert(:user) + clear_config([:instance, :federating], false) note_activity = insert(:note_activity) - conn = put_req_header(conn, "accept", "text/html") - - ensure_federating_or_authenticated(conn, "/notice/#{note_activity.id}", user) + conn + |> put_req_header("accept", "text/html") + |> get("/notice/#{note_activity.id}") + |> response(200) end end describe "GET /notice/:id/embed_player" do setup do note_activity = insert(:note_activity) - object = Pleroma.Object.normalize(note_activity) + object = Pleroma.Object.normalize(note_activity, fetch: false) object_data = Map.put(object.data, "attachment", [ @@ -287,7 +293,7 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do test "404s when attachment is empty", %{conn: conn} do note_activity = insert(:note_activity) - object = Pleroma.Object.normalize(note_activity) + object = Pleroma.Object.normalize(note_activity, fetch: false) object_data = Map.put(object.data, "attachment", []) object @@ -301,7 +307,7 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do test "404s when attachment isn't audio or video", %{conn: conn} do note_activity = insert(:note_activity) - object = Pleroma.Object.normalize(note_activity) + object = Pleroma.Object.normalize(note_activity, fetch: false) object_data = Map.put(object.data, "attachment", [ @@ -325,14 +331,66 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do |> response(404) end - test "it requires authentication if instance is NOT federating", %{ + test "does not require authentication on non-federating instances", %{ conn: conn, note_activity: note_activity } do + clear_config([:instance, :federating], false) + + conn + |> put_req_header("accept", "text/html") + |> get("/notice/#{note_activity.id}/embed_player") + |> response(200) + end + end + + describe "notice compatibility routes" do + test "Soapbox FE", %{conn: conn} do user = insert(:user) - conn = put_req_header(conn, "accept", "text/html") + note_activity = insert(:note_activity, user: user) + + resp = + conn + |> put_req_header("accept", "text/html") + |> get("/@#{user.nickname}/posts/#{note_activity.id}") + |> response(200) + + expected = + "<meta content=\"#{Endpoint.url()}/notice/#{note_activity.id}\" property=\"og:url\">" + + assert resp =~ expected + end + + test "Mastodon", %{conn: conn} do + user = insert(:user) + note_activity = insert(:note_activity, user: user) + + resp = + conn + |> put_req_header("accept", "text/html") + |> get("/@#{user.nickname}/#{note_activity.id}") + |> response(200) + + expected = + "<meta content=\"#{Endpoint.url()}/notice/#{note_activity.id}\" property=\"og:url\">" + + assert resp =~ expected + end + + test "Twitter", %{conn: conn} do + user = insert(:user) + note_activity = insert(:note_activity, user: user) + + resp = + conn + |> put_req_header("accept", "text/html") + |> get("/#{user.nickname}/status/#{note_activity.id}") + |> response(200) + + expected = + "<meta content=\"#{Endpoint.url()}/notice/#{note_activity.id}\" property=\"og:url\">" - ensure_federating_or_authenticated(conn, "/notice/#{note_activity.id}/embed_player", user) + assert resp =~ expected end end end diff --git a/test/web/pleroma_api/controllers/account_controller_test.exs b/test/pleroma/web/pleroma_api/controllers/account_controller_test.exs index 07909d48b..ad271c31b 100644 --- a/test/web/pleroma_api/controllers/account_controller_test.exs +++ b/test/pleroma/web/pleroma_api/controllers/account_controller_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do @@ -17,10 +17,10 @@ defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do setup do {:ok, user} = insert(:user) - |> User.confirmation_changeset(need_confirmation: true) + |> User.confirmation_changeset(set_confirmation: false) |> User.update_and_set_cache() - assert user.confirmation_pending + refute user.is_confirmed [user: user] end @@ -174,9 +174,7 @@ defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do response = conn |> get( - "/api/v1/pleroma/accounts/#{user.id}/favourites?since_id=#{third_activity.id}&max_id=#{ - seventh_activity.id - }" + "/api/v1/pleroma/accounts/#{user.id}/favourites?since_id=#{third_activity.id}&max_id=#{seventh_activity.id}" ) |> json_response_and_validate_schema(:ok) diff --git a/test/pleroma/web/pleroma_api/controllers/app_controller_test.exs b/test/pleroma/web/pleroma_api/controllers/app_controller_test.exs new file mode 100644 index 000000000..5e24e18a8 --- /dev/null +++ b/test/pleroma/web/pleroma_api/controllers/app_controller_test.exs @@ -0,0 +1,53 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.PleromaAPI.AppControllerTest do + use Pleroma.Web.ConnCase, async: true + + alias Pleroma.Web.OAuth.App + alias Pleroma.Web.Push + + import Pleroma.Factory + + test "apps", %{conn: conn} do + user = insert(:user) + app_attrs = build(:oauth_app) + + creation = + conn + |> put_req_header("content-type", "application/json") + |> assign(:user, user) + |> post("/api/v1/apps", %{ + client_name: app_attrs.client_name, + redirect_uris: app_attrs.redirect_uris + }) + + [app] = App.get_user_apps(user) + + expected = %{ + "name" => app.client_name, + "website" => app.website, + "client_id" => app.client_id, + "client_secret" => app.client_secret, + "id" => app.id |> to_string(), + "redirect_uri" => app.redirect_uris, + "vapid_key" => Push.vapid_config() |> Keyword.get(:public_key) + } + + assert expected == json_response_and_validate_schema(creation, 200) + + response = + conn + |> put_req_header("content-type", "application/json") + |> assign(:user, user) + |> assign(:token, insert(:oauth_token, user: user, scopes: ["read", "follow"])) + |> get("/api/v1/pleroma/apps") + |> json_response_and_validate_schema(200) + + [apps] = response + + assert length(response) == 1 + assert apps["client_id"] == app.client_id + end +end diff --git a/test/pleroma/web/pleroma_api/controllers/backup_controller_test.exs b/test/pleroma/web/pleroma_api/controllers/backup_controller_test.exs new file mode 100644 index 000000000..3ee660a05 --- /dev/null +++ b/test/pleroma/web/pleroma_api/controllers/backup_controller_test.exs @@ -0,0 +1,85 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.PleromaAPI.BackupControllerTest do + use Pleroma.Web.ConnCase + + alias Pleroma.User.Backup + alias Pleroma.Web.PleromaAPI.BackupView + + setup do + clear_config([Pleroma.Upload, :uploader]) + clear_config([Backup, :limit_days]) + oauth_access(["read:accounts"]) + end + + test "GET /api/v1/pleroma/backups", %{user: user, conn: conn} do + assert {:ok, %Oban.Job{args: %{"backup_id" => backup_id}}} = Backup.create(user) + + backup = Backup.get(backup_id) + + response = + conn + |> get("/api/v1/pleroma/backups") + |> json_response_and_validate_schema(:ok) + + assert [ + %{ + "content_type" => "application/zip", + "url" => url, + "file_size" => 0, + "processed" => false, + "inserted_at" => _ + } + ] = response + + assert url == BackupView.download_url(backup) + + Pleroma.Tests.ObanHelpers.perform_all() + + assert [ + %{ + "url" => ^url, + "processed" => true + } + ] = + conn + |> get("/api/v1/pleroma/backups") + |> json_response_and_validate_schema(:ok) + end + + test "POST /api/v1/pleroma/backups", %{user: _user, conn: conn} do + assert [ + %{ + "content_type" => "application/zip", + "url" => url, + "file_size" => 0, + "processed" => false, + "inserted_at" => _ + } + ] = + conn + |> post("/api/v1/pleroma/backups") + |> json_response_and_validate_schema(:ok) + + Pleroma.Tests.ObanHelpers.perform_all() + + assert [ + %{ + "url" => ^url, + "processed" => true + } + ] = + conn + |> get("/api/v1/pleroma/backups") + |> json_response_and_validate_schema(:ok) + + days = Pleroma.Config.get([Backup, :limit_days]) + + assert %{"error" => "Last export was less than #{days} days ago"} == + conn + |> post("/api/v1/pleroma/backups") + |> json_response_and_validate_schema(400) + end +end diff --git a/test/web/pleroma_api/controllers/chat_controller_test.exs b/test/pleroma/web/pleroma_api/controllers/chat_controller_test.exs index 7be5fe09c..99b0d43a7 100644 --- a/test/web/pleroma_api/controllers/chat_controller_test.exs +++ b/test/pleroma/web/pleroma_api/controllers/chat_controller_test.exs @@ -1,8 +1,8 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.PleromaAPI.ChatControllerTest do - use Pleroma.Web.ConnCase, async: true + use Pleroma.Web.ConnCase alias Pleroma.Chat alias Pleroma.Chat.MessageReference @@ -22,7 +22,7 @@ defmodule Pleroma.Web.PleromaAPI.ChatControllerTest do {:ok, create} = CommonAPI.post_chat_message(other_user, user, "sup") {:ok, _create} = CommonAPI.post_chat_message(other_user, user, "sup part 2") {:ok, chat} = Chat.get_or_create(user.id, other_user.ap_id) - object = Object.normalize(create, false) + object = Object.normalize(create, fetch: false) cm_ref = MessageReference.for_chat_and_object(chat, object) assert cm_ref.unread == true @@ -52,7 +52,7 @@ defmodule Pleroma.Web.PleromaAPI.ChatControllerTest do {:ok, create} = CommonAPI.post_chat_message(other_user, user, "sup") {:ok, _create} = CommonAPI.post_chat_message(other_user, user, "sup part 2") {:ok, chat} = Chat.get_or_create(user.id, other_user.ap_id) - object = Object.normalize(create, false) + object = Object.normalize(create, fetch: false) cm_ref = MessageReference.for_chat_and_object(chat, object) assert cm_ref.unread == true @@ -82,11 +82,13 @@ defmodule Pleroma.Web.PleromaAPI.ChatControllerTest do result = conn |> put_req_header("content-type", "application/json") + |> put_req_header("idempotency-key", "123") |> post("/api/v1/pleroma/chats/#{chat.id}/messages", %{"content" => "Hallo!!"}) |> json_response_and_validate_schema(200) assert result["content"] == "Hallo!!" assert result["chat_id"] == chat.id |> to_string() + assert result["idempotency_key"] == "123" end test "it fails if there is no content", %{conn: conn, user: user} do @@ -100,12 +102,12 @@ defmodule Pleroma.Web.PleromaAPI.ChatControllerTest do |> post("/api/v1/pleroma/chats/#{chat.id}/messages") |> json_response_and_validate_schema(400) - assert result + assert %{"error" => "no_content"} == result end test "it works with an attachment", %{conn: conn, user: user} do file = %Plug.Upload{ - content_type: "image/jpg", + content_type: "image/jpeg", path: Path.absname("test/fixtures/image.jpg"), filename: "an_image.jpg" } @@ -126,6 +128,23 @@ defmodule Pleroma.Web.PleromaAPI.ChatControllerTest do assert result["attachment"] end + + test "gets MRF reason when rejected", %{conn: conn, user: user} do + clear_config([:mrf_keyword, :reject], ["GNO"]) + clear_config([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.KeywordPolicy]) + + other_user = insert(:user) + + {:ok, chat} = Chat.get_or_create(user.id, other_user.ap_id) + + result = + conn + |> put_req_header("content-type", "application/json") + |> post("/api/v1/pleroma/chats/#{chat.id}/messages", %{"content" => "GNO/Linux"}) + |> json_response_and_validate_schema(422) + + assert %{"error" => "[KeywordPolicy] Matches with rejected keyword"} == result + end end describe "DELETE /api/v1/pleroma/chats/:id/messages/:message_id" do @@ -139,7 +158,7 @@ defmodule Pleroma.Web.PleromaAPI.ChatControllerTest do {:ok, other_message} = CommonAPI.post_chat_message(recipient, user, "nico nico ni") - object = Object.normalize(message, false) + object = Object.normalize(message, fetch: false) chat = Chat.get(user.id, recipient.ap_id) @@ -157,7 +176,7 @@ defmodule Pleroma.Web.PleromaAPI.ChatControllerTest do assert %{data: %{"type" => "Tombstone"}} = Object.get_by_id(object.id) # Deleting other people's messages just removes the reference - object = Object.normalize(other_message, false) + object = Object.normalize(other_message, fetch: false) cm_ref = MessageReference.for_chat_and_object(chat, object) result = @@ -184,17 +203,39 @@ defmodule Pleroma.Web.PleromaAPI.ChatControllerTest do chat = Chat.get(user.id, recipient.ap_id) - result = - conn - |> get("/api/v1/pleroma/chats/#{chat.id}/messages") - |> json_response_and_validate_schema(200) + response = get(conn, "/api/v1/pleroma/chats/#{chat.id}/messages") + result = json_response_and_validate_schema(response, 200) + + [next, prev] = get_resp_header(response, "link") |> hd() |> String.split(", ") + api_endpoint = "/api/v1/pleroma/chats/" + + assert String.match?( + next, + ~r(#{api_endpoint}.*/messages\?limit=\d+&max_id=.*; rel=\"next\"$) + ) + + assert String.match?( + prev, + ~r(#{api_endpoint}.*/messages\?limit=\d+&min_id=.*; rel=\"prev\"$) + ) assert length(result) == 20 - result = - conn - |> get("/api/v1/pleroma/chats/#{chat.id}/messages?max_id=#{List.last(result)["id"]}") - |> json_response_and_validate_schema(200) + response = + get(conn, "/api/v1/pleroma/chats/#{chat.id}/messages?max_id=#{List.last(result)["id"]}") + + result = json_response_and_validate_schema(response, 200) + [next, prev] = get_resp_header(response, "link") |> hd() |> String.split(", ") + + assert String.match?( + next, + ~r(#{api_endpoint}.*/messages\?limit=\d+&max_id=.*; rel=\"next\"$) + ) + + assert String.match?( + prev, + ~r(#{api_endpoint}.*/messages\?limit=\d+&max_id=.*&min_id=.*; rel=\"prev\"$) + ) assert length(result) == 10 end @@ -223,12 +264,11 @@ defmodule Pleroma.Web.PleromaAPI.ChatControllerTest do assert length(result) == 3 # Trying to get the chat of a different user - result = - conn - |> assign(:user, other_user) - |> get("/api/v1/pleroma/chats/#{chat.id}/messages") + other_user_chat = Chat.get(other_user.id, user.ap_id) - assert result |> json_response(404) + conn + |> get("/api/v1/pleroma/chats/#{other_user_chat.id}/messages") + |> json_response_and_validate_schema(404) end end @@ -264,110 +304,165 @@ defmodule Pleroma.Web.PleromaAPI.ChatControllerTest do end end - describe "GET /api/v1/pleroma/chats" do - setup do: oauth_access(["read:chats"]) - - test "it does not return chats with deleted users", %{conn: conn, user: user} do - recipient = insert(:user) - {:ok, _} = Chat.get_or_create(user.id, recipient.ap_id) - - Pleroma.Repo.delete(recipient) - User.invalidate_cache(recipient) - - result = - conn - |> get("/api/v1/pleroma/chats") - |> json_response_and_validate_schema(200) - - assert length(result) == 0 - end - - test "it does not return chats with users you blocked", %{conn: conn, user: user} do - recipient = insert(:user) - - {:ok, _} = Chat.get_or_create(user.id, recipient.ap_id) - - result = - conn - |> get("/api/v1/pleroma/chats") - |> json_response_and_validate_schema(200) - - assert length(result) == 1 + for tested_endpoint <- ["/api/v1/pleroma/chats", "/api/v2/pleroma/chats"] do + describe "GET #{tested_endpoint}" do + setup do: oauth_access(["read:chats"]) - User.block(user, recipient) - - result = - conn - |> get("/api/v1/pleroma/chats") - |> json_response_and_validate_schema(200) - - assert length(result) == 0 - end - - test "it returns all chats", %{conn: conn, user: user} do - Enum.each(1..30, fn _ -> + test "it does not return chats with deleted users", %{conn: conn, user: user} do recipient = insert(:user) {:ok, _} = Chat.get_or_create(user.id, recipient.ap_id) - end) - result = - conn - |> get("/api/v1/pleroma/chats") - |> json_response_and_validate_schema(200) + Pleroma.Repo.delete(recipient) + User.invalidate_cache(recipient) - assert length(result) == 30 - end + result = + conn + |> get(unquote(tested_endpoint)) + |> json_response_and_validate_schema(200) - test "it return a list of chats the current user is participating in, in descending order of updates", - %{conn: conn, user: user} do - har = insert(:user) - jafnhar = insert(:user) - tridi = insert(:user) + assert length(result) == 0 + end - {:ok, chat_1} = Chat.get_or_create(user.id, har.ap_id) - :timer.sleep(1000) - {:ok, _chat_2} = Chat.get_or_create(user.id, jafnhar.ap_id) - :timer.sleep(1000) - {:ok, chat_3} = Chat.get_or_create(user.id, tridi.ap_id) - :timer.sleep(1000) + test "it does not return chats with users you blocked", %{conn: conn, user: user} do + recipient = insert(:user) - # bump the second one - {:ok, chat_2} = Chat.bump_or_create(user.id, jafnhar.ap_id) + {:ok, _} = Chat.get_or_create(user.id, recipient.ap_id) - result = - conn - |> get("/api/v1/pleroma/chats") - |> json_response_and_validate_schema(200) + result = + conn + |> get(unquote(tested_endpoint)) + |> json_response_and_validate_schema(200) - ids = Enum.map(result, & &1["id"]) + assert length(result) == 1 - assert ids == [ - chat_2.id |> to_string(), - chat_3.id |> to_string(), - chat_1.id |> to_string() - ] - end + User.block(user, recipient) - test "it is not affected by :restrict_unauthenticated setting (issue #1973)", %{ - conn: conn, - user: user - } do - clear_config([:restrict_unauthenticated, :profiles, :local], true) - clear_config([:restrict_unauthenticated, :profiles, :remote], true) + result = + conn + |> get(unquote(tested_endpoint)) + |> json_response_and_validate_schema(200) - user2 = insert(:user) - user3 = insert(:user, local: false) + assert length(result) == 0 + end - {:ok, _chat_12} = Chat.get_or_create(user.id, user2.ap_id) - {:ok, _chat_13} = Chat.get_or_create(user.id, user3.ap_id) + test "it does not return chats with users you muted", %{conn: conn, user: user} do + recipient = insert(:user) - result = - conn - |> get("/api/v1/pleroma/chats") - |> json_response_and_validate_schema(200) + {:ok, _} = Chat.get_or_create(user.id, recipient.ap_id) - account_ids = Enum.map(result, &get_in(&1, ["account", "id"])) - assert Enum.sort(account_ids) == Enum.sort([user2.id, user3.id]) + result = + conn + |> get(unquote(tested_endpoint)) + |> json_response_and_validate_schema(200) + + assert length(result) == 1 + + User.mute(user, recipient) + + result = + conn + |> get(unquote(tested_endpoint)) + |> json_response_and_validate_schema(200) + + assert length(result) == 0 + + result = + conn + |> get("#{unquote(tested_endpoint)}?with_muted=true") + |> json_response_and_validate_schema(200) + + assert length(result) == 1 + end + + if tested_endpoint == "/api/v1/pleroma/chats" do + test "it returns all chats", %{conn: conn, user: user} do + Enum.each(1..30, fn _ -> + recipient = insert(:user) + {:ok, _} = Chat.get_or_create(user.id, recipient.ap_id) + end) + + result = + conn + |> get(unquote(tested_endpoint)) + |> json_response_and_validate_schema(200) + + assert length(result) == 30 + end + else + test "it paginates chats", %{conn: conn, user: user} do + Enum.each(1..30, fn _ -> + recipient = insert(:user) + {:ok, _} = Chat.get_or_create(user.id, recipient.ap_id) + end) + + result = + conn + |> get(unquote(tested_endpoint)) + |> json_response_and_validate_schema(200) + + assert length(result) == 20 + last_id = List.last(result)["id"] + + result = + conn + |> get(unquote(tested_endpoint) <> "?max_id=#{last_id}") + |> json_response_and_validate_schema(200) + + assert length(result) == 10 + end + end + + test "it return a list of chats the current user is participating in, in descending order of updates", + %{conn: conn, user: user} do + har = insert(:user) + jafnhar = insert(:user) + tridi = insert(:user) + + {:ok, chat_1} = Chat.get_or_create(user.id, har.ap_id) + {:ok, chat_1} = time_travel(chat_1, -3) + {:ok, chat_2} = Chat.get_or_create(user.id, jafnhar.ap_id) + {:ok, _chat_2} = time_travel(chat_2, -2) + {:ok, chat_3} = Chat.get_or_create(user.id, tridi.ap_id) + {:ok, chat_3} = time_travel(chat_3, -1) + + # bump the second one + {:ok, chat_2} = Chat.bump_or_create(user.id, jafnhar.ap_id) + + result = + conn + |> get(unquote(tested_endpoint)) + |> json_response_and_validate_schema(200) + + ids = Enum.map(result, & &1["id"]) + + assert ids == [ + chat_2.id |> to_string(), + chat_3.id |> to_string(), + chat_1.id |> to_string() + ] + end + + test "it is not affected by :restrict_unauthenticated setting (issue #1973)", %{ + conn: conn, + user: user + } do + clear_config([:restrict_unauthenticated, :profiles, :local], true) + clear_config([:restrict_unauthenticated, :profiles, :remote], true) + + user2 = insert(:user) + user3 = insert(:user, local: false) + + {:ok, _chat_12} = Chat.get_or_create(user.id, user2.ap_id) + {:ok, _chat_13} = Chat.get_or_create(user.id, user3.ap_id) + + result = + conn + |> get(unquote(tested_endpoint)) + |> json_response_and_validate_schema(200) + + account_ids = Enum.map(result, &get_in(&1, ["account", "id"])) + assert Enum.sort(account_ids) == Enum.sort([user2.id, user3.id]) + end end end end diff --git a/test/web/pleroma_api/controllers/conversation_controller_test.exs b/test/pleroma/web/pleroma_api/controllers/conversation_controller_test.exs index e6d0b3e37..54f2c5a58 100644 --- a/test/web/pleroma_api/controllers/conversation_controller_test.exs +++ b/test/pleroma/web/pleroma_api/controllers/conversation_controller_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.PleromaAPI.ConversationControllerTest do - use Pleroma.Web.ConnCase + use Pleroma.Web.ConnCase, async: true alias Pleroma.Conversation.Participation alias Pleroma.Repo @@ -104,7 +104,7 @@ defmodule Pleroma.Web.PleromaAPI.ConversationControllerTest do [participation] = Participation.for_user(user) participation = Repo.preload(participation, :recipients) - assert user in participation.recipients + assert refresh_record(user) in participation.recipients assert other_user in participation.recipients end @@ -121,7 +121,7 @@ defmodule Pleroma.Web.PleromaAPI.ConversationControllerTest do [participation2, participation1] = Participation.for_user(other_user) assert Participation.get(participation2.id).read == false assert Participation.get(participation1.id).read == false - assert User.get_cached_by_id(other_user.id).unread_conversation_count == 2 + assert Participation.unread_count(other_user) == 2 [%{"unread" => false}, %{"unread" => false}] = conn @@ -131,6 +131,6 @@ defmodule Pleroma.Web.PleromaAPI.ConversationControllerTest do [participation2, participation1] = Participation.for_user(other_user) assert Participation.get(participation2.id).read == true assert Participation.get(participation1.id).read == true - assert User.get_cached_by_id(other_user.id).unread_conversation_count == 0 + assert Participation.unread_count(other_user) == 0 end end diff --git a/test/pleroma/web/pleroma_api/controllers/emoji_file_controller_test.exs b/test/pleroma/web/pleroma_api/controllers/emoji_file_controller_test.exs new file mode 100644 index 000000000..547391249 --- /dev/null +++ b/test/pleroma/web/pleroma_api/controllers/emoji_file_controller_test.exs @@ -0,0 +1,381 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.PleromaAPI.EmojiFileControllerTest do + use Pleroma.Web.ConnCase + + import Mock + import Tesla.Mock + import Pleroma.Factory + + @emoji_path Path.join( + Pleroma.Config.get!([:instance, :static_dir]), + "emoji" + ) + setup do: clear_config([:instance, :public], true) + + setup do + admin = insert(:user, is_admin: true) + token = insert(:oauth_admin_token, user: admin) + + admin_conn = + build_conn() + |> assign(:user, admin) + |> assign(:token, token) + + Pleroma.Emoji.reload() + {:ok, %{admin_conn: admin_conn}} + end + + describe "POST/PATCH/DELETE /api/pleroma/emoji/packs/files?name=:name" do + setup do + pack_file = "#{@emoji_path}/test_pack/pack.json" + original_content = File.read!(pack_file) + + on_exit(fn -> + File.write!(pack_file, original_content) + end) + + :ok + end + + test "upload zip file with emojies", %{admin_conn: admin_conn} do + on_exit(fn -> + [ + "128px/a_trusted_friend-128.png", + "auroraborealis.png", + "1000px/baby_in_a_box.png", + "1000px/bear.png", + "128px/bear-128.png" + ] + |> Enum.each(fn path -> File.rm_rf!("#{@emoji_path}/test_pack/#{path}") end) + end) + + resp = + admin_conn + |> put_req_header("content-type", "multipart/form-data") + |> post("/api/pleroma/emoji/packs/files?name=test_pack", %{ + file: %Plug.Upload{ + content_type: "application/zip", + filename: "emojis.zip", + path: Path.absname("test/fixtures/emojis.zip") + } + }) + |> json_response_and_validate_schema(200) + + assert resp == %{ + "a_trusted_friend-128" => "128px/a_trusted_friend-128.png", + "auroraborealis" => "auroraborealis.png", + "baby_in_a_box" => "1000px/baby_in_a_box.png", + "bear" => "1000px/bear.png", + "bear-128" => "128px/bear-128.png", + "blank" => "blank.png", + "blank2" => "blank2.png" + } + + Enum.each(Map.values(resp), fn path -> + assert File.exists?("#{@emoji_path}/test_pack/#{path}") + end) + end + + test "create shortcode exists", %{admin_conn: admin_conn} do + assert admin_conn + |> put_req_header("content-type", "multipart/form-data") + |> post("/api/pleroma/emoji/packs/files?name=test_pack", %{ + shortcode: "blank", + filename: "dir/blank.png", + file: %Plug.Upload{ + filename: "blank.png", + path: "#{@emoji_path}/test_pack/blank.png" + } + }) + |> json_response_and_validate_schema(:conflict) == %{ + "error" => "An emoji with the \"blank\" shortcode already exists" + } + end + + test "don't rewrite old emoji", %{admin_conn: admin_conn} do + on_exit(fn -> File.rm_rf!("#{@emoji_path}/test_pack/dir/") end) + + assert admin_conn + |> put_req_header("content-type", "multipart/form-data") + |> post("/api/pleroma/emoji/packs/files?name=test_pack", %{ + shortcode: "blank3", + filename: "dir/blank.png", + file: %Plug.Upload{ + filename: "blank.png", + path: "#{@emoji_path}/test_pack/blank.png" + } + }) + |> json_response_and_validate_schema(200) == %{ + "blank" => "blank.png", + "blank2" => "blank2.png", + "blank3" => "dir/blank.png" + } + + assert File.exists?("#{@emoji_path}/test_pack/dir/blank.png") + + assert admin_conn + |> put_req_header("content-type", "multipart/form-data") + |> patch("/api/pleroma/emoji/packs/files?name=test_pack", %{ + shortcode: "blank", + new_shortcode: "blank2", + new_filename: "dir_2/blank_3.png" + }) + |> json_response_and_validate_schema(:conflict) == %{ + "error" => + "New shortcode \"blank2\" is already used. If you want to override emoji use 'force' option" + } + end + + test "rewrite old emoji with force option", %{admin_conn: admin_conn} do + on_exit(fn -> File.rm_rf!("#{@emoji_path}/test_pack/dir_2/") end) + + assert admin_conn + |> put_req_header("content-type", "multipart/form-data") + |> post("/api/pleroma/emoji/packs/files?name=test_pack", %{ + shortcode: "blank3", + filename: "dir/blank.png", + file: %Plug.Upload{ + filename: "blank.png", + path: "#{@emoji_path}/test_pack/blank.png" + } + }) + |> json_response_and_validate_schema(200) == %{ + "blank" => "blank.png", + "blank2" => "blank2.png", + "blank3" => "dir/blank.png" + } + + assert File.exists?("#{@emoji_path}/test_pack/dir/blank.png") + + assert admin_conn + |> put_req_header("content-type", "multipart/form-data") + |> patch("/api/pleroma/emoji/packs/files?name=test_pack", %{ + shortcode: "blank3", + new_shortcode: "blank4", + new_filename: "dir_2/blank_3.png", + force: true + }) + |> json_response_and_validate_schema(200) == %{ + "blank" => "blank.png", + "blank2" => "blank2.png", + "blank4" => "dir_2/blank_3.png" + } + + assert File.exists?("#{@emoji_path}/test_pack/dir_2/blank_3.png") + end + + test "with empty filename", %{admin_conn: admin_conn} do + assert admin_conn + |> put_req_header("content-type", "multipart/form-data") + |> post("/api/pleroma/emoji/packs/files?name=test_pack", %{ + shortcode: "blank2", + filename: "", + file: %Plug.Upload{ + filename: "blank.png", + path: "#{@emoji_path}/test_pack/blank.png" + } + }) + |> json_response_and_validate_schema(422) == %{ + "error" => "pack name, shortcode or filename cannot be empty" + } + end + + test "add file with not loaded pack", %{admin_conn: admin_conn} do + assert admin_conn + |> put_req_header("content-type", "multipart/form-data") + |> post("/api/pleroma/emoji/packs/files?name=not_loaded", %{ + shortcode: "blank3", + filename: "dir/blank.png", + file: %Plug.Upload{ + filename: "blank.png", + path: "#{@emoji_path}/test_pack/blank.png" + } + }) + |> json_response_and_validate_schema(:not_found) == %{ + "error" => "pack \"not_loaded\" is not found" + } + end + + test "returns an error on add file when file system is not writable", %{ + admin_conn: admin_conn + } do + pack_file = Path.join([@emoji_path, "not_loaded", "pack.json"]) + + with_mocks([ + {File, [:passthrough], [stat: fn ^pack_file -> {:error, :eacces} end]} + ]) do + assert admin_conn + |> put_req_header("content-type", "multipart/form-data") + |> post("/api/pleroma/emoji/packs/files?name=not_loaded", %{ + shortcode: "blank3", + filename: "dir/blank.png", + file: %Plug.Upload{ + filename: "blank.png", + path: "#{@emoji_path}/test_pack/blank.png" + } + }) + |> json_response_and_validate_schema(500) == %{ + "error" => + "Unexpected error occurred while adding file to pack. (POSIX error: Permission denied)" + } + end + end + + test "remove file with not loaded pack", %{admin_conn: admin_conn} do + assert admin_conn + |> delete("/api/pleroma/emoji/packs/files?name=not_loaded&shortcode=blank3") + |> json_response_and_validate_schema(:not_found) == %{ + "error" => "pack \"not_loaded\" is not found" + } + end + + test "remove file with empty shortcode", %{admin_conn: admin_conn} do + assert admin_conn + |> delete("/api/pleroma/emoji/packs/files?name=not_loaded&shortcode=") + |> json_response_and_validate_schema(:not_found) == %{ + "error" => "pack \"not_loaded\" is not found" + } + end + + test "update file with not loaded pack", %{admin_conn: admin_conn} do + assert admin_conn + |> put_req_header("content-type", "multipart/form-data") + |> patch("/api/pleroma/emoji/packs/files?name=not_loaded", %{ + shortcode: "blank4", + new_shortcode: "blank3", + new_filename: "dir_2/blank_3.png" + }) + |> json_response_and_validate_schema(:not_found) == %{ + "error" => "pack \"not_loaded\" is not found" + } + end + + test "new with shortcode as file with update", %{admin_conn: admin_conn} do + assert admin_conn + |> put_req_header("content-type", "multipart/form-data") + |> post("/api/pleroma/emoji/packs/files?name=test_pack", %{ + shortcode: "blank4", + filename: "dir/blank.png", + file: %Plug.Upload{ + filename: "blank.png", + path: "#{@emoji_path}/test_pack/blank.png" + } + }) + |> json_response_and_validate_schema(200) == %{ + "blank" => "blank.png", + "blank4" => "dir/blank.png", + "blank2" => "blank2.png" + } + + assert File.exists?("#{@emoji_path}/test_pack/dir/blank.png") + + assert admin_conn + |> put_req_header("content-type", "multipart/form-data") + |> patch("/api/pleroma/emoji/packs/files?name=test_pack", %{ + shortcode: "blank4", + new_shortcode: "blank3", + new_filename: "dir_2/blank_3.png" + }) + |> json_response_and_validate_schema(200) == %{ + "blank3" => "dir_2/blank_3.png", + "blank" => "blank.png", + "blank2" => "blank2.png" + } + + refute File.exists?("#{@emoji_path}/test_pack/dir/") + assert File.exists?("#{@emoji_path}/test_pack/dir_2/blank_3.png") + + assert admin_conn + |> delete("/api/pleroma/emoji/packs/files?name=test_pack&shortcode=blank3") + |> json_response_and_validate_schema(200) == %{ + "blank" => "blank.png", + "blank2" => "blank2.png" + } + + refute File.exists?("#{@emoji_path}/test_pack/dir_2/") + + on_exit(fn -> File.rm_rf!("#{@emoji_path}/test_pack/dir") end) + end + + test "new with shortcode from url", %{admin_conn: admin_conn} do + mock(fn + %{ + method: :get, + url: "https://test-blank/blank_url.png" + } -> + text(File.read!("#{@emoji_path}/test_pack/blank.png")) + end) + + assert admin_conn + |> put_req_header("content-type", "multipart/form-data") + |> post("/api/pleroma/emoji/packs/files?name=test_pack", %{ + shortcode: "blank_url", + file: "https://test-blank/blank_url.png" + }) + |> json_response_and_validate_schema(200) == %{ + "blank_url" => "blank_url.png", + "blank" => "blank.png", + "blank2" => "blank2.png" + } + + assert File.exists?("#{@emoji_path}/test_pack/blank_url.png") + + on_exit(fn -> File.rm_rf!("#{@emoji_path}/test_pack/blank_url.png") end) + end + + test "new without shortcode", %{admin_conn: admin_conn} do + on_exit(fn -> File.rm_rf!("#{@emoji_path}/test_pack/shortcode.png") end) + + assert admin_conn + |> put_req_header("content-type", "multipart/form-data") + |> post("/api/pleroma/emoji/packs/files?name=test_pack", %{ + file: %Plug.Upload{ + filename: "shortcode.png", + path: "#{Pleroma.Config.get([:instance, :static_dir])}/add/shortcode.png" + } + }) + |> json_response_and_validate_schema(200) == %{ + "shortcode" => "shortcode.png", + "blank" => "blank.png", + "blank2" => "blank2.png" + } + end + + test "remove non existing shortcode in pack.json", %{admin_conn: admin_conn} do + assert admin_conn + |> delete("/api/pleroma/emoji/packs/files?name=test_pack&shortcode=blank3") + |> json_response_and_validate_schema(:bad_request) == %{ + "error" => "Emoji \"blank3\" does not exist" + } + end + + test "update non existing emoji", %{admin_conn: admin_conn} do + assert admin_conn + |> put_req_header("content-type", "multipart/form-data") + |> patch("/api/pleroma/emoji/packs/files?name=test_pack", %{ + shortcode: "blank3", + new_shortcode: "blank4", + new_filename: "dir_2/blank_3.png" + }) + |> json_response_and_validate_schema(:bad_request) == %{ + "error" => "Emoji \"blank3\" does not exist" + } + end + + test "update with empty shortcode", %{admin_conn: admin_conn} do + assert %{ + "error" => "Missing field: new_shortcode." + } = + admin_conn + |> put_req_header("content-type", "multipart/form-data") + |> patch("/api/pleroma/emoji/packs/files?name=test_pack", %{ + shortcode: "blank", + new_filename: "dir_2/blank_3.png" + }) + |> json_response_and_validate_schema(:bad_request) + end + end +end diff --git a/test/web/pleroma_api/controllers/emoji_pack_controller_test.exs b/test/pleroma/web/pleroma_api/controllers/emoji_pack_controller_test.exs index e113bb15f..d1ba067b8 100644 --- a/test/web/pleroma_api/controllers/emoji_pack_controller_test.exs +++ b/test/pleroma/web/pleroma_api/controllers/emoji_pack_controller_test.exs @@ -1,10 +1,11 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do - use Pleroma.Web.ConnCase + use Pleroma.Web.ConnCase, async: false + import Mock import Tesla.Mock import Pleroma.Factory @@ -12,7 +13,6 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do Pleroma.Config.get!([:instance, :static_dir]), "emoji" ) - setup do: clear_config([:auth, :enforce_oauth_admin_scope_usage], false) setup do: clear_config([:instance, :public], true) @@ -30,18 +30,18 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do end test "GET /api/pleroma/emoji/packs when :public: false", %{conn: conn} do - Config.put([:instance, :public], false) + clear_config([:instance, :public], false) conn |> get("/api/pleroma/emoji/packs") |> json_response_and_validate_schema(200) end test "GET /api/pleroma/emoji/packs", %{conn: conn} do resp = conn |> get("/api/pleroma/emoji/packs") |> json_response_and_validate_schema(200) - assert resp["count"] == 3 + assert resp["count"] == 4 assert resp["packs"] |> Map.keys() - |> length() == 3 + |> length() == 4 shared = resp["packs"]["test_pack"] assert shared["files"] == %{"blank" => "blank.png", "blank2" => "blank2.png"} @@ -58,7 +58,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do |> get("/api/pleroma/emoji/packs?page_size=1") |> json_response_and_validate_schema(200) - assert resp["count"] == 3 + assert resp["count"] == 4 packs = Map.keys(resp["packs"]) @@ -71,7 +71,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do |> get("/api/pleroma/emoji/packs?page_size=1&page=2") |> json_response_and_validate_schema(200) - assert resp["count"] == 3 + assert resp["count"] == 4 packs = Map.keys(resp["packs"]) assert length(packs) == 1 [pack2] = packs @@ -81,18 +81,28 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do |> get("/api/pleroma/emoji/packs?page_size=1&page=3") |> json_response_and_validate_schema(200) - assert resp["count"] == 3 + assert resp["count"] == 4 packs = Map.keys(resp["packs"]) assert length(packs) == 1 [pack3] = packs - assert [pack1, pack2, pack3] |> Enum.uniq() |> length() == 3 + + resp = + conn + |> get("/api/pleroma/emoji/packs?page_size=1&page=4") + |> json_response_and_validate_schema(200) + + assert resp["count"] == 4 + packs = Map.keys(resp["packs"]) + assert length(packs) == 1 + [pack4] = packs + assert [pack1, pack2, pack3, pack4] |> Enum.uniq() |> length() == 4 end describe "GET /api/pleroma/emoji/packs/remote" do test "shareable instance", %{admin_conn: admin_conn, conn: conn} do resp = conn - |> get("/api/pleroma/emoji/packs") + |> get("/api/pleroma/emoji/packs?page=2&page_size=1") |> json_response_and_validate_schema(200) mock(fn @@ -102,12 +112,12 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do %{method: :get, url: "https://example.com/nodeinfo/2.1.json"} -> json(%{metadata: %{features: ["shareable_emoji_packs"]}}) - %{method: :get, url: "https://example.com/api/pleroma/emoji/packs"} -> + %{method: :get, url: "https://example.com/api/pleroma/emoji/packs?page=2&page_size=1"} -> json(resp) end) assert admin_conn - |> get("/api/pleroma/emoji/packs/remote?url=https://example.com") + |> get("/api/pleroma/emoji/packs/remote?url=https://example.com&page=2&page_size=1") |> json_response_and_validate_schema(200) == resp end @@ -128,11 +138,11 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do end end - describe "GET /api/pleroma/emoji/packs/:name/archive" do + describe "GET /api/pleroma/emoji/packs/archive?name=:name" do test "download shared pack", %{conn: conn} do resp = conn - |> get("/api/pleroma/emoji/packs/test_pack/archive") + |> get("/api/pleroma/emoji/packs/archive?name=test_pack") |> response(200) {:ok, arch} = :zip.unzip(resp, [:memory]) @@ -143,7 +153,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do test "non existing pack", %{conn: conn} do assert conn - |> get("/api/pleroma/emoji/packs/test_pack_for_import/archive") + |> get("/api/pleroma/emoji/packs/archive?name=test_pack_for_import") |> json_response_and_validate_schema(:not_found) == %{ "error" => "Pack test_pack_for_import does not exist" } @@ -151,7 +161,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do test "non downloadable pack", %{conn: conn} do assert conn - |> get("/api/pleroma/emoji/packs/test_pack_nonshared/archive") + |> get("/api/pleroma/emoji/packs/archive?name=test_pack_nonshared") |> json_response_and_validate_schema(:forbidden) == %{ "error" => "Pack test_pack_nonshared cannot be downloaded from this instance, either pack sharing was disabled for this pack or some files are missing" @@ -173,28 +183,28 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do %{ method: :get, - url: "https://example.com/api/pleroma/emoji/packs/test_pack" + url: "https://example.com/api/pleroma/emoji/pack?name=test_pack" } -> conn - |> get("/api/pleroma/emoji/packs/test_pack") + |> get("/api/pleroma/emoji/pack?name=test_pack") |> json_response_and_validate_schema(200) |> json() %{ method: :get, - url: "https://example.com/api/pleroma/emoji/packs/test_pack/archive" + url: "https://example.com/api/pleroma/emoji/packs/archive?name=test_pack" } -> conn - |> get("/api/pleroma/emoji/packs/test_pack/archive") + |> get("/api/pleroma/emoji/packs/archive?name=test_pack") |> response(200) |> text() %{ method: :get, - url: "https://example.com/api/pleroma/emoji/packs/test_pack_nonshared" + url: "https://example.com/api/pleroma/emoji/pack?name=test_pack_nonshared" } -> conn - |> get("/api/pleroma/emoji/packs/test_pack_nonshared") + |> get("/api/pleroma/emoji/pack?name=test_pack_nonshared") |> json_response_and_validate_schema(200) |> json() @@ -218,7 +228,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do assert File.exists?("#{@emoji_path}/test_pack2/blank.png") assert admin_conn - |> delete("/api/pleroma/emoji/packs/test_pack2") + |> delete("/api/pleroma/emoji/pack?name=test_pack2") |> json_response_and_validate_schema(200) == "ok" refute File.exists?("#{@emoji_path}/test_pack2") @@ -239,7 +249,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do assert File.exists?("#{@emoji_path}/test_pack_nonshared2/blank.png") assert admin_conn - |> delete("/api/pleroma/emoji/packs/test_pack_nonshared2") + |> delete("/api/pleroma/emoji/pack?name=test_pack_nonshared2") |> json_response_and_validate_schema(200) == "ok" refute File.exists?("#{@emoji_path}/test_pack_nonshared2") @@ -279,14 +289,14 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do %{ method: :get, - url: "https://example.com/api/pleroma/emoji/packs/pack_bad_sha" + url: "https://example.com/api/pleroma/emoji/pack?name=pack_bad_sha" } -> {:ok, pack} = Pleroma.Emoji.Pack.load_pack("pack_bad_sha") %Tesla.Env{status: 200, body: Jason.encode!(pack)} %{ method: :get, - url: "https://example.com/api/pleroma/emoji/packs/pack_bad_sha/archive" + url: "https://example.com/api/pleroma/emoji/packs/archive?name=pack_bad_sha" } -> %Tesla.Env{ status: 200, @@ -316,7 +326,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do %{ method: :get, - url: "https://example.com/api/pleroma/emoji/packs/test_pack" + url: "https://example.com/api/pleroma/emoji/pack?name=test_pack" } -> {:ok, pack} = Pleroma.Emoji.Pack.load_pack("test_pack") %Tesla.Env{status: 200, body: Jason.encode!(pack)} @@ -336,7 +346,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do end end - describe "PATCH /api/pleroma/emoji/packs/:name" do + describe "PATCH/update /api/pleroma/emoji/pack?name=:name" do setup do pack_file = "#{@emoji_path}/test_pack/pack.json" original_content = File.read!(pack_file) @@ -355,10 +365,26 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do }} end + test "returns error when file system not writable", %{admin_conn: conn} = ctx do + with_mocks([ + {File, [:passthrough], [stat: fn _ -> {:error, :eacces} end]} + ]) do + assert conn + |> put_req_header("content-type", "multipart/form-data") + |> patch( + "/api/pleroma/emoji/pack?name=test_pack", + %{"metadata" => ctx[:new_data]} + ) + |> json_response_and_validate_schema(500) + end + end + test "for a pack without a fallback source", ctx do assert ctx[:admin_conn] |> put_req_header("content-type", "multipart/form-data") - |> patch("/api/pleroma/emoji/packs/test_pack", %{"metadata" => ctx[:new_data]}) + |> patch("/api/pleroma/emoji/pack?name=test_pack", %{ + "metadata" => ctx[:new_data] + }) |> json_response_and_validate_schema(200) == ctx[:new_data] assert Jason.decode!(File.read!(ctx[:pack_file]))["pack"] == ctx[:new_data] @@ -384,7 +410,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do assert ctx[:admin_conn] |> put_req_header("content-type", "multipart/form-data") - |> patch("/api/pleroma/emoji/packs/test_pack", %{metadata: new_data}) + |> patch("/api/pleroma/emoji/pack?name=test_pack", %{metadata: new_data}) |> json_response_and_validate_schema(200) == new_data_with_sha assert Jason.decode!(File.read!(ctx[:pack_file]))["pack"] == new_data_with_sha @@ -404,304 +430,57 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do assert ctx[:admin_conn] |> put_req_header("content-type", "multipart/form-data") - |> patch("/api/pleroma/emoji/packs/test_pack", %{metadata: new_data}) + |> patch("/api/pleroma/emoji/pack?name=test_pack", %{metadata: new_data}) |> json_response_and_validate_schema(:bad_request) == %{ "error" => "The fallback archive does not have all files specified in pack.json" } end end - describe "POST/PATCH/DELETE /api/pleroma/emoji/packs/:name/files" do - setup do - pack_file = "#{@emoji_path}/test_pack/pack.json" - original_content = File.read!(pack_file) - - on_exit(fn -> - File.write!(pack_file, original_content) - end) - - :ok - end - - test "create shortcode exists", %{admin_conn: admin_conn} do - assert admin_conn - |> put_req_header("content-type", "multipart/form-data") - |> post("/api/pleroma/emoji/packs/test_pack/files", %{ - shortcode: "blank", - filename: "dir/blank.png", - file: %Plug.Upload{ - filename: "blank.png", - path: "#{@emoji_path}/test_pack/blank.png" - } - }) - |> json_response_and_validate_schema(:conflict) == %{ - "error" => "An emoji with the \"blank\" shortcode already exists" - } - end - - test "don't rewrite old emoji", %{admin_conn: admin_conn} do - on_exit(fn -> File.rm_rf!("#{@emoji_path}/test_pack/dir/") end) - - assert admin_conn - |> put_req_header("content-type", "multipart/form-data") - |> post("/api/pleroma/emoji/packs/test_pack/files", %{ - shortcode: "blank3", - filename: "dir/blank.png", - file: %Plug.Upload{ - filename: "blank.png", - path: "#{@emoji_path}/test_pack/blank.png" - } - }) - |> json_response_and_validate_schema(200) == %{ - "blank" => "blank.png", - "blank2" => "blank2.png", - "blank3" => "dir/blank.png" - } - - assert File.exists?("#{@emoji_path}/test_pack/dir/blank.png") - - assert admin_conn - |> put_req_header("content-type", "multipart/form-data") - |> patch("/api/pleroma/emoji/packs/test_pack/files", %{ - shortcode: "blank", - new_shortcode: "blank2", - new_filename: "dir_2/blank_3.png" - }) - |> json_response_and_validate_schema(:conflict) == %{ - "error" => - "New shortcode \"blank2\" is already used. If you want to override emoji use 'force' option" - } - end - - test "rewrite old emoji with force option", %{admin_conn: admin_conn} do - on_exit(fn -> File.rm_rf!("#{@emoji_path}/test_pack/dir_2/") end) - - assert admin_conn - |> put_req_header("content-type", "multipart/form-data") - |> post("/api/pleroma/emoji/packs/test_pack/files", %{ - shortcode: "blank3", - filename: "dir/blank.png", - file: %Plug.Upload{ - filename: "blank.png", - path: "#{@emoji_path}/test_pack/blank.png" - } - }) - |> json_response_and_validate_schema(200) == %{ - "blank" => "blank.png", - "blank2" => "blank2.png", - "blank3" => "dir/blank.png" - } - - assert File.exists?("#{@emoji_path}/test_pack/dir/blank.png") - - assert admin_conn - |> put_req_header("content-type", "multipart/form-data") - |> patch("/api/pleroma/emoji/packs/test_pack/files", %{ - shortcode: "blank3", - new_shortcode: "blank4", - new_filename: "dir_2/blank_3.png", - force: true - }) - |> json_response_and_validate_schema(200) == %{ - "blank" => "blank.png", - "blank2" => "blank2.png", - "blank4" => "dir_2/blank_3.png" - } - - assert File.exists?("#{@emoji_path}/test_pack/dir_2/blank_3.png") - end - - test "with empty filename", %{admin_conn: admin_conn} do - assert admin_conn - |> put_req_header("content-type", "multipart/form-data") - |> post("/api/pleroma/emoji/packs/test_pack/files", %{ - shortcode: "blank2", - filename: "", - file: %Plug.Upload{ - filename: "blank.png", - path: "#{@emoji_path}/test_pack/blank.png" - } - }) - |> json_response_and_validate_schema(:bad_request) == %{ - "error" => "pack name, shortcode or filename cannot be empty" - } - end - - test "add file with not loaded pack", %{admin_conn: admin_conn} do - assert admin_conn - |> put_req_header("content-type", "multipart/form-data") - |> post("/api/pleroma/emoji/packs/not_loaded/files", %{ - shortcode: "blank3", - filename: "dir/blank.png", - file: %Plug.Upload{ - filename: "blank.png", - path: "#{@emoji_path}/test_pack/blank.png" - } - }) - |> json_response_and_validate_schema(:bad_request) == %{ - "error" => "pack \"not_loaded\" is not found" - } - end - - test "remove file with not loaded pack", %{admin_conn: admin_conn} do - assert admin_conn - |> delete("/api/pleroma/emoji/packs/not_loaded/files?shortcode=blank3") - |> json_response_and_validate_schema(:bad_request) == %{ - "error" => "pack \"not_loaded\" is not found" - } - end - - test "remove file with empty shortcode", %{admin_conn: admin_conn} do - assert admin_conn - |> delete("/api/pleroma/emoji/packs/not_loaded/files?shortcode=") - |> json_response_and_validate_schema(:bad_request) == %{ - "error" => "pack name or shortcode cannot be empty" - } - end - - test "update file with not loaded pack", %{admin_conn: admin_conn} do - assert admin_conn - |> put_req_header("content-type", "multipart/form-data") - |> patch("/api/pleroma/emoji/packs/not_loaded/files", %{ - shortcode: "blank4", - new_shortcode: "blank3", - new_filename: "dir_2/blank_3.png" - }) - |> json_response_and_validate_schema(:bad_request) == %{ - "error" => "pack \"not_loaded\" is not found" - } - end - - test "new with shortcode as file with update", %{admin_conn: admin_conn} do - assert admin_conn - |> put_req_header("content-type", "multipart/form-data") - |> post("/api/pleroma/emoji/packs/test_pack/files", %{ - shortcode: "blank4", - filename: "dir/blank.png", - file: %Plug.Upload{ - filename: "blank.png", - path: "#{@emoji_path}/test_pack/blank.png" - } - }) - |> json_response_and_validate_schema(200) == %{ - "blank" => "blank.png", - "blank4" => "dir/blank.png", - "blank2" => "blank2.png" - } - - assert File.exists?("#{@emoji_path}/test_pack/dir/blank.png") - - assert admin_conn - |> put_req_header("content-type", "multipart/form-data") - |> patch("/api/pleroma/emoji/packs/test_pack/files", %{ - shortcode: "blank4", - new_shortcode: "blank3", - new_filename: "dir_2/blank_3.png" - }) - |> json_response_and_validate_schema(200) == %{ - "blank3" => "dir_2/blank_3.png", - "blank" => "blank.png", - "blank2" => "blank2.png" - } - - refute File.exists?("#{@emoji_path}/test_pack/dir/") - assert File.exists?("#{@emoji_path}/test_pack/dir_2/blank_3.png") - - assert admin_conn - |> delete("/api/pleroma/emoji/packs/test_pack/files?shortcode=blank3") - |> json_response_and_validate_schema(200) == %{ - "blank" => "blank.png", - "blank2" => "blank2.png" - } - - refute File.exists?("#{@emoji_path}/test_pack/dir_2/") - - on_exit(fn -> File.rm_rf!("#{@emoji_path}/test_pack/dir") end) - end - - test "new with shortcode from url", %{admin_conn: admin_conn} do - mock(fn - %{ - method: :get, - url: "https://test-blank/blank_url.png" - } -> - text(File.read!("#{@emoji_path}/test_pack/blank.png")) - end) - - assert admin_conn - |> put_req_header("content-type", "multipart/form-data") - |> post("/api/pleroma/emoji/packs/test_pack/files", %{ - shortcode: "blank_url", - file: "https://test-blank/blank_url.png" - }) - |> json_response_and_validate_schema(200) == %{ - "blank_url" => "blank_url.png", - "blank" => "blank.png", - "blank2" => "blank2.png" - } - - assert File.exists?("#{@emoji_path}/test_pack/blank_url.png") - - on_exit(fn -> File.rm_rf!("#{@emoji_path}/test_pack/blank_url.png") end) - end - - test "new without shortcode", %{admin_conn: admin_conn} do - on_exit(fn -> File.rm_rf!("#{@emoji_path}/test_pack/shortcode.png") end) - - assert admin_conn - |> put_req_header("content-type", "multipart/form-data") - |> post("/api/pleroma/emoji/packs/test_pack/files", %{ - file: %Plug.Upload{ - filename: "shortcode.png", - path: "#{Pleroma.Config.get([:instance, :static_dir])}/add/shortcode.png" + describe "POST/DELETE /api/pleroma/emoji/pack?name=:name" do + test "returns an error on creates pack when file system not writable", %{ + admin_conn: admin_conn + } do + path_pack = Path.join(@emoji_path, "test_pack") + + with_mocks([ + {File, [:passthrough], [mkdir: fn ^path_pack -> {:error, :eacces} end]} + ]) do + assert admin_conn + |> post("/api/pleroma/emoji/pack?name=test_pack") + |> json_response_and_validate_schema(500) == %{ + "error" => + "Unexpected error occurred while creating pack. (POSIX error: Permission denied)" } - }) - |> json_response_and_validate_schema(200) == %{ - "shortcode" => "shortcode.png", - "blank" => "blank.png", - "blank2" => "blank2.png" - } + end end - test "remove non existing shortcode in pack.json", %{admin_conn: admin_conn} do - assert admin_conn - |> delete("/api/pleroma/emoji/packs/test_pack/files?shortcode=blank3") - |> json_response_and_validate_schema(:bad_request) == %{ - "error" => "Emoji \"blank3\" does not exist" - } - end - - test "update non existing emoji", %{admin_conn: admin_conn} do - assert admin_conn - |> put_req_header("content-type", "multipart/form-data") - |> patch("/api/pleroma/emoji/packs/test_pack/files", %{ - shortcode: "blank3", - new_shortcode: "blank4", - new_filename: "dir_2/blank_3.png" - }) - |> json_response_and_validate_schema(:bad_request) == %{ - "error" => "Emoji \"blank3\" does not exist" - } - end - - test "update with empty shortcode", %{admin_conn: admin_conn} do - assert %{ - "error" => "Missing field: new_shortcode." - } = - admin_conn - |> put_req_header("content-type", "multipart/form-data") - |> patch("/api/pleroma/emoji/packs/test_pack/files", %{ - shortcode: "blank", - new_filename: "dir_2/blank_3.png" - }) - |> json_response_and_validate_schema(:bad_request) + test "returns an error on deletes pack when the file system is not writable", %{ + admin_conn: admin_conn + } do + path_pack = Path.join(@emoji_path, "test_emoji_pack") + + try do + {:ok, _pack} = Pleroma.Emoji.Pack.create("test_emoji_pack") + + with_mocks([ + {File, [:passthrough], [rm_rf: fn ^path_pack -> {:error, :eacces, path_pack} end]} + ]) do + assert admin_conn + |> delete("/api/pleroma/emoji/pack?name=test_emoji_pack") + |> json_response_and_validate_schema(500) == %{ + "error" => + "Couldn't delete the `test_emoji_pack` pack (POSIX error: Permission denied)" + } + end + after + File.rm_rf(path_pack) + end end - end - describe "POST/DELETE /api/pleroma/emoji/packs/:name" do test "creating and deleting a pack", %{admin_conn: admin_conn} do assert admin_conn - |> post("/api/pleroma/emoji/packs/test_created") + |> post("/api/pleroma/emoji/pack?name=test_created") |> json_response_and_validate_schema(200) == "ok" assert File.exists?("#{@emoji_path}/test_created/pack.json") @@ -713,7 +492,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do } assert admin_conn - |> delete("/api/pleroma/emoji/packs/test_created") + |> delete("/api/pleroma/emoji/pack?name=test_created") |> json_response_and_validate_schema(200) == "ok" refute File.exists?("#{@emoji_path}/test_created/pack.json") @@ -726,7 +505,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do File.write!(Path.join(path, "pack.json"), pack_file) assert admin_conn - |> post("/api/pleroma/emoji/packs/test_created") + |> post("/api/pleroma/emoji/pack?name=test_created") |> json_response_and_validate_schema(:conflict) == %{ "error" => "A pack named \"test_created\" already exists" } @@ -736,7 +515,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do test "with empty name", %{admin_conn: admin_conn} do assert admin_conn - |> post("/api/pleroma/emoji/packs/ ") + |> post("/api/pleroma/emoji/pack?name= ") |> json_response_and_validate_schema(:bad_request) == %{ "error" => "pack name cannot be empty" } @@ -745,7 +524,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do test "deleting nonexisting pack", %{admin_conn: admin_conn} do assert admin_conn - |> delete("/api/pleroma/emoji/packs/non_existing") + |> delete("/api/pleroma/emoji/pack?name=non_existing") |> json_response_and_validate_schema(:not_found) == %{ "error" => "Pack non_existing does not exist" } @@ -753,7 +532,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do test "deleting with empty name", %{admin_conn: admin_conn} do assert admin_conn - |> delete("/api/pleroma/emoji/packs/ ") + |> delete("/api/pleroma/emoji/pack?name= ") |> json_response_and_validate_schema(:bad_request) == %{ "error" => "pack name cannot be empty" } @@ -801,7 +580,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do } end - describe "GET /api/pleroma/emoji/packs/:name" do + describe "GET /api/pleroma/emoji/pack?name=:name" do test "shows pack.json", %{conn: conn} do assert %{ "files" => files, @@ -816,7 +595,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do } } = conn - |> get("/api/pleroma/emoji/packs/test_pack") + |> get("/api/pleroma/emoji/pack?name=test_pack") |> json_response_and_validate_schema(200) assert files == %{"blank" => "blank.png", "blank2" => "blank2.png"} @@ -826,7 +605,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do "files_count" => 2 } = conn - |> get("/api/pleroma/emoji/packs/test_pack?page_size=1") + |> get("/api/pleroma/emoji/pack?name=test_pack&page_size=1") |> json_response_and_validate_schema(200) assert files |> Map.keys() |> length() == 1 @@ -836,15 +615,33 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do "files_count" => 2 } = conn - |> get("/api/pleroma/emoji/packs/test_pack?page_size=1&page=2") + |> get("/api/pleroma/emoji/pack?name=test_pack&page_size=1&page=2") |> json_response_and_validate_schema(200) assert files |> Map.keys() |> length() == 1 end + test "for pack name with special chars", %{conn: conn} do + assert %{ + "files" => _files, + "files_count" => 1, + "pack" => %{ + "can-download" => true, + "description" => "Test description", + "download-sha256" => _, + "homepage" => "https://pleroma.social", + "license" => "Test license", + "share-files" => true + } + } = + conn + |> get("/api/pleroma/emoji/pack?name=blobs.gg") + |> json_response_and_validate_schema(200) + end + test "non existing pack", %{conn: conn} do assert conn - |> get("/api/pleroma/emoji/packs/non_existing") + |> get("/api/pleroma/emoji/pack?name=non_existing") |> json_response_and_validate_schema(:not_found) == %{ "error" => "Pack non_existing does not exist" } @@ -852,7 +649,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do test "error name", %{conn: conn} do assert conn - |> get("/api/pleroma/emoji/packs/ ") + |> get("/api/pleroma/emoji/pack?name= ") |> json_response_and_validate_schema(:bad_request) == %{ "error" => "pack name cannot be empty" } diff --git a/test/web/pleroma_api/controllers/emoji_reaction_controller_test.exs b/test/pleroma/web/pleroma_api/controllers/emoji_reaction_controller_test.exs index 3deab30d1..28483985c 100644 --- a/test/web/pleroma_api/controllers/emoji_reaction_controller_test.exs +++ b/test/pleroma/web/pleroma_api/controllers/emoji_reaction_controller_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.PleromaAPI.EmojiReactionControllerTest do @@ -106,6 +106,48 @@ defmodule Pleroma.Web.PleromaAPI.EmojiReactionControllerTest do result end + test "GET /api/v1/pleroma/statuses/:id/reactions?with_muted=true", %{conn: conn} do + user = insert(:user) + user2 = insert(:user) + user3 = insert(:user) + + token = insert(:oauth_token, user: user, scopes: ["read:statuses"]) + + {:ok, activity} = CommonAPI.post(user, %{status: "#cofe"}) + + {:ok, _} = CommonAPI.react_with_emoji(activity.id, user2, "🎅") + {:ok, _} = CommonAPI.react_with_emoji(activity.id, user3, "🎅") + + result = + conn + |> assign(:user, user) + |> assign(:token, token) + |> get("/api/v1/pleroma/statuses/#{activity.id}/reactions") + |> json_response_and_validate_schema(200) + + assert [%{"name" => "🎅", "count" => 2}] = result + + User.mute(user, user3) + + result = + conn + |> assign(:user, user) + |> assign(:token, token) + |> get("/api/v1/pleroma/statuses/#{activity.id}/reactions") + |> json_response_and_validate_schema(200) + + assert [%{"name" => "🎅", "count" => 1}] = result + + result = + conn + |> assign(:user, user) + |> assign(:token, token) + |> get("/api/v1/pleroma/statuses/#{activity.id}/reactions?with_muted=true") + |> json_response_and_validate_schema(200) + + assert [%{"name" => "🎅", "count" => 2}] = result + end + test "GET /api/v1/pleroma/statuses/:id/reactions with :show_reactions disabled", %{conn: conn} do clear_config([:instance, :show_reactions], false) diff --git a/test/pleroma/web/pleroma_api/controllers/instances_controller_test.exs b/test/pleroma/web/pleroma_api/controllers/instances_controller_test.exs new file mode 100644 index 000000000..54cf9d083 --- /dev/null +++ b/test/pleroma/web/pleroma_api/controllers/instances_controller_test.exs @@ -0,0 +1,38 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.PleromaApi.InstancesControllerTest do + use Pleroma.Web.ConnCase + + alias Pleroma.Instances + + setup_all do: clear_config([:instance, :federation_reachability_timeout_days], 1) + + setup do + constant = "http://consistently-unreachable.name/" + eventual = "http://eventually-unreachable.com/path" + + {:ok, %Pleroma.Instances.Instance{unreachable_since: constant_unreachable}} = + Instances.set_consistently_unreachable(constant) + + _eventual_unrechable = Instances.set_unreachable(eventual) + + %{constant_unreachable: constant_unreachable, constant: constant} + end + + test "GET /api/v1/pleroma/federation_status", %{ + conn: conn, + constant_unreachable: constant_unreachable, + constant: constant + } do + constant_host = URI.parse(constant).host + + assert conn + |> put_req_header("content-type", "application/json") + |> get("/api/v1/pleroma/federation_status") + |> json_response_and_validate_schema(200) == %{ + "unreachable" => %{constant_host => to_string(constant_unreachable)} + } + end +end diff --git a/test/web/pleroma_api/controllers/mascot_controller_test.exs b/test/pleroma/web/pleroma_api/controllers/mascot_controller_test.exs index e2ead6e15..0011ddd54 100644 --- a/test/web/pleroma_api/controllers/mascot_controller_test.exs +++ b/test/pleroma/web/pleroma_api/controllers/mascot_controller_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.PleromaAPI.MascotControllerTest do - use Pleroma.Web.ConnCase + use Pleroma.Web.ConnCase, async: true alias Pleroma.User @@ -24,7 +24,7 @@ defmodule Pleroma.Web.PleromaAPI.MascotControllerTest do assert json_response_and_validate_schema(ret_conn, 415) file = %Plug.Upload{ - content_type: "image/jpg", + content_type: "image/jpeg", path: Path.absname("test/fixtures/image.jpg"), filename: "an_image.jpg" } @@ -34,7 +34,7 @@ defmodule Pleroma.Web.PleromaAPI.MascotControllerTest do |> put_req_header("content-type", "multipart/form-data") |> put("/api/v1/pleroma/mascot", %{"file" => file}) - assert %{"id" => _, "type" => image} = json_response_and_validate_schema(conn, 200) + assert %{"id" => _, "type" => _image} = json_response_and_validate_schema(conn, 200) end test "mascot retrieving" do @@ -48,7 +48,7 @@ defmodule Pleroma.Web.PleromaAPI.MascotControllerTest do # When a user sets their mascot, we should get that back file = %Plug.Upload{ - content_type: "image/jpg", + content_type: "image/jpeg", path: Path.absname("test/fixtures/image.jpg"), filename: "an_image.jpg" } diff --git a/test/web/pleroma_api/controllers/notification_controller_test.exs b/test/pleroma/web/pleroma_api/controllers/notification_controller_test.exs index bb4fe6c49..08f374908 100644 --- a/test/web/pleroma_api/controllers/notification_controller_test.exs +++ b/test/pleroma/web/pleroma_api/controllers/notification_controller_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.PleromaAPI.NotificationControllerTest do - use Pleroma.Web.ConnCase + use Pleroma.Web.ConnCase, async: true alias Pleroma.Notification alias Pleroma.Repo diff --git a/test/pleroma/web/pleroma_api/controllers/report_controller_test.exs b/test/pleroma/web/pleroma_api/controllers/report_controller_test.exs new file mode 100644 index 000000000..c507aeca0 --- /dev/null +++ b/test/pleroma/web/pleroma_api/controllers/report_controller_test.exs @@ -0,0 +1,80 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.PleromaAPI.ReportControllerTest do + use Pleroma.Web.ConnCase, async: true + + import Pleroma.Factory + + alias Pleroma.Web.CommonAPI + + describe "GET /api/v0/pleroma/reports" do + test "returns list of own reports" do + %{conn: reporter_conn, user: reporter} = oauth_access(["read:reports"]) + %{conn: reported_conn, user: reported} = oauth_access(["read:reports"]) + activity = insert(:note_activity, user: reported) + + {:ok, %{id: report_id}} = + CommonAPI.report(reporter, %{ + account_id: reported.id, + comment: "You stole my sandwich!", + status_ids: [activity.id] + }) + + assert reported_response = + reported_conn + |> get("/api/v0/pleroma/reports") + |> json_response_and_validate_schema(:ok) + + assert reported_response == %{"reports" => [], "total" => 0} + + assert reporter_response = + reporter_conn + |> get("/api/v0/pleroma/reports") + |> json_response_and_validate_schema(:ok) + + assert %{"reports" => [report], "total" => 1} = reporter_response + assert report["id"] == report_id + refute report["notes"] + end + end + + describe "GET /api/v0/pleroma/reports/:id" do + test "returns report by its id" do + %{conn: reporter_conn, user: reporter} = oauth_access(["read:reports"]) + %{conn: reported_conn, user: reported} = oauth_access(["read:reports"]) + activity = insert(:note_activity, user: reported) + + {:ok, %{id: report_id}} = + CommonAPI.report(reporter, %{ + account_id: reported.id, + comment: "You stole my sandwich!", + status_ids: [activity.id] + }) + + assert reported_conn + |> get("/api/v0/pleroma/reports/#{report_id}") + |> json_response_and_validate_schema(:not_found) + + assert response = + reporter_conn + |> get("/api/v0/pleroma/reports/#{report_id}") + |> json_response_and_validate_schema(:ok) + + assert response["id"] == report_id + refute response["notes"] + end + + test "returns 404 when report id is invalid" do + %{conn: conn, user: _user} = oauth_access(["read:reports"]) + + assert response = + conn + |> get("/api/v0/pleroma/reports/0") + |> json_response_and_validate_schema(:not_found) + + assert response == %{"error" => "Record not found"} + end + end +end diff --git a/test/web/pleroma_api/controllers/scrobble_controller_test.exs b/test/pleroma/web/pleroma_api/controllers/scrobble_controller_test.exs index f39c07ac6..d4546f442 100644 --- a/test/web/pleroma_api/controllers/scrobble_controller_test.exs +++ b/test/pleroma/web/pleroma_api/controllers/scrobble_controller_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.PleromaAPI.ScrobbleControllerTest do - use Pleroma.Web.ConnCase + use Pleroma.Web.ConnCase, async: true alias Pleroma.Web.CommonAPI diff --git a/test/web/pleroma_api/controllers/two_factor_authentication_controller_test.exs b/test/pleroma/web/pleroma_api/controllers/two_factor_authentication_controller_test.exs index d23d08a00..24074f4e5 100644 --- a/test/web/pleroma_api/controllers/two_factor_authentication_controller_test.exs +++ b/test/pleroma/web/pleroma_api/controllers/two_factor_authentication_controller_test.exs @@ -1,5 +1,9 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + defmodule Pleroma.Web.PleromaAPI.TwoFactorAuthenticationControllerTest do - use Pleroma.Web.ConnCase + use Pleroma.Web.ConnCase, async: true import Pleroma.Factory alias Pleroma.MFA.Settings diff --git a/test/pleroma/web/pleroma_api/controllers/user_import_controller_test.exs b/test/pleroma/web/pleroma_api/controllers/user_import_controller_test.exs new file mode 100644 index 000000000..d977bc3a2 --- /dev/null +++ b/test/pleroma/web/pleroma_api/controllers/user_import_controller_test.exs @@ -0,0 +1,235 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.PleromaAPI.UserImportControllerTest do + use Pleroma.Web.ConnCase + use Oban.Testing, repo: Pleroma.Repo + + alias Pleroma.Tests.ObanHelpers + + import Pleroma.Factory + import Mock + + setup do + Tesla.Mock.mock(fn env -> apply(HttpRequestMock, :request, [env]) end) + :ok + end + + describe "POST /api/pleroma/follow_import" do + setup do: oauth_access(["follow"]) + + test "it returns HTTP 200", %{conn: conn} do + user2 = insert(:user) + + assert "job started" == + conn + |> put_req_header("content-type", "application/json") + |> post("/api/pleroma/follow_import", %{"list" => "#{user2.ap_id}"}) + |> json_response_and_validate_schema(200) + end + + test "it imports follow lists from file", %{conn: conn} do + user2 = insert(:user) + + with_mocks([ + {File, [], + read!: fn "follow_list.txt" -> + "Account address,Show boosts\n#{user2.ap_id},true" + end} + ]) do + assert "job started" == + conn + |> put_req_header("content-type", "application/json") + |> post("/api/pleroma/follow_import", %{ + "list" => %Plug.Upload{path: "follow_list.txt"} + }) + |> json_response_and_validate_schema(200) + + assert [{:ok, job_result}] = ObanHelpers.perform_all() + assert job_result == [refresh_record(user2)] + assert [%Pleroma.User{follower_count: 1}] = job_result + end + end + + test "it imports new-style mastodon follow lists", %{conn: conn} do + user2 = insert(:user) + + response = + conn + |> put_req_header("content-type", "application/json") + |> post("/api/pleroma/follow_import", %{ + "list" => "Account address,Show boosts\n#{user2.ap_id},true" + }) + |> json_response_and_validate_schema(200) + + assert response == "job started" + end + + test "requires 'follow' or 'write:follows' permissions" do + token1 = insert(:oauth_token, scopes: ["read", "write"]) + token2 = insert(:oauth_token, scopes: ["follow"]) + token3 = insert(:oauth_token, scopes: ["something"]) + another_user = insert(:user) + + for token <- [token1, token2, token3] do + conn = + build_conn() + |> put_req_header("authorization", "Bearer #{token.token}") + |> put_req_header("content-type", "application/json") + |> post("/api/pleroma/follow_import", %{"list" => "#{another_user.ap_id}"}) + + if token == token3 do + assert %{"error" => "Insufficient permissions: follow | write:follows."} == + json_response(conn, 403) + else + assert json_response_and_validate_schema(conn, 200) + end + end + end + + test "it imports follows with different nickname variations", %{conn: conn} do + users = [user2, user3, user4, user5, user6] = insert_list(5, :user) + + identifiers = + [ + user2.ap_id, + user3.nickname, + " ", + "@" <> user4.nickname, + user5.nickname <> "@localhost", + "@" <> user6.nickname <> "@localhost" + ] + |> Enum.join("\n") + + assert "job started" == + conn + |> put_req_header("content-type", "application/json") + |> post("/api/pleroma/follow_import", %{"list" => identifiers}) + |> json_response_and_validate_schema(200) + + assert [{:ok, job_result}] = ObanHelpers.perform_all() + assert job_result == Enum.map(users, &refresh_record/1) + end + end + + describe "POST /api/pleroma/blocks_import" do + # Note: "follow" or "write:blocks" permission is required + setup do: oauth_access(["write:blocks"]) + + test "it returns HTTP 200", %{conn: conn} do + user2 = insert(:user) + + assert "job started" == + conn + |> put_req_header("content-type", "application/json") + |> post("/api/pleroma/blocks_import", %{"list" => "#{user2.ap_id}"}) + |> json_response_and_validate_schema(200) + end + + test "it imports blocks users from file", %{conn: conn} do + users = [user2, user3] = insert_list(2, :user) + + with_mocks([ + {File, [], read!: fn "blocks_list.txt" -> "#{user2.ap_id} #{user3.ap_id}" end} + ]) do + assert "job started" == + conn + |> put_req_header("content-type", "application/json") + |> post("/api/pleroma/blocks_import", %{ + "list" => %Plug.Upload{path: "blocks_list.txt"} + }) + |> json_response_and_validate_schema(200) + + assert [{:ok, job_result}] = ObanHelpers.perform_all() + assert job_result == users + end + end + + test "it imports blocks with different nickname variations", %{conn: conn} do + users = [user2, user3, user4, user5, user6] = insert_list(5, :user) + + identifiers = + [ + user2.ap_id, + user3.nickname, + "@" <> user4.nickname, + user5.nickname <> "@localhost", + "@" <> user6.nickname <> "@localhost" + ] + |> Enum.join(" ") + + assert "job started" == + conn + |> put_req_header("content-type", "application/json") + |> post("/api/pleroma/blocks_import", %{"list" => identifiers}) + |> json_response_and_validate_schema(200) + + assert [{:ok, job_result}] = ObanHelpers.perform_all() + assert job_result == users + end + end + + describe "POST /api/pleroma/mutes_import" do + # Note: "follow" or "write:mutes" permission is required + setup do: oauth_access(["write:mutes"]) + + test "it returns HTTP 200", %{user: user, conn: conn} do + user2 = insert(:user) + + assert "job started" == + conn + |> put_req_header("content-type", "application/json") + |> post("/api/pleroma/mutes_import", %{"list" => "#{user2.ap_id}"}) + |> json_response_and_validate_schema(200) + + assert [{:ok, job_result}] = ObanHelpers.perform_all() + assert job_result == [user2] + assert Pleroma.User.mutes?(user, user2) + end + + test "it imports mutes users from file", %{user: user, conn: conn} do + users = [user2, user3] = insert_list(2, :user) + + with_mocks([ + {File, [], read!: fn "mutes_list.txt" -> "#{user2.ap_id} #{user3.ap_id}" end} + ]) do + assert "job started" == + conn + |> put_req_header("content-type", "application/json") + |> post("/api/pleroma/mutes_import", %{ + "list" => %Plug.Upload{path: "mutes_list.txt"} + }) + |> json_response_and_validate_schema(200) + + assert [{:ok, job_result}] = ObanHelpers.perform_all() + assert job_result == users + assert Enum.all?(users, &Pleroma.User.mutes?(user, &1)) + end + end + + test "it imports mutes with different nickname variations", %{user: user, conn: conn} do + users = [user2, user3, user4, user5, user6] = insert_list(5, :user) + + identifiers = + [ + user2.ap_id, + user3.nickname, + "@" <> user4.nickname, + user5.nickname <> "@localhost", + "@" <> user6.nickname <> "@localhost" + ] + |> Enum.join(" ") + + assert "job started" == + conn + |> put_req_header("content-type", "application/json") + |> post("/api/pleroma/mutes_import", %{"list" => identifiers}) + |> json_response_and_validate_schema(200) + + assert [{:ok, job_result}] = ObanHelpers.perform_all() + assert job_result == users + assert Enum.all?(users, &Pleroma.User.mutes?(user, &1)) + end + end +end diff --git a/test/pleroma/web/pleroma_api/views/app_view_test.exs b/test/pleroma/web/pleroma_api/views/app_view_test.exs new file mode 100644 index 000000000..f0aee6987 --- /dev/null +++ b/test/pleroma/web/pleroma_api/views/app_view_test.exs @@ -0,0 +1,21 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.PleromaAPI.AppViewTest do + use Pleroma.DataCase, async: true + alias Pleroma.Web.PleromaAPI.AppView + import Pleroma.Factory + + test "index.json" do + apps = [ + insert(:oauth_app), + insert(:oauth_app), + insert(:oauth_app) + ] + + results = AppView.render("index.json", %{apps: apps}) + + assert [%{client_id: _, client_secret: _}, _, _] = results + end +end diff --git a/test/pleroma/web/pleroma_api/views/backup_view_test.exs b/test/pleroma/web/pleroma_api/views/backup_view_test.exs new file mode 100644 index 000000000..9b4298dd1 --- /dev/null +++ b/test/pleroma/web/pleroma_api/views/backup_view_test.exs @@ -0,0 +1,18 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.PleromaAPI.BackupViewTest do + use Pleroma.DataCase, async: true + alias Pleroma.User.Backup + alias Pleroma.Web.PleromaAPI.BackupView + import Pleroma.Factory + + test "it renders the ID" do + user = insert(:user) + backup = Backup.new(user) + + result = BackupView.render("show.json", backup: backup) + assert result.id == backup.id + end +end diff --git a/test/web/pleroma_api/views/chat/message_reference_view_test.exs b/test/pleroma/web/pleroma_api/views/chat_message_reference_view_test.exs index 40dbae3cd..6deaa2102 100644 --- a/test/web/pleroma_api/views/chat/message_reference_view_test.exs +++ b/test/pleroma/web/pleroma_api/views/chat_message_reference_view_test.exs @@ -1,8 +1,8 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.Web.PleromaAPI.Chat.MessageReferenceViewTest do +defmodule Pleroma.Web.PleromaAPI.ChatMessageReferenceViewTest do use Pleroma.DataCase alias Pleroma.Chat @@ -19,17 +19,19 @@ defmodule Pleroma.Web.PleromaAPI.Chat.MessageReferenceViewTest do recipient = insert(:user) file = %Plug.Upload{ - content_type: "image/jpg", + content_type: "image/jpeg", path: Path.absname("test/fixtures/image.jpg"), filename: "an_image.jpg" } {:ok, upload} = ActivityPub.upload(file, actor: user.ap_id) - {:ok, activity} = CommonAPI.post_chat_message(user, recipient, "kippis :firefox:") + + {:ok, activity} = + CommonAPI.post_chat_message(user, recipient, "kippis :firefox:", idempotency_key: "123") chat = Chat.get(user.id, recipient.ap_id) - object = Object.normalize(activity) + object = Object.normalize(activity, fetch: false) cm_ref = MessageReference.for_chat_and_object(chat, object) @@ -42,10 +44,11 @@ defmodule Pleroma.Web.PleromaAPI.Chat.MessageReferenceViewTest do assert chat_message[:created_at] assert chat_message[:unread] == false assert match?([%{shortcode: "firefox"}], chat_message[:emojis]) + assert chat_message[:idempotency_key] == "123" clear_config([:rich_media, :enabled], true) - Tesla.Mock.mock(fn + Tesla.Mock.mock_global(fn %{url: "https://example.com/ogp"} -> %Tesla.Env{status: 200, body: File.read!("test/fixtures/rich_media/ogp.html")} end) @@ -55,7 +58,7 @@ defmodule Pleroma.Web.PleromaAPI.Chat.MessageReferenceViewTest do media_id: upload.id ) - object = Object.normalize(activity) + object = Object.normalize(activity, fetch: false) cm_ref = MessageReference.for_chat_and_object(chat, object) diff --git a/test/web/pleroma_api/views/chat_view_test.exs b/test/pleroma/web/pleroma_api/views/chat_view_test.exs index 02484b705..5456c2de0 100644 --- a/test/web/pleroma_api/views/chat_view_test.exs +++ b/test/pleroma/web/pleroma_api/views/chat_view_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.PleromaAPI.ChatViewTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true alias Pleroma.Chat alias Pleroma.Chat.MessageReference @@ -35,7 +35,7 @@ defmodule Pleroma.Web.PleromaAPI.ChatViewTest do {:ok, chat_message_creation} = CommonAPI.post_chat_message(user, recipient, "hello") - chat_message = Object.normalize(chat_message_creation, false) + chat_message = Object.normalize(chat_message_creation, fetch: false) {:ok, chat} = Chat.get_or_create(user.id, recipient.ap_id) diff --git a/test/web/pleroma_api/views/scrobble_view_test.exs b/test/pleroma/web/pleroma_api/views/scrobble_view_test.exs index 6bdb56509..382051f6f 100644 --- a/test/web/pleroma_api/views/scrobble_view_test.exs +++ b/test/pleroma/web/pleroma_api/views/scrobble_view_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.Web.PleromaAPI.StatusViewTest do - use Pleroma.DataCase +defmodule Pleroma.Web.PleromaAPI.ScrobbleViewTest do + use Pleroma.DataCase, async: true alias Pleroma.Web.PleromaAPI.ScrobbleView diff --git a/test/plugs/admin_secret_authentication_plug_test.exs b/test/pleroma/web/plugs/admin_secret_authentication_plug_test.exs index 89df03c4b..79561afb7 100644 --- a/test/plugs/admin_secret_authentication_plug_test.exs +++ b/test/pleroma/web/plugs/admin_secret_authentication_plug_test.exs @@ -1,17 +1,17 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.Plugs.AdminSecretAuthenticationPlugTest do - use Pleroma.Web.ConnCase, async: true +defmodule Pleroma.Web.Plugs.AdminSecretAuthenticationPlugTest do + use Pleroma.Web.ConnCase import Mock import Pleroma.Factory - alias Pleroma.Plugs.AdminSecretAuthenticationPlug - alias Pleroma.Plugs.OAuthScopesPlug - alias Pleroma.Plugs.PlugHelper - alias Pleroma.Plugs.RateLimiter + alias Pleroma.Web.Plugs.AdminSecretAuthenticationPlug + alias Pleroma.Web.Plugs.OAuthScopesPlug + alias Pleroma.Web.Plugs.PlugHelper + alias Pleroma.Web.Plugs.RateLimiter test "does nothing if a user is assigned", %{conn: conn} do user = insert(:user) @@ -35,7 +35,7 @@ defmodule Pleroma.Plugs.AdminSecretAuthenticationPlugTest do end test "with `admin_token` query parameter", %{conn: conn} do - Pleroma.Config.put(:admin_token, "password123") + clear_config(:admin_token, "password123") conn = %{conn | params: %{"admin_token" => "wrong_password"}} @@ -49,11 +49,12 @@ defmodule Pleroma.Plugs.AdminSecretAuthenticationPlugTest do |> AdminSecretAuthenticationPlug.call(%{}) assert conn.assigns[:user].is_admin + assert conn.assigns[:token] == nil assert PlugHelper.plug_skipped?(conn, OAuthScopesPlug) end test "with `x-admin-token` HTTP header", %{conn: conn} do - Pleroma.Config.put(:admin_token, "☕️") + clear_config(:admin_token, "☕️") conn = conn @@ -69,6 +70,7 @@ defmodule Pleroma.Plugs.AdminSecretAuthenticationPlugTest do |> AdminSecretAuthenticationPlug.call(%{}) assert conn.assigns[:user].is_admin + assert conn.assigns[:token] == nil assert PlugHelper.plug_skipped?(conn, OAuthScopesPlug) end end diff --git a/test/plugs/authentication_plug_test.exs b/test/pleroma/web/plugs/authentication_plug_test.exs index 777ae15ae..118ab302a 100644 --- a/test/plugs/authentication_plug_test.exs +++ b/test/pleroma/web/plugs/authentication_plug_test.exs @@ -1,14 +1,14 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.Plugs.AuthenticationPlugTest do +defmodule Pleroma.Web.Plugs.AuthenticationPlugTest do use Pleroma.Web.ConnCase, async: true - alias Pleroma.Plugs.AuthenticationPlug - alias Pleroma.Plugs.OAuthScopesPlug - alias Pleroma.Plugs.PlugHelper alias Pleroma.User + alias Pleroma.Web.Plugs.AuthenticationPlug + alias Pleroma.Web.Plugs.OAuthScopesPlug + alias Pleroma.Web.Plugs.PlugHelper import ExUnit.CaptureLog import Pleroma.Factory @@ -17,7 +17,7 @@ defmodule Pleroma.Plugs.AuthenticationPlugTest do user = %User{ id: 1, name: "dude", - password_hash: Pbkdf2.hash_pwd_salt("guy") + password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt("guy") } conn = @@ -48,6 +48,7 @@ defmodule Pleroma.Plugs.AuthenticationPlugTest do |> AuthenticationPlug.call(%{}) assert conn.assigns.user == conn.assigns.auth_user + assert conn.assigns.token == nil assert PlugHelper.plug_skipped?(conn, OAuthScopesPlug) end @@ -62,6 +63,7 @@ defmodule Pleroma.Plugs.AuthenticationPlugTest do |> AuthenticationPlug.call(%{}) assert conn.assigns.user.id == conn.assigns.auth_user.id + assert conn.assigns.token == nil assert PlugHelper.plug_skipped?(conn, OAuthScopesPlug) user = User.get_by_id(user.id) @@ -83,6 +85,7 @@ defmodule Pleroma.Plugs.AuthenticationPlugTest do |> AuthenticationPlug.call(%{}) assert conn.assigns.user.id == conn.assigns.auth_user.id + assert conn.assigns.token == nil assert PlugHelper.plug_skipped?(conn, OAuthScopesPlug) user = User.get_by_id(user.id) @@ -118,7 +121,7 @@ defmodule Pleroma.Plugs.AuthenticationPlugTest do "psBWV8gxkGOZWBz$PmfCycChoxeJ3GgGzwvhlgacb9mUoZ.KUXNCssekER4SJ7bOK53uXrHNb2e4i8yPFgSKyzaW9CcmrDXWIEMtD1" assert capture_log(fn -> - refute Pleroma.Plugs.AuthenticationPlug.checkpw("password", hash) + refute AuthenticationPlug.checkpw("password", hash) end) =~ "[error] Password hash not recognized" end end diff --git a/test/plugs/basic_auth_decoder_plug_test.exs b/test/pleroma/web/plugs/basic_auth_decoder_plug_test.exs index a6063d4f6..e90078eb5 100644 --- a/test/plugs/basic_auth_decoder_plug_test.exs +++ b/test/pleroma/web/plugs/basic_auth_decoder_plug_test.exs @@ -1,11 +1,11 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.Plugs.BasicAuthDecoderPlugTest do +defmodule Pleroma.Web.Plugs.BasicAuthDecoderPlugTest do use Pleroma.Web.ConnCase, async: true - alias Pleroma.Plugs.BasicAuthDecoderPlug + alias Pleroma.Web.Plugs.BasicAuthDecoderPlug defp basic_auth_enc(username, password) do "Basic " <> Base.encode64("#{username}:#{password}") diff --git a/test/plugs/cache_control_test.exs b/test/pleroma/web/plugs/cache_control_test.exs index 6b567e81d..263961897 100644 --- a/test/plugs/cache_control_test.exs +++ b/test/pleroma/web/plugs/cache_control_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.Web.CacheControlTest do - use Pleroma.Web.ConnCase +defmodule Pleroma.Web.Plugs.CacheControlTest do + use Pleroma.Web.ConnCase, async: true alias Plug.Conn test "Verify Cache-Control header on static assets", %{conn: conn} do diff --git a/test/plugs/cache_test.exs b/test/pleroma/web/plugs/cache_test.exs index 8b231c881..0ceab6cab 100644 --- a/test/plugs/cache_test.exs +++ b/test/pleroma/web/plugs/cache_test.exs @@ -1,12 +1,13 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.Plugs.CacheTest do - use ExUnit.Case, async: true +defmodule Pleroma.Web.Plugs.CacheTest do + # Relies on Cachex, has to stay synchronous + use Pleroma.DataCase use Plug.Test - alias Pleroma.Plugs.Cache + alias Pleroma.Web.Plugs.Cache @miss_resp {200, [ @@ -24,11 +25,6 @@ defmodule Pleroma.Plugs.CacheTest do @ttl 5 - setup do - Cachex.clear(:web_resp_cache) - :ok - end - test "caches a response" do assert @miss_resp == conn(:get, "/") diff --git a/test/pleroma/web/plugs/digest_plug_test.exs b/test/pleroma/web/plugs/digest_plug_test.exs new file mode 100644 index 000000000..629c28c93 --- /dev/null +++ b/test/pleroma/web/plugs/digest_plug_test.exs @@ -0,0 +1,48 @@ +defmodule Pleroma.Web.Plugs.DigestPlugTest do + use ExUnit.Case, async: true + use Plug.Test + + test "digest algorithm is taken from digest header" do + body = "{\"hello\": \"world\"}" + digest = "X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE=" + + {:ok, ^body, conn} = + :get + |> conn("/", body) + |> put_req_header("content-type", "application/json") + |> put_req_header("digest", "sha-256=" <> digest) + |> Pleroma.Web.Plugs.DigestPlug.read_body([]) + + assert conn.assigns[:digest] == "sha-256=" <> digest + + {:ok, ^body, conn} = + :get + |> conn("/", body) + |> put_req_header("content-type", "application/json") + |> put_req_header("digest", "SHA-256=" <> digest) + |> Pleroma.Web.Plugs.DigestPlug.read_body([]) + + assert conn.assigns[:digest] == "SHA-256=" <> digest + end + + test "error if digest algorithm is invalid" do + body = "{\"hello\": \"world\"}" + digest = "X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE=" + + assert_raise ArgumentError, "invalid value for digest algorithm, got: MD5", fn -> + :get + |> conn("/", body) + |> put_req_header("content-type", "application/json") + |> put_req_header("digest", "MD5=" <> digest) + |> Pleroma.Web.Plugs.DigestPlug.read_body([]) + end + + assert_raise ArgumentError, "invalid value for digest algorithm, got: md5", fn -> + :get + |> conn("/", body) + |> put_req_header("content-type", "application/json") + |> put_req_header("digest", "md5=" <> digest) + |> Pleroma.Web.Plugs.DigestPlug.read_body([]) + end + end +end diff --git a/test/plugs/ensure_authenticated_plug_test.exs b/test/pleroma/web/plugs/ensure_authenticated_plug_test.exs index a0667c5e0..6b3ee3d87 100644 --- a/test/plugs/ensure_authenticated_plug_test.exs +++ b/test/pleroma/web/plugs/ensure_authenticated_plug_test.exs @@ -1,12 +1,12 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.Plugs.EnsureAuthenticatedPlugTest do +defmodule Pleroma.Web.Plugs.EnsureAuthenticatedPlugTest do use Pleroma.Web.ConnCase, async: true - alias Pleroma.Plugs.EnsureAuthenticatedPlug alias Pleroma.User + alias Pleroma.Web.Plugs.EnsureAuthenticatedPlug describe "without :if_func / :unless_func options" do test "it halts if user is NOT assigned", %{conn: conn} do diff --git a/test/plugs/ensure_public_or_authenticated_plug_test.exs b/test/pleroma/web/plugs/ensure_public_or_authenticated_plug_test.exs index fc2934369..75c3b5784 100644 --- a/test/plugs/ensure_public_or_authenticated_plug_test.exs +++ b/test/pleroma/web/plugs/ensure_public_or_authenticated_plug_test.exs @@ -1,18 +1,17 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.Plugs.EnsurePublicOrAuthenticatedPlugTest do - use Pleroma.Web.ConnCase, async: true +defmodule Pleroma.Web.Plugs.EnsurePublicOrAuthenticatedPlugTest do + use Pleroma.Web.ConnCase - alias Pleroma.Config - alias Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug alias Pleroma.User + alias Pleroma.Web.Plugs.EnsurePublicOrAuthenticatedPlug setup do: clear_config([:instance, :public]) test "it halts if not public and no user is assigned", %{conn: conn} do - Config.put([:instance, :public], false) + clear_config([:instance, :public], false) conn = conn @@ -23,7 +22,7 @@ defmodule Pleroma.Plugs.EnsurePublicOrAuthenticatedPlugTest do end test "it continues if public", %{conn: conn} do - Config.put([:instance, :public], true) + clear_config([:instance, :public], true) ret_conn = conn @@ -33,7 +32,7 @@ defmodule Pleroma.Plugs.EnsurePublicOrAuthenticatedPlugTest do end test "it continues if a user is assigned, even if not public", %{conn: conn} do - Config.put([:instance, :public], false) + clear_config([:instance, :public], false) conn = conn diff --git a/test/pleroma/web/plugs/ensure_staff_privileged_plug_test.exs b/test/pleroma/web/plugs/ensure_staff_privileged_plug_test.exs new file mode 100644 index 000000000..74f4ae504 --- /dev/null +++ b/test/pleroma/web/plugs/ensure_staff_privileged_plug_test.exs @@ -0,0 +1,60 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.Plugs.EnsureStaffPrivilegedPlugTest do + use Pleroma.Web.ConnCase, async: true + + alias Pleroma.Web.Plugs.EnsureStaffPrivilegedPlug + import Pleroma.Factory + + test "accepts a user that is an admin" do + user = insert(:user, is_admin: true) + + conn = assign(build_conn(), :user, user) + + ret_conn = EnsureStaffPrivilegedPlug.call(conn, %{}) + + assert conn == ret_conn + end + + test "accepts a user that is a moderator when :privileged_staff is enabled" do + clear_config([:instance, :privileged_staff], true) + user = insert(:user, is_moderator: true) + + conn = assign(build_conn(), :user, user) + + ret_conn = EnsureStaffPrivilegedPlug.call(conn, %{}) + + assert conn == ret_conn + end + + test "denies a user that is a moderator when :privileged_staff is disabled" do + clear_config([:instance, :privileged_staff], false) + user = insert(:user, is_moderator: true) + + conn = + build_conn() + |> assign(:user, user) + |> EnsureStaffPrivilegedPlug.call(%{}) + + assert conn.status == 403 + end + + test "denies a user that isn't a staff member" do + user = insert(:user) + + conn = + build_conn() + |> assign(:user, user) + |> EnsureStaffPrivilegedPlug.call(%{}) + + assert conn.status == 403 + end + + test "denies when a user isn't set" do + conn = EnsureStaffPrivilegedPlug.call(build_conn(), %{}) + + assert conn.status == 403 + end +end diff --git a/test/pleroma/web/plugs/ensure_user_token_assigns_plug_test.exs b/test/pleroma/web/plugs/ensure_user_token_assigns_plug_test.exs new file mode 100644 index 000000000..28ec67158 --- /dev/null +++ b/test/pleroma/web/plugs/ensure_user_token_assigns_plug_test.exs @@ -0,0 +1,69 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.Plugs.EnsureUserTokenAssignsPlugTest do + use Pleroma.Web.ConnCase, async: true + + import Pleroma.Factory + + alias Pleroma.Web.Plugs.EnsureUserTokenAssignsPlug + + test "with :user assign set to a User record " <> + "and :token assign set to a Token belonging to this user, " <> + "it does nothing" do + %{conn: conn} = oauth_access(["read"]) + + ret_conn = EnsureUserTokenAssignsPlug.call(conn, %{}) + + assert conn == ret_conn + end + + test "with :user assign set to a User record " <> + "but :token assign not set or not a Token, " <> + "it assigns :token to `nil`", + %{conn: conn} do + user = insert(:user) + conn = assign(conn, :user, user) + + ret_conn = EnsureUserTokenAssignsPlug.call(conn, %{}) + + assert %{token: nil} = ret_conn.assigns + + ret_conn2 = + conn + |> assign(:token, 1) + |> EnsureUserTokenAssignsPlug.call(%{}) + + assert %{token: nil} = ret_conn2.assigns + end + + # Abnormal (unexpected) scenario + test "with :user assign set to a User record " <> + "but :token assign set to a Token NOT belonging to :user, " <> + "it drops auth info" do + %{conn: conn} = oauth_access(["read"]) + other_user = insert(:user) + + conn = assign(conn, :user, other_user) + + ret_conn = EnsureUserTokenAssignsPlug.call(conn, %{}) + + assert %{user: nil, token: nil} = ret_conn.assigns + end + + test "if :user assign is not set to a User record, it sets :user and :token to nil", %{ + conn: conn + } do + ret_conn = EnsureUserTokenAssignsPlug.call(conn, %{}) + + assert %{user: nil, token: nil} = ret_conn.assigns + + ret_conn2 = + conn + |> assign(:user, 1) + |> EnsureUserTokenAssignsPlug.call(%{}) + + assert %{user: nil, token: nil} = ret_conn2.assigns + end +end diff --git a/test/web/plugs/federating_plug_test.exs b/test/pleroma/web/plugs/federating_plug_test.exs index 2f8aadadc..01ecd2a1e 100644 --- a/test/web/plugs/federating_plug_test.exs +++ b/test/pleroma/web/plugs/federating_plug_test.exs @@ -1,29 +1,29 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.Web.FederatingPlugTest do +defmodule Pleroma.Web.Plugs.FederatingPlugTest do use Pleroma.Web.ConnCase setup do: clear_config([:instance, :federating]) test "returns and halt the conn when federating is disabled" do - Pleroma.Config.put([:instance, :federating], false) + clear_config([:instance, :federating], false) conn = build_conn() - |> Pleroma.Web.FederatingPlug.call(%{}) + |> Pleroma.Web.Plugs.FederatingPlug.call(%{}) assert conn.status == 404 assert conn.halted end test "does nothing when federating is enabled" do - Pleroma.Config.put([:instance, :federating], true) + clear_config([:instance, :federating], true) conn = build_conn() - |> Pleroma.Web.FederatingPlug.call(%{}) + |> Pleroma.Web.Plugs.FederatingPlug.call(%{}) refute conn.status refute conn.halted diff --git a/test/pleroma/web/plugs/frontend_static_plug_test.exs b/test/pleroma/web/plugs/frontend_static_plug_test.exs new file mode 100644 index 000000000..4b3925ad2 --- /dev/null +++ b/test/pleroma/web/plugs/frontend_static_plug_test.exs @@ -0,0 +1,110 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.Plugs.FrontendStaticPlugTest do + use Pleroma.Web.ConnCase + import Mock + + @dir "test/tmp/instance_static" + + setup do + File.mkdir_p!(@dir) + on_exit(fn -> File.rm_rf(@dir) end) + end + + setup do: clear_config([:instance, :static_dir], @dir) + + test "init will give a static plug config + the frontend type" do + opts = + [ + at: "/admin", + frontend_type: :admin + ] + |> Pleroma.Web.Plugs.FrontendStatic.init() + + assert opts[:at] == ["admin"] + assert opts[:frontend_type] == :admin + end + + test "overrides existing static files", %{conn: conn} do + name = "pelmora" + ref = "uguu" + + clear_config([:frontends, :primary], %{"name" => name, "ref" => ref}) + path = "#{@dir}/frontends/#{name}/#{ref}" + + File.mkdir_p!(path) + File.write!("#{path}/index.html", "from frontend plug") + + index = get(conn, "/") + assert html_response(index, 200) == "from frontend plug" + end + + test "overrides existing static files for the `pleroma/admin` path", %{conn: conn} do + name = "pelmora" + ref = "uguu" + + clear_config([:frontends, :admin], %{"name" => name, "ref" => ref}) + path = "#{@dir}/frontends/#{name}/#{ref}" + + File.mkdir_p!(path) + File.write!("#{path}/index.html", "from frontend plug") + + index = get(conn, "/pleroma/admin/") + assert html_response(index, 200) == "from frontend plug" + end + + test "exclude invalid path", %{conn: conn} do + name = "pleroma-fe" + ref = "dist" + clear_config([:media_proxy, :enabled], true) + clear_config([Pleroma.Web.Endpoint, :secret_key_base], "00000000000") + clear_config([:frontends, :primary], %{"name" => name, "ref" => ref}) + path = "#{@dir}/frontends/#{name}/#{ref}" + + File.mkdir_p!("#{path}/proxy/rr/ss") + File.write!("#{path}/proxy/rr/ss/Ek7w8WPVcAApOvN.jpg:large", "FB image") + + url = + Pleroma.Web.MediaProxy.encode_url("https://pbs.twimg.com/media/Ek7w8WPVcAApOvN.jpg:large") + + with_mock Pleroma.ReverseProxy, + call: fn _conn, _url, _opts -> %Plug.Conn{status: :success} end do + assert %Plug.Conn{status: :success} = get(conn, url) + end + end + + test "api routes are detected correctly" do + # If this test fails we have probably added something + # new that should be in /api/ instead + expected_routes = [ + "api", + "main", + "ostatus_subscribe", + "oauth", + "objects", + "activities", + "notice", + "@:nickname", + ":nickname", + "users", + "tags", + "mailer", + "inbox", + "relay", + "internal", + ".well-known", + "nodeinfo", + "manifest.json", + "auth", + "proxy", + "phoenix", + "test", + "user_exists", + "check_password" + ] + + assert expected_routes == Pleroma.Web.Router.get_api_routes() + end +end diff --git a/test/plugs/http_security_plug_test.exs b/test/pleroma/web/plugs/http_security_plug_test.exs index 2297e3dac..4e7befdd5 100644 --- a/test/plugs/http_security_plug_test.exs +++ b/test/pleroma/web/plugs/http_security_plug_test.exs @@ -1,11 +1,10 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.Plugs.HTTPSecurityPlugTest do use Pleroma.Web.ConnCase - alias Pleroma.Config alias Plug.Conn describe "http security enabled" do @@ -73,6 +72,21 @@ defmodule Pleroma.Web.Plugs.HTTPSecurityPlugTest do assert csp =~ "media-src 'self' https:;" assert csp =~ "img-src 'self' data: blob: https:;" end + + test "it sets the Service-Worker-Allowed header", %{conn: conn} do + clear_config([:http_security, :enabled], true) + clear_config([:frontends, :primary], %{"name" => "fedi-fe", "ref" => "develop"}) + + clear_config([:frontends, :available], %{ + "fedi-fe" => %{ + "name" => "fedi-fe", + "custom-http-headers" => [{"service-worker-allowed", "/"}] + } + }) + + conn = get(conn, "/api/v1/instance") + assert Conn.get_resp_header(conn, "service-worker-allowed") == ["/"] + end end describe "img-src and media-src" do diff --git a/test/plugs/http_signature_plug_test.exs b/test/pleroma/web/plugs/http_signature_plug_test.exs index e6cbde803..56ef6b06f 100644 --- a/test/plugs/http_signature_plug_test.exs +++ b/test/pleroma/web/plugs/http_signature_plug_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.Plugs.HTTPSignaturePlugTest do @@ -32,11 +32,7 @@ defmodule Pleroma.Web.Plugs.HTTPSignaturePlugTest do describe "requires a signature when `authorized_fetch_mode` is enabled" do setup do - Pleroma.Config.put([:activitypub, :authorized_fetch_mode], true) - - on_exit(fn -> - Pleroma.Config.put([:activitypub, :authorized_fetch_mode], false) - end) + clear_config([:activitypub, :authorized_fetch_mode], true) params = %{"actor" => "http://mastodon.example.org/users/admin"} conn = build_conn(:get, "/doesntmattter", params) |> put_format("activity+json") diff --git a/test/plugs/idempotency_plug_test.exs b/test/pleroma/web/plugs/idempotency_plug_test.exs index 21fa0fbcf..dd8cda664 100644 --- a/test/plugs/idempotency_plug_test.exs +++ b/test/pleroma/web/plugs/idempotency_plug_test.exs @@ -1,12 +1,13 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.Plugs.IdempotencyPlugTest do - use ExUnit.Case, async: true +defmodule Pleroma.Web.Plugs.IdempotencyPlugTest do + # Relies on Cachex, has to stay synchronous + use Pleroma.DataCase use Plug.Test - alias Pleroma.Plugs.IdempotencyPlug + alias Pleroma.Web.Plugs.IdempotencyPlug alias Plug.Conn test "returns result from cache" do diff --git a/test/plugs/instance_static_test.exs b/test/pleroma/web/plugs/instance_static_test.exs index d42ba817e..46f2ca6b1 100644 --- a/test/plugs/instance_static_test.exs +++ b/test/pleroma/web/plugs/instance_static_test.exs @@ -1,8 +1,8 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.Web.InstanceStaticPlugTest do +defmodule Pleroma.Web.Plugs.InstanceStaticTest do use Pleroma.Web.ConnCase @dir "test/tmp/instance_static" diff --git a/test/plugs/mapped_identity_to_signature_plug_test.exs b/test/pleroma/web/plugs/mapped_signature_to_identity_plug_test.exs index 0ad3c2929..00ce6492d 100644 --- a/test/plugs/mapped_identity_to_signature_plug_test.exs +++ b/test/pleroma/web/plugs/mapped_signature_to_identity_plug_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.Plugs.MappedSignatureToIdentityPlugTest do diff --git a/test/pleroma/web/plugs/o_auth_plug_test.exs b/test/pleroma/web/plugs/o_auth_plug_test.exs new file mode 100644 index 000000000..9e4be5559 --- /dev/null +++ b/test/pleroma/web/plugs/o_auth_plug_test.exs @@ -0,0 +1,128 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.Plugs.OAuthPlugTest do + use Pleroma.Web.ConnCase, async: true + + alias Pleroma.Helpers.AuthHelper + alias Pleroma.Web.OAuth.Token + alias Pleroma.Web.OAuth.Token.Strategy.Revoke + alias Pleroma.Web.Plugs.OAuthPlug + alias Plug.Session + + import Pleroma.Factory + + setup %{conn: conn} do + user = insert(:user) + {:ok, oauth_token} = Token.create(insert(:oauth_app), user) + %{user: user, token: oauth_token, conn: conn} + end + + test "it does nothing if a user is assigned", %{conn: conn} do + conn = assign(conn, :user, %Pleroma.User{}) + ret_conn = OAuthPlug.call(conn, %{}) + + assert ret_conn == conn + end + + test "with valid token (uppercase) in auth header, it assigns the user", %{conn: conn} = opts do + conn = + conn + |> put_req_header("authorization", "BEARER #{opts[:token].token}") + |> OAuthPlug.call(%{}) + + assert conn.assigns[:user] == opts[:user] + end + + test "with valid token (downcase) in auth header, it assigns the user", %{conn: conn} = opts do + conn = + conn + |> put_req_header("authorization", "bearer #{opts[:token].token}") + |> OAuthPlug.call(%{}) + + assert conn.assigns[:user] == opts[:user] + end + + test "with valid token (downcase) in url parameters, it assigns the user", opts do + conn = + :get + |> build_conn("/?access_token=#{opts[:token].token}") + |> put_req_header("content-type", "application/json") + |> fetch_query_params() + |> OAuthPlug.call(%{}) + + assert conn.assigns[:user] == opts[:user] + end + + test "with valid token (downcase) in body parameters, it assigns the user", opts do + conn = + :post + |> build_conn("/api/v1/statuses", access_token: opts[:token].token, status: "test") + |> OAuthPlug.call(%{}) + + assert conn.assigns[:user] == opts[:user] + end + + test "with invalid token, it does not assign the user", %{conn: conn} do + conn = + conn + |> put_req_header("authorization", "bearer TTTTT") + |> OAuthPlug.call(%{}) + + refute conn.assigns[:user] + end + + describe "with :oauth_token in session, " do + setup %{token: oauth_token, conn: conn} do + session_opts = [ + store: :cookie, + key: "_test", + signing_salt: "cooldude" + ] + + conn = + conn + |> Session.call(Session.init(session_opts)) + |> fetch_session() + |> AuthHelper.put_session_token(oauth_token.token) + + %{conn: conn} + end + + test "if session-stored token matches a valid OAuth token, assigns :user and :token", %{ + conn: conn, + user: user, + token: oauth_token + } do + conn = OAuthPlug.call(conn, %{}) + + assert conn.assigns.user && conn.assigns.user.id == user.id + assert conn.assigns.token && conn.assigns.token.id == oauth_token.id + end + + test "if session-stored token matches an expired OAuth token, does nothing", %{ + conn: conn, + token: oauth_token + } do + expired_valid_until = NaiveDateTime.add(NaiveDateTime.utc_now(), -3600 * 24, :second) + + oauth_token + |> Ecto.Changeset.change(valid_until: expired_valid_until) + |> Pleroma.Repo.update() + + ret_conn = OAuthPlug.call(conn, %{}) + assert ret_conn == conn + end + + test "if session-stored token matches a revoked OAuth token, does nothing", %{ + conn: conn, + token: oauth_token + } do + Revoke.revoke(oauth_token) + + ret_conn = OAuthPlug.call(conn, %{}) + assert ret_conn == conn + end + end +end diff --git a/test/plugs/oauth_scopes_plug_test.exs b/test/pleroma/web/plugs/o_auth_scopes_plug_test.exs index 884de7b4d..9f6d3dc71 100644 --- a/test/plugs/oauth_scopes_plug_test.exs +++ b/test/pleroma/web/plugs/o_auth_scopes_plug_test.exs @@ -1,12 +1,12 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.Plugs.OAuthScopesPlugTest do - use Pleroma.Web.ConnCase, async: true +defmodule Pleroma.Web.Plugs.OAuthScopesPlugTest do + use Pleroma.Web.ConnCase - alias Pleroma.Plugs.OAuthScopesPlug alias Pleroma.Repo + alias Pleroma.Web.Plugs.OAuthScopesPlug import Mock import Pleroma.Factory @@ -169,42 +169,4 @@ defmodule Pleroma.Plugs.OAuthScopesPlugTest do assert f.(["admin:read"], ["write", "admin"]) == ["admin:read"] end end - - describe "transform_scopes/2" do - setup do: clear_config([:auth, :enforce_oauth_admin_scope_usage]) - - setup do - {:ok, %{f: &OAuthScopesPlug.transform_scopes/2}} - end - - test "with :admin option, prefixes all requested scopes with `admin:` " <> - "and [optionally] keeps only prefixed scopes, " <> - "depending on `[:auth, :enforce_oauth_admin_scope_usage]` setting", - %{f: f} do - Pleroma.Config.put([:auth, :enforce_oauth_admin_scope_usage], false) - - assert f.(["read"], %{admin: true}) == ["admin:read", "read"] - - assert f.(["read", "write"], %{admin: true}) == [ - "admin:read", - "read", - "admin:write", - "write" - ] - - Pleroma.Config.put([:auth, :enforce_oauth_admin_scope_usage], true) - - assert f.(["read:accounts"], %{admin: true}) == ["admin:read:accounts"] - - assert f.(["read", "write:reports"], %{admin: true}) == [ - "admin:read", - "admin:write:reports" - ] - end - - test "with no supported options, returns unmodified scopes", %{f: f} do - assert f.(["read"], %{}) == ["read"] - assert f.(["read", "write"], %{}) == ["read", "write"] - end - end end diff --git a/test/web/plugs/plug_test.exs b/test/pleroma/web/plugs/plug_helper_test.exs index 943e484e7..346113628 100644 --- a/test/web/plugs/plug_test.exs +++ b/test/pleroma/web/plugs/plug_helper_test.exs @@ -1,13 +1,13 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.Web.PlugTest do +defmodule Pleroma.Web.Plugs.PlugHelperTest do @moduledoc "Tests for the functionality added via `use Pleroma.Web, :plug`" - alias Pleroma.Plugs.ExpectAuthenticatedCheckPlug - alias Pleroma.Plugs.ExpectPublicOrAuthenticatedCheckPlug - alias Pleroma.Plugs.PlugHelper + alias Pleroma.Web.Plugs.ExpectAuthenticatedCheckPlug + alias Pleroma.Web.Plugs.ExpectPublicOrAuthenticatedCheckPlug + alias Pleroma.Web.Plugs.PlugHelper import Mock diff --git a/test/plugs/rate_limiter_test.exs b/test/pleroma/web/plugs/rate_limiter_test.exs index 4d3d694f4..b7cfde1f7 100644 --- a/test/plugs/rate_limiter_test.exs +++ b/test/pleroma/web/plugs/rate_limiter_test.exs @@ -1,13 +1,12 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.Plugs.RateLimiterTest do +defmodule Pleroma.Web.Plugs.RateLimiterTest do use Pleroma.Web.ConnCase alias Phoenix.ConnTest - alias Pleroma.Config - alias Pleroma.Plugs.RateLimiter + alias Pleroma.Web.Plugs.RateLimiter alias Plug.Conn import Pleroma.Factory @@ -19,11 +18,11 @@ defmodule Pleroma.Plugs.RateLimiterTest do describe "config" do @limiter_name :test_init - setup do: clear_config([Pleroma.Plugs.RemoteIp, :enabled]) + setup do: clear_config([Pleroma.Web.Plugs.RemoteIp, :enabled]) test "config is required for plug to work" do - Config.put([:rate_limit, @limiter_name], {1, 1}) - Config.put([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8}) + clear_config([:rate_limit, @limiter_name], {1, 1}) + clear_config([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8}) assert %{limits: {1, 1}, name: :test_init, opts: [name: :test_init]} == [name: @limiter_name] @@ -49,13 +48,14 @@ defmodule Pleroma.Plugs.RateLimiterTest do refute RateLimiter.disabled?(build_conn()) end + @tag :erratic test "it restricts based on config values" do limiter_name = :test_plug_opts scale = 80 limit = 5 - Config.put([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8}) - Config.put([:rate_limit, limiter_name], {scale, limit}) + clear_config([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8}) + clear_config([:rate_limit, limiter_name], {scale, limit}) plug_opts = RateLimiter.init(name: limiter_name) conn = build_conn(:get, "/") @@ -86,8 +86,8 @@ defmodule Pleroma.Plugs.RateLimiterTest do test "`bucket_name` option overrides default bucket name" do limiter_name = :test_bucket_name - Config.put([:rate_limit, limiter_name], {1000, 5}) - Config.put([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8}) + clear_config([:rate_limit, limiter_name], {1000, 5}) + clear_config([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8}) base_bucket_name = "#{limiter_name}:group1" plug_opts = RateLimiter.init(name: limiter_name, bucket_name: base_bucket_name) @@ -101,8 +101,8 @@ defmodule Pleroma.Plugs.RateLimiterTest do test "`params` option allows different queries to be tracked independently" do limiter_name = :test_params - Config.put([:rate_limit, limiter_name], {1000, 5}) - Config.put([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8}) + clear_config([:rate_limit, limiter_name], {1000, 5}) + clear_config([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8}) plug_opts = RateLimiter.init(name: limiter_name, params: ["id"]) @@ -117,8 +117,8 @@ defmodule Pleroma.Plugs.RateLimiterTest do test "it supports combination of options modifying bucket name" do limiter_name = :test_options_combo - Config.put([:rate_limit, limiter_name], {1000, 5}) - Config.put([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8}) + clear_config([:rate_limit, limiter_name], {1000, 5}) + clear_config([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8}) base_bucket_name = "#{limiter_name}:group1" @@ -138,10 +138,11 @@ defmodule Pleroma.Plugs.RateLimiterTest do end describe "unauthenticated users" do + @tag :erratic test "are restricted based on remote IP" do limiter_name = :test_unauthenticated - Config.put([:rate_limit, limiter_name], [{1000, 5}, {1, 10}]) - Config.put([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8}) + clear_config([:rate_limit, limiter_name], [{1000, 5}, {1, 10}]) + clear_config([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8}) plug_opts = RateLimiter.init(name: limiter_name) @@ -175,13 +176,14 @@ defmodule Pleroma.Plugs.RateLimiterTest do :ok end + @tag :erratic test "can have limits separate from unauthenticated connections" do limiter_name = :test_authenticated1 scale = 50 limit = 5 - Config.put([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8}) - Config.put([:rate_limit, limiter_name], [{1000, 1}, {scale, limit}]) + clear_config([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8}) + clear_config([:rate_limit, limiter_name], [{1000, 1}, {scale, limit}]) plug_opts = RateLimiter.init(name: limiter_name) @@ -200,10 +202,11 @@ defmodule Pleroma.Plugs.RateLimiterTest do assert conn.halted end + @tag :erratic test "different users are counted independently" do limiter_name = :test_authenticated2 - Config.put([:rate_limit, limiter_name], [{1, 10}, {1000, 5}]) - Config.put([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8}) + clear_config([:rate_limit, limiter_name], [{1, 10}, {1000, 5}]) + clear_config([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8}) plug_opts = RateLimiter.init(name: limiter_name) @@ -232,8 +235,8 @@ defmodule Pleroma.Plugs.RateLimiterTest do test "doesn't crash due to a race condition when multiple requests are made at the same time and the bucket is not yet initialized" do limiter_name = :test_race_condition - Pleroma.Config.put([:rate_limit, limiter_name], {1000, 5}) - Pleroma.Config.put([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8}) + clear_config([:rate_limit, limiter_name], {1000, 5}) + clear_config([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8}) opts = RateLimiter.init(name: limiter_name) diff --git a/test/pleroma/web/plugs/remote_ip_test.exs b/test/pleroma/web/plugs/remote_ip_test.exs new file mode 100644 index 000000000..4d98de2bd --- /dev/null +++ b/test/pleroma/web/plugs/remote_ip_test.exs @@ -0,0 +1,108 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.Plugs.RemoteIpTest do + use ExUnit.Case + use Plug.Test + + alias Pleroma.Web.Plugs.RemoteIp + + import Pleroma.Tests.Helpers, only: [clear_config: 2] + + setup do: + clear_config(RemoteIp, + enabled: true, + headers: ["x-forwarded-for"], + proxies: [], + reserved: [ + "127.0.0.0/8", + "::1/128", + "fc00::/7", + "10.0.0.0/8", + "172.16.0.0/12", + "192.168.0.0/16" + ] + ) + + test "disabled" do + clear_config(RemoteIp, enabled: false) + + %{remote_ip: remote_ip} = conn(:get, "/") + + conn = + conn(:get, "/") + |> put_req_header("x-forwarded-for", "1.1.1.1") + |> RemoteIp.call(nil) + + assert conn.remote_ip == remote_ip + end + + test "enabled" do + conn = + conn(:get, "/") + |> put_req_header("x-forwarded-for", "1.1.1.1") + |> RemoteIp.call(nil) + + assert conn.remote_ip == {1, 1, 1, 1} + end + + test "custom headers" do + clear_config(RemoteIp, enabled: true, headers: ["cf-connecting-ip"]) + + conn = + conn(:get, "/") + |> put_req_header("x-forwarded-for", "1.1.1.1") + |> RemoteIp.call(nil) + + refute conn.remote_ip == {1, 1, 1, 1} + + conn = + conn(:get, "/") + |> put_req_header("cf-connecting-ip", "1.1.1.1") + |> RemoteIp.call(nil) + + assert conn.remote_ip == {1, 1, 1, 1} + end + + test "custom proxies" do + conn = + conn(:get, "/") + |> put_req_header("x-forwarded-for", "173.245.48.1, 1.1.1.1, 173.245.48.2") + |> RemoteIp.call(nil) + + refute conn.remote_ip == {1, 1, 1, 1} + + clear_config([RemoteIp, :proxies], ["173.245.48.0/20"]) + + conn = + conn(:get, "/") + |> put_req_header("x-forwarded-for", "173.245.48.1, 1.1.1.1, 173.245.48.2") + |> RemoteIp.call(nil) + + assert conn.remote_ip == {1, 1, 1, 1} + end + + test "proxies set without CIDR format" do + clear_config([RemoteIp, :proxies], ["173.245.48.1"]) + + conn = + conn(:get, "/") + |> put_req_header("x-forwarded-for", "173.245.48.1, 1.1.1.1") + |> RemoteIp.call(nil) + + assert conn.remote_ip == {1, 1, 1, 1} + end + + test "proxies set `nonsensical` CIDR" do + clear_config([RemoteIp, :reserved], ["127.0.0.0/8"]) + clear_config([RemoteIp, :proxies], ["10.0.0.3/24"]) + + conn = + conn(:get, "/") + |> put_req_header("x-forwarded-for", "10.0.0.3, 1.1.1.1") + |> RemoteIp.call(nil) + + assert conn.remote_ip == {1, 1, 1, 1} + end +end diff --git a/test/plugs/set_format_plug_test.exs b/test/pleroma/web/plugs/set_format_plug_test.exs index 7a1dfe9bf..21043f698 100644 --- a/test/plugs/set_format_plug_test.exs +++ b/test/pleroma/web/plugs/set_format_plug_test.exs @@ -1,12 +1,12 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.Plugs.SetFormatPlugTest do +defmodule Pleroma.Web.Plugs.SetFormatPlugTest do use ExUnit.Case, async: true use Plug.Test - alias Pleroma.Plugs.SetFormatPlug + alias Pleroma.Web.Plugs.SetFormatPlug test "set format from params" do conn = diff --git a/test/plugs/set_locale_plug_test.exs b/test/pleroma/web/plugs/set_locale_plug_test.exs index 7114b1557..5261e67ae 100644 --- a/test/plugs/set_locale_plug_test.exs +++ b/test/pleroma/web/plugs/set_locale_plug_test.exs @@ -1,12 +1,12 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.Plugs.SetLocalePlugTest do +defmodule Pleroma.Web.Plugs.SetLocalePlugTest do use ExUnit.Case, async: true use Plug.Test - alias Pleroma.Plugs.SetLocalePlug + alias Pleroma.Web.Plugs.SetLocalePlug alias Plug.Conn test "default locale is `en`" do diff --git a/test/plugs/set_user_session_id_plug_test.exs b/test/pleroma/web/plugs/set_user_session_id_plug_test.exs index 7f1a1e98b..9814c80d8 100644 --- a/test/plugs/set_user_session_id_plug_test.exs +++ b/test/pleroma/web/plugs/set_user_session_id_plug_test.exs @@ -1,12 +1,12 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.Plugs.SetUserSessionIdPlugTest do +defmodule Pleroma.Web.Plugs.SetUserSessionIdPlugTest do use Pleroma.Web.ConnCase, async: true - alias Pleroma.Plugs.SetUserSessionIdPlug - alias Pleroma.User + alias Pleroma.Helpers.AuthHelper + alias Pleroma.Web.Plugs.SetUserSessionIdPlug setup %{conn: conn} do session_opts = [ @@ -18,28 +18,26 @@ defmodule Pleroma.Plugs.SetUserSessionIdPlugTest do conn = conn |> Plug.Session.call(Plug.Session.init(session_opts)) - |> fetch_session + |> fetch_session() %{conn: conn} end test "doesn't do anything if the user isn't set", %{conn: conn} do - ret_conn = - conn - |> SetUserSessionIdPlug.call(%{}) + ret_conn = SetUserSessionIdPlug.call(conn, %{}) assert ret_conn == conn end - test "sets the user_id in the session to the user id of the user assign", %{conn: conn} do - Code.ensure_compiled(Pleroma.User) + test "sets session token basing on :token assign", %{conn: conn} do + %{user: user, token: oauth_token} = oauth_access(["read"]) - conn = + ret_conn = conn - |> assign(:user, %User{id: 1}) + |> assign(:user, user) + |> assign(:token, oauth_token) |> SetUserSessionIdPlug.call(%{}) - id = get_session(conn, :user_id) - assert id == 1 + assert AuthHelper.get_session_token(ret_conn) == oauth_token.token end end diff --git a/test/plugs/uploaded_media_plug_test.exs b/test/pleroma/web/plugs/uploaded_media_plug_test.exs index 20b13dfac..75f313282 100644 --- a/test/plugs/uploaded_media_plug_test.exs +++ b/test/pleroma/web/plugs/uploaded_media_plug_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.Web.UploadedMediaPlugTest do - use Pleroma.Web.ConnCase +defmodule Pleroma.Web.Plugs.UploadedMediaPlugTest do + use Pleroma.Web.ConnCase, async: true alias Pleroma.Upload defp upload_file(context) do @@ -11,7 +11,7 @@ defmodule Pleroma.Web.UploadedMediaPlugTest do File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg") file = %Plug.Upload{ - content_type: "image/jpg", + content_type: "image/jpeg", path: Path.absname("test/fixtures/image_tmp.jpg"), filename: "nice_tf.jpg" } diff --git a/test/plugs/user_enabled_plug_test.exs b/test/pleroma/web/plugs/user_enabled_plug_test.exs index b219d8abf..999c6c49c 100644 --- a/test/plugs/user_enabled_plug_test.exs +++ b/test/pleroma/web/plugs/user_enabled_plug_test.exs @@ -1,11 +1,11 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.Plugs.UserEnabledPlugTest do - use Pleroma.Web.ConnCase, async: true +defmodule Pleroma.Web.Plugs.UserEnabledPlugTest do + use Pleroma.Web.ConnCase - alias Pleroma.Plugs.UserEnabledPlug + alias Pleroma.Web.Plugs.UserEnabledPlug import Pleroma.Factory setup do: clear_config([:instance, :account_activation_required]) @@ -20,9 +20,9 @@ defmodule Pleroma.Plugs.UserEnabledPlugTest do test "with a user that's not confirmed and a config requiring confirmation, it removes that user", %{conn: conn} do - Pleroma.Config.put([:instance, :account_activation_required], true) + clear_config([:instance, :account_activation_required], true) - user = insert(:user, confirmation_pending: true) + user = insert(:user, is_confirmed: false) conn = conn @@ -33,7 +33,7 @@ defmodule Pleroma.Plugs.UserEnabledPlugTest do end test "with a user that is deactivated, it removes that user", %{conn: conn} do - user = insert(:user, deactivated: true) + user = insert(:user, is_active: false) conn = conn diff --git a/test/plugs/user_fetcher_plug_test.exs b/test/pleroma/web/plugs/user_fetcher_plug_test.exs index 0496f14dd..902bee642 100644 --- a/test/plugs/user_fetcher_plug_test.exs +++ b/test/pleroma/web/plugs/user_fetcher_plug_test.exs @@ -1,11 +1,11 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.Plugs.UserFetcherPlugTest do +defmodule Pleroma.Web.Plugs.UserFetcherPlugTest do use Pleroma.Web.ConnCase, async: true - alias Pleroma.Plugs.UserFetcherPlug + alias Pleroma.Web.Plugs.UserFetcherPlug import Pleroma.Factory setup do diff --git a/test/plugs/user_is_admin_plug_test.exs b/test/pleroma/web/plugs/user_is_admin_plug_test.exs index 8bc00e444..58996d5a4 100644 --- a/test/plugs/user_is_admin_plug_test.exs +++ b/test/pleroma/web/plugs/user_is_admin_plug_test.exs @@ -1,11 +1,11 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.Plugs.UserIsAdminPlugTest do +defmodule Pleroma.Web.Plugs.UserIsAdminPlugTest do use Pleroma.Web.ConnCase, async: true - alias Pleroma.Plugs.UserIsAdminPlug + alias Pleroma.Web.Plugs.UserIsAdminPlug import Pleroma.Factory test "accepts a user that is an admin" do diff --git a/test/pleroma/web/plugs/user_is_staff_plug_test.exs b/test/pleroma/web/plugs/user_is_staff_plug_test.exs new file mode 100644 index 000000000..a0c4061db --- /dev/null +++ b/test/pleroma/web/plugs/user_is_staff_plug_test.exs @@ -0,0 +1,47 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.Plugs.UserIsStaffPlugTest do + use Pleroma.Web.ConnCase, async: true + + alias Pleroma.Web.Plugs.UserIsStaffPlug + import Pleroma.Factory + + test "accepts a user that is an admin" do + user = insert(:user, is_admin: true) + + conn = assign(build_conn(), :user, user) + + ret_conn = UserIsStaffPlug.call(conn, %{}) + + assert conn == ret_conn + end + + test "accepts a user that is a moderator" do + user = insert(:user, is_moderator: true) + + conn = assign(build_conn(), :user, user) + + ret_conn = UserIsStaffPlug.call(conn, %{}) + + assert conn == ret_conn + end + + test "denies a user that isn't a staff member" do + user = insert(:user) + + conn = + build_conn() + |> assign(:user, user) + |> UserIsStaffPlug.call(%{}) + + assert conn.status == 403 + end + + test "denies when a user isn't set" do + conn = UserIsStaffPlug.call(build_conn(), %{}) + + assert conn.status == 403 + end +end diff --git a/test/pleroma/web/plugs/user_tracking_plug_test.exs b/test/pleroma/web/plugs/user_tracking_plug_test.exs new file mode 100644 index 000000000..8e9d59b99 --- /dev/null +++ b/test/pleroma/web/plugs/user_tracking_plug_test.exs @@ -0,0 +1,58 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.Plugs.UserTrackingPlugTest do + use Pleroma.Web.ConnCase, async: true + + import Pleroma.Factory + + alias Pleroma.Web.Plugs.UserTrackingPlug + + test "updates last_active_at for a new user", %{conn: conn} do + user = insert(:user) + + assert is_nil(user.last_active_at) + + test_started_at = NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second) + + %{assigns: %{user: user}} = + conn + |> assign(:user, user) + |> UserTrackingPlug.call(%{}) + + assert user.last_active_at >= test_started_at + assert user.last_active_at <= NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second) + end + + test "doesn't update last_active_at if it was updated recently", %{conn: conn} do + last_active_at = + NaiveDateTime.utc_now() + |> NaiveDateTime.add(-:timer.hours(1), :millisecond) + |> NaiveDateTime.truncate(:second) + + user = insert(:user, %{last_active_at: last_active_at}) + + %{assigns: %{user: user}} = + conn + |> assign(:user, user) + |> UserTrackingPlug.call(%{}) + + assert user.last_active_at == last_active_at + end + + test "skips updating last_active_at if user ID is nil", %{conn: conn} do + %{assigns: %{user: user}} = + conn + |> assign(:user, %Pleroma.User{}) + |> UserTrackingPlug.call(%{}) + + assert is_nil(user.last_active_at) + end + + test "does nothing if user is not present", %{conn: conn} do + %{assigns: assigns} = UserTrackingPlug.call(conn, %{}) + + refute Map.has_key?(assigns, :user) + end +end diff --git a/test/web/preload/instance_test.exs b/test/pleroma/web/preload/providers/instance_test.exs index a46f28312..a401475ee 100644 --- a/test/web/preload/instance_test.exs +++ b/test/pleroma/web/preload/providers/instance_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.Preload.Providers.InstanceTest do @@ -45,4 +45,12 @@ defmodule Pleroma.Web.Preload.Providers.InstanceTest do assert metadata.private == false assert metadata.suggestions == %{enabled: false} end + + test "it renders the frontend configurations", %{ + "/api/pleroma/frontend_configurations" => fe_configs + } do + assert %{ + pleroma_fe: %{background: "/images/city.jpg", logo: "/static/logo.svg"} + } = fe_configs + end end diff --git a/test/web/preload/timeline_test.exs b/test/pleroma/web/preload/providers/timeline_test.exs index 3b1f2f1aa..2ae2ca5fb 100644 --- a/test/web/preload/timeline_test.exs +++ b/test/pleroma/web/preload/providers/timeline_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.Preload.Providers.TimelineTest do diff --git a/test/web/preload/user_test.exs b/test/pleroma/web/preload/providers/user_test.exs index 83f065e27..b7017ac20 100644 --- a/test/web/preload/user_test.exs +++ b/test/pleroma/web/preload/providers/user_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.Preload.Providers.UserTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true import Pleroma.Factory alias Pleroma.Web.Preload.Providers.User diff --git a/test/web/push/impl_test.exs b/test/pleroma/web/push/impl_test.exs index aeb5c1fbd..b3ca1a337 100644 --- a/test/web/push/impl_test.exs +++ b/test/pleroma/web/push/impl_test.exs @@ -1,9 +1,11 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.Push.ImplTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true + + import Pleroma.Factory alias Pleroma.Notification alias Pleroma.Object @@ -13,8 +15,6 @@ defmodule Pleroma.Web.Push.ImplTest do alias Pleroma.Web.Push.Impl alias Pleroma.Web.Push.Subscription - import Pleroma.Factory - setup do Tesla.Mock.mock(fn %{method: :post, url: "https://example.com/example/1234"} -> @@ -118,7 +118,7 @@ defmodule Pleroma.Web.Push.ImplTest do "<span>Lorem ipsum dolor sit amet</span>, consectetur :firefox: adipiscing elit. Fusce sagittis finibus turpis." }) - object = Object.normalize(activity) + object = Object.normalize(activity, fetch: false) assert Impl.format_body( %{ @@ -137,7 +137,7 @@ defmodule Pleroma.Web.Push.ImplTest do user = insert(:user, nickname: "Bob") other_user = insert(:user) {:ok, _, _, activity} = CommonAPI.follow(user, other_user) - object = Object.normalize(activity, false) + object = Object.normalize(activity, fetch: false) assert Impl.format_body(%{activity: activity, type: "follow"}, user, object) == "@Bob has followed you" @@ -156,7 +156,7 @@ defmodule Pleroma.Web.Push.ImplTest do }) {:ok, announce_activity} = CommonAPI.repeat(activity.id, user) - object = Object.normalize(activity) + object = Object.normalize(activity, fetch: false) assert Impl.format_body(%{activity: announce_activity}, user, object) == "@#{user.nickname} repeated: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce sagittis fini..." @@ -175,7 +175,7 @@ defmodule Pleroma.Web.Push.ImplTest do }) {:ok, activity} = CommonAPI.favorite(user, activity.id) - object = Object.normalize(activity) + object = Object.normalize(activity, fetch: false) assert Impl.format_body(%{activity: activity, type: "favourite"}, user, object) == "@Bob has favorited your post" @@ -184,6 +184,24 @@ defmodule Pleroma.Web.Push.ImplTest do "New Favorite" end + test "renders title and body for pleroma:emoji_reaction activity" do + user = insert(:user, nickname: "Bob") + + {:ok, activity} = + CommonAPI.post(user, %{ + status: "This post is a really good post!" + }) + + {:ok, activity} = CommonAPI.react_with_emoji(activity.id, user, "👍") + object = Object.normalize(activity, fetch: false) + + assert Impl.format_body(%{activity: activity, type: "pleroma:emoji_reaction"}, user, object) == + "@Bob reacted with 👍" + + assert Impl.format_title(%{activity: activity, type: "pleroma:emoji_reaction"}) == + "New Reaction" + end + test "renders title for create activity with direct visibility" do user = insert(:user, nickname: "Bob") @@ -203,7 +221,7 @@ defmodule Pleroma.Web.Push.ImplTest do recipient = insert(:user) {:ok, chat} = CommonAPI.post_chat_message(user, recipient, "hey") - object = Object.normalize(chat, false) + object = Object.normalize(chat, fetch: false) [notification] = Notification.for_user(recipient) res = Impl.build_content(notification, user, object) @@ -219,7 +237,7 @@ defmodule Pleroma.Web.Push.ImplTest do recipient = insert(:user) file = %Plug.Upload{ - content_type: "image/jpg", + content_type: "image/jpeg", path: Path.absname("test/fixtures/image.jpg"), filename: "an_image.jpg" } @@ -227,7 +245,7 @@ defmodule Pleroma.Web.Push.ImplTest do {:ok, upload} = ActivityPub.upload(file, actor: user.ap_id) {:ok, chat} = CommonAPI.post_chat_message(user, recipient, nil, media_id: upload.id) - object = Object.normalize(chat, false) + object = Object.normalize(chat, fetch: false) [notification] = Notification.for_user(recipient) res = Impl.build_content(notification, user, object) @@ -253,7 +271,7 @@ defmodule Pleroma.Web.Push.ImplTest do notif = insert(:notification, user: user2, activity: activity) actor = User.get_cached_by_ap_id(notif.activity.data["actor"]) - object = Object.normalize(activity) + object = Object.normalize(activity, fetch: false) assert Impl.build_content(notif, actor, object) == %{ body: "New Direct Message" @@ -268,7 +286,7 @@ defmodule Pleroma.Web.Push.ImplTest do notif = insert(:notification, user: user2, activity: activity, type: "mention") actor = User.get_cached_by_ap_id(notif.activity.data["actor"]) - object = Object.normalize(activity) + object = Object.normalize(activity, fetch: false) assert Impl.build_content(notif, actor, object) == %{ body: "New Mention" @@ -279,7 +297,7 @@ defmodule Pleroma.Web.Push.ImplTest do notif = insert(:notification, user: user2, activity: activity, type: "favourite") actor = User.get_cached_by_ap_id(notif.activity.data["actor"]) - object = Object.normalize(activity) + object = Object.normalize(activity, fetch: false) assert Impl.build_content(notif, actor, object) == %{ body: "New Favorite" @@ -302,7 +320,7 @@ defmodule Pleroma.Web.Push.ImplTest do notif = insert(:notification, user: user2, activity: activity) actor = User.get_cached_by_ap_id(notif.activity.data["actor"]) - object = Object.normalize(activity) + object = Object.normalize(activity, fetch: false) assert Impl.build_content(notif, actor, object) == %{ body: @@ -320,7 +338,7 @@ defmodule Pleroma.Web.Push.ImplTest do notif = insert(:notification, user: user2, activity: activity, type: "mention") actor = User.get_cached_by_ap_id(notif.activity.data["actor"]) - object = Object.normalize(activity) + object = Object.normalize(activity, fetch: false) assert Impl.build_content(notif, actor, object) == %{ body: @@ -333,7 +351,7 @@ defmodule Pleroma.Web.Push.ImplTest do notif = insert(:notification, user: user2, activity: activity, type: "favourite") actor = User.get_cached_by_ap_id(notif.activity.data["actor"]) - object = Object.normalize(activity) + object = Object.normalize(activity, fetch: false) assert Impl.build_content(notif, actor, object) == %{ body: "@Bob has favorited your post", diff --git a/test/web/rel_me_test.exs b/test/pleroma/web/rel_me_test.exs index 65255916d..313b163b5 100644 --- a/test/web/rel_me_test.exs +++ b/test/pleroma/web/rel_me_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.RelMeTest do - use ExUnit.Case + use Pleroma.DataCase setup_all do Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) diff --git a/test/web/rich_media/helpers_test.exs b/test/pleroma/web/rich_media/helpers_test.exs index 8264a9c41..689854fb6 100644 --- a/test/web/rich_media/helpers_test.exs +++ b/test/pleroma/web/rich_media/helpers_test.exs @@ -1,12 +1,10 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.RichMedia.HelpersTest do use Pleroma.DataCase - alias Pleroma.Config - alias Pleroma.Object alias Pleroma.Web.CommonAPI alias Pleroma.Web.RichMedia.Helpers @@ -30,7 +28,7 @@ defmodule Pleroma.Web.RichMedia.HelpersTest do content_type: "text/markdown" }) - Config.put([:rich_media, :enabled], true) + clear_config([:rich_media, :enabled], true) assert %{} == Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity) end @@ -44,7 +42,7 @@ defmodule Pleroma.Web.RichMedia.HelpersTest do content_type: "text/markdown" }) - Config.put([:rich_media, :enabled], true) + clear_config([:rich_media, :enabled], true) assert %{} == Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity) end @@ -58,47 +56,12 @@ defmodule Pleroma.Web.RichMedia.HelpersTest do content_type: "text/markdown" }) - Config.put([:rich_media, :enabled], true) + clear_config([:rich_media, :enabled], true) assert %{page_url: "https://example.com/ogp", rich_media: _} = Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity) end - test "refuses to crawl URLs from posts marked sensitive" do - user = insert(:user) - - {:ok, activity} = - CommonAPI.post(user, %{ - status: "http://example.com/ogp", - sensitive: true - }) - - %Object{} = object = Object.normalize(activity) - - assert object.data["sensitive"] - - Config.put([:rich_media, :enabled], true) - - assert %{} = Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity) - end - - test "refuses to crawl URLs from posts tagged NSFW" do - user = insert(:user) - - {:ok, activity} = - CommonAPI.post(user, %{ - status: "http://example.com/ogp #nsfw" - }) - - %Object{} = object = Object.normalize(activity) - - assert object.data["sensitive"] - - Config.put([:rich_media, :enabled], true) - - assert %{} = Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity) - end - test "refuses to crawl URLs of private network from posts" do user = insert(:user) @@ -110,7 +73,7 @@ defmodule Pleroma.Web.RichMedia.HelpersTest do {:ok, activity4} = CommonAPI.post(user, %{status: "https://192.168.10.40/notice/9kCP7V"}) {:ok, activity5} = CommonAPI.post(user, %{status: "https://pleroma.local/notice/9kCP7V"}) - Config.put([:rich_media, :enabled], true) + clear_config([:rich_media, :enabled], true) assert %{} = Helpers.fetch_data_for_activity(activity) assert %{} = Helpers.fetch_data_for_activity(activity2) diff --git a/test/web/rich_media/aws_signed_url_test.exs b/test/pleroma/web/rich_media/parser/ttl/aws_signed_url_test.exs index 1ceae1a31..0c8203417 100644 --- a/test/web/rich_media/aws_signed_url_test.exs +++ b/test/pleroma/web/rich_media/parser/ttl/aws_signed_url_test.exs @@ -1,9 +1,10 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.Web.RichMedia.TTL.AwsSignedUrlTest do - use ExUnit.Case, async: true +defmodule Pleroma.Web.RichMedia.Parser.TTL.AwsSignedUrlTest do + # Relies on Cachex, needs to be synchronous + use Pleroma.DataCase test "s3 signed url is parsed correct for expiration time" do url = "https://pleroma.social/amz" @@ -65,9 +66,7 @@ defmodule Pleroma.Web.RichMedia.TTL.AwsSignedUrlTest do end defp construct_s3_url(timestamp, valid_till) do - "https://pleroma.s3.ap-southeast-1.amazonaws.com/sachin%20%281%29%20_a%20-%25%2Aasdasd%20BNN%20bnnn%20.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIBLWWK6RGDQXDLJQ%2F20190716%2Fap-southeast-1%2Fs3%2Faws4_request&X-Amz-Date=#{ - timestamp - }&X-Amz-Expires=#{valid_till}&X-Amz-Signature=04ffd6b98634f4b1bbabc62e0fac4879093cd54a6eed24fe8eb38e8369526bbf&X-Amz-SignedHeaders=host" + "https://pleroma.s3.ap-southeast-1.amazonaws.com/sachin%20%281%29%20_a%20-%25%2Aasdasd%20BNN%20bnnn%20.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIBLWWK6RGDQXDLJQ%2F20190716%2Fap-southeast-1%2Fs3%2Faws4_request&X-Amz-Date=#{timestamp}&X-Amz-Expires=#{valid_till}&X-Amz-Signature=04ffd6b98634f4b1bbabc62e0fac4879093cd54a6eed24fe8eb38e8369526bbf&X-Amz-SignedHeaders=host" end defp construct_metadata(timestamp, valid_till, url) do diff --git a/test/web/rich_media/parser_test.exs b/test/pleroma/web/rich_media/parser_test.exs index 21ae35f8b..2f363b012 100644 --- a/test/web/rich_media/parser_test.exs +++ b/test/pleroma/web/rich_media/parser_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.RichMedia.ParserTest do @@ -56,6 +56,27 @@ defmodule Pleroma.Web.RichMedia.ParserTest do %{method: :get, url: "http://example.com/error"} -> {:error, :overload} + + %{ + method: :head, + url: "http://example.com/huge-page" + } -> + %Tesla.Env{ + status: 200, + headers: [{"content-length", "2000001"}, {"content-type", "text/html"}] + } + + %{ + method: :head, + url: "http://example.com/pdf-file" + } -> + %Tesla.Env{ + status: 200, + headers: [{"content-length", "1000000"}, {"content-type", "application/pdf"}] + } + + %{method: :head} -> + %Tesla.Env{status: 404, body: "", headers: []} end) :ok @@ -144,4 +165,12 @@ defmodule Pleroma.Web.RichMedia.ParserTest do test "returns error if getting page was not successful" do assert {:error, :overload} = Parser.parse("http://example.com/error") end + + test "does a HEAD request to check if the body is too large" do + assert {:error, :body_too_large} = Parser.parse("http://example.com/huge-page") + end + + test "does a HEAD request to check if the body is html" do + assert {:error, {:content_type, _}} = Parser.parse("http://example.com/pdf-file") + end end diff --git a/test/web/rich_media/parsers/twitter_card_test.exs b/test/pleroma/web/rich_media/parsers/twitter_card_test.exs index 219f005a2..2aacd29a3 100644 --- a/test/web/rich_media/parsers/twitter_card_test.exs +++ b/test/pleroma/web/rich_media/parsers/twitter_card_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.RichMedia.Parsers.TwitterCardTest do diff --git a/test/web/chat_channel_test.exs b/test/pleroma/web/shout_channel_test.exs index f18f3a212..5c86efe9f 100644 --- a/test/web/chat_channel_test.exs +++ b/test/pleroma/web/shout_channel_test.exs @@ -1,6 +1,10 @@ -defmodule Pleroma.Web.ChatChannelTest do +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ShoutChannelTest do use Pleroma.Web.ChannelCase - alias Pleroma.Web.ChatChannel + alias Pleroma.Web.ShoutChannel alias Pleroma.Web.UserSocket import Pleroma.Factory @@ -10,7 +14,7 @@ defmodule Pleroma.Web.ChatChannelTest do {:ok, _, socket} = socket(UserSocket, "", %{user_name: user.nickname}) - |> subscribe_and_join(ChatChannel, "chat:public") + |> subscribe_and_join(ShoutChannel, "chat:public") {:ok, socket: socket} end @@ -21,7 +25,7 @@ defmodule Pleroma.Web.ChatChannelTest do end describe "message lengths" do - setup do: clear_config([:instance, :chat_limit]) + setup do: clear_config([:shout, :limit]) test "it ignores messages of length zero", %{socket: socket} do push(socket, "new_msg", %{"text" => ""}) @@ -29,7 +33,7 @@ defmodule Pleroma.Web.ChatChannelTest do end test "it ignores messages above a certain length", %{socket: socket} do - Pleroma.Config.put([:instance, :chat_limit], 2) + clear_config([:shout, :limit], 2) push(socket, "new_msg", %{"text" => "123"}) refute_broadcast("new_msg", %{text: "123"}) end diff --git a/test/web/static_fe/static_fe_controller_test.exs b/test/pleroma/web/static_fe/static_fe_controller_test.exs index 1598bf675..5752cffda 100644 --- a/test/web/static_fe/static_fe_controller_test.exs +++ b/test/pleroma/web/static_fe/static_fe_controller_test.exs @@ -1,15 +1,18 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + defmodule Pleroma.Web.StaticFE.StaticFEControllerTest do use Pleroma.Web.ConnCase alias Pleroma.Activity - alias Pleroma.Config alias Pleroma.Web.ActivityPub.Transmogrifier + alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.CommonAPI import Pleroma.Factory setup_all do: clear_config([:static_fe, :enabled], true) - setup do: clear_config([:instance, :federating], true) setup %{conn: conn} do conn = put_req_header(conn, "accept", "text/html") @@ -70,8 +73,27 @@ defmodule Pleroma.Web.StaticFE.StaticFEControllerTest do refute html =~ ">test29<" end - test "it requires authentication if instance is NOT federating", %{conn: conn, user: user} do - ensure_federating_or_authenticated(conn, "/users/#{user.nickname}", user) + test "does not require authentication on non-federating instances", %{ + conn: conn, + user: user + } do + clear_config([:instance, :federating], false) + + conn = get(conn, "/users/#{user.nickname}") + + assert html_response(conn, 200) =~ user.nickname + end + + test "returns 404 for local user with `restrict_unauthenticated/profiles/local` setting", %{ + conn: conn + } do + clear_config([:restrict_unauthenticated, :profiles, :local], true) + + local_user = insert(:user, local: true) + + conn + |> get("/users/#{local_user.nickname}") + |> html_response(404) end end @@ -164,16 +186,16 @@ defmodule Pleroma.Web.StaticFE.StaticFEControllerTest do test "302 for remote cached status", %{conn: conn, user: user} do message = %{ "@context" => "https://www.w3.org/ns/activitystreams", - "to" => user.follower_address, - "cc" => "https://www.w3.org/ns/activitystreams#Public", "type" => "Create", + "actor" => user.ap_id, "object" => %{ + "to" => user.follower_address, + "cc" => "https://www.w3.org/ns/activitystreams#Public", + "id" => Utils.generate_object_id(), "content" => "blah blah blah", "type" => "Note", - "attributedTo" => user.ap_id, - "inReplyTo" => nil - }, - "actor" => user.ap_id + "attributedTo" => user.ap_id + } } assert {:ok, activity} = Transmogrifier.handle_incoming(message) @@ -183,10 +205,28 @@ defmodule Pleroma.Web.StaticFE.StaticFEControllerTest do assert html_response(conn, 302) =~ "redirected" end - test "it requires authentication if instance is NOT federating", %{conn: conn, user: user} do + test "does not require authentication on non-federating instances", %{ + conn: conn, + user: user + } do + clear_config([:instance, :federating], false) + + {:ok, activity} = CommonAPI.post(user, %{status: "testing a thing!"}) + + conn = get(conn, "/notice/#{activity.id}") + + assert html_response(conn, 200) =~ "testing a thing!" + end + + test "returns 404 for local public activity with `restrict_unauthenticated/activities/local` setting", + %{conn: conn, user: user} do + clear_config([:restrict_unauthenticated, :activities, :local], true) + {:ok, activity} = CommonAPI.post(user, %{status: "testing a thing!"}) - ensure_federating_or_authenticated(conn, "/notice/#{activity.id}", user) + conn + |> get("/notice/#{activity.id}") + |> html_response(404) end end end diff --git a/test/web/streamer/streamer_test.exs b/test/pleroma/web/streamer_test.exs index d56d74464..b2941a62c 100644 --- a/test/web/streamer/streamer_test.exs +++ b/test/pleroma/web/streamer_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.StreamerTest do @@ -21,92 +21,156 @@ defmodule Pleroma.Web.StreamerTest do setup do: clear_config([:instance, :skip_thread_containment]) - describe "get_topic without an user" do + describe "get_topic/_ (unauthenticated)" do test "allows public" do - assert {:ok, "public"} = Streamer.get_topic("public", nil) - assert {:ok, "public:local"} = Streamer.get_topic("public:local", nil) - assert {:ok, "public:media"} = Streamer.get_topic("public:media", nil) - assert {:ok, "public:local:media"} = Streamer.get_topic("public:local:media", nil) + assert {:ok, "public"} = Streamer.get_topic("public", nil, nil) + assert {:ok, "public:local"} = Streamer.get_topic("public:local", nil, nil) + assert {:ok, "public:media"} = Streamer.get_topic("public:media", nil, nil) + assert {:ok, "public:local:media"} = Streamer.get_topic("public:local:media", nil, nil) + end + + test "allows instance streams" do + assert {:ok, "public:remote:lain.com"} = + Streamer.get_topic("public:remote", nil, nil, %{"instance" => "lain.com"}) + + assert {:ok, "public:remote:media:lain.com"} = + Streamer.get_topic("public:remote:media", nil, nil, %{"instance" => "lain.com"}) end test "allows hashtag streams" do - assert {:ok, "hashtag:cofe"} = Streamer.get_topic("hashtag", nil, %{"tag" => "cofe"}) + assert {:ok, "hashtag:cofe"} = Streamer.get_topic("hashtag", nil, nil, %{"tag" => "cofe"}) end test "disallows user streams" do - assert {:error, _} = Streamer.get_topic("user", nil) - assert {:error, _} = Streamer.get_topic("user:notification", nil) - assert {:error, _} = Streamer.get_topic("direct", nil) + assert {:error, _} = Streamer.get_topic("user", nil, nil) + assert {:error, _} = Streamer.get_topic("user:notification", nil, nil) + assert {:error, _} = Streamer.get_topic("direct", nil, nil) end test "disallows list streams" do - assert {:error, _} = Streamer.get_topic("list", nil, %{"list" => 42}) + assert {:error, _} = Streamer.get_topic("list", nil, nil, %{"list" => 42}) end end - describe "get_topic with an user" do - setup do - user = insert(:user) - {:ok, %{user: user}} - end + describe "get_topic/_ (authenticated)" do + setup do: oauth_access(["read"]) + + test "allows public streams (regardless of OAuth token scopes)", %{ + user: user, + token: read_oauth_token + } do + with oauth_token <- [nil, read_oauth_token] do + assert {:ok, "public"} = Streamer.get_topic("public", user, oauth_token) + assert {:ok, "public:local"} = Streamer.get_topic("public:local", user, oauth_token) + assert {:ok, "public:media"} = Streamer.get_topic("public:media", user, oauth_token) - test "allows public streams", %{user: user} do - assert {:ok, "public"} = Streamer.get_topic("public", user) - assert {:ok, "public:local"} = Streamer.get_topic("public:local", user) - assert {:ok, "public:media"} = Streamer.get_topic("public:media", user) - assert {:ok, "public:local:media"} = Streamer.get_topic("public:local:media", user) + assert {:ok, "public:local:media"} = + Streamer.get_topic("public:local:media", user, oauth_token) + end end - test "allows user streams", %{user: user} do + test "allows user streams (with proper OAuth token scopes)", %{ + user: user, + token: read_oauth_token + } do + %{token: read_notifications_token} = oauth_access(["read:notifications"], user: user) + %{token: read_statuses_token} = oauth_access(["read:statuses"], user: user) + %{token: badly_scoped_token} = oauth_access(["irrelevant:scope"], user: user) + expected_user_topic = "user:#{user.id}" - expected_notif_topic = "user:notification:#{user.id}" + expected_notification_topic = "user:notification:#{user.id}" expected_direct_topic = "direct:#{user.id}" - assert {:ok, ^expected_user_topic} = Streamer.get_topic("user", user) - assert {:ok, ^expected_notif_topic} = Streamer.get_topic("user:notification", user) - assert {:ok, ^expected_direct_topic} = Streamer.get_topic("direct", user) + expected_pleroma_chat_topic = "user:pleroma_chat:#{user.id}" + + for valid_user_token <- [read_oauth_token, read_statuses_token] do + assert {:ok, ^expected_user_topic} = Streamer.get_topic("user", user, valid_user_token) + + assert {:ok, ^expected_direct_topic} = + Streamer.get_topic("direct", user, valid_user_token) + + assert {:ok, ^expected_pleroma_chat_topic} = + Streamer.get_topic("user:pleroma_chat", user, valid_user_token) + end + + for invalid_user_token <- [read_notifications_token, badly_scoped_token], + user_topic <- ["user", "direct", "user:pleroma_chat"] do + assert {:error, :unauthorized} = Streamer.get_topic(user_topic, user, invalid_user_token) + end + + for valid_notification_token <- [read_oauth_token, read_notifications_token] do + assert {:ok, ^expected_notification_topic} = + Streamer.get_topic("user:notification", user, valid_notification_token) + end + + for invalid_notification_token <- [read_statuses_token, badly_scoped_token] do + assert {:error, :unauthorized} = + Streamer.get_topic("user:notification", user, invalid_notification_token) + end end - test "allows hashtag streams", %{user: user} do - assert {:ok, "hashtag:cofe"} = Streamer.get_topic("hashtag", user, %{"tag" => "cofe"}) + test "allows hashtag streams (regardless of OAuth token scopes)", %{ + user: user, + token: read_oauth_token + } do + for oauth_token <- [nil, read_oauth_token] do + assert {:ok, "hashtag:cofe"} = + Streamer.get_topic("hashtag", user, oauth_token, %{"tag" => "cofe"}) + end end - test "disallows registering to an user stream", %{user: user} do + test "disallows registering to another user's stream", %{user: user, token: read_oauth_token} do another_user = insert(:user) - assert {:error, _} = Streamer.get_topic("user:#{another_user.id}", user) - assert {:error, _} = Streamer.get_topic("user:notification:#{another_user.id}", user) - assert {:error, _} = Streamer.get_topic("direct:#{another_user.id}", user) + assert {:error, _} = Streamer.get_topic("user:#{another_user.id}", user, read_oauth_token) + + assert {:error, _} = + Streamer.get_topic("user:notification:#{another_user.id}", user, read_oauth_token) + + assert {:error, _} = Streamer.get_topic("direct:#{another_user.id}", user, read_oauth_token) end - test "allows list stream that are owned by the user", %{user: user} do + test "allows list stream that are owned by the user (with `read` or `read:lists` scopes)", %{ + user: user, + token: read_oauth_token + } do + %{token: read_lists_token} = oauth_access(["read:lists"], user: user) + %{token: invalid_token} = oauth_access(["irrelevant:scope"], user: user) {:ok, list} = List.create("Test", user) - assert {:error, _} = Streamer.get_topic("list:#{list.id}", user) - assert {:ok, _} = Streamer.get_topic("list", user, %{"list" => list.id}) + + assert {:error, _} = Streamer.get_topic("list:#{list.id}", user, read_oauth_token) + + for valid_token <- [read_oauth_token, read_lists_token] do + assert {:ok, _} = Streamer.get_topic("list", user, valid_token, %{"list" => list.id}) + end + + assert {:error, _} = Streamer.get_topic("list", user, invalid_token, %{"list" => list.id}) end - test "disallows list stream that are not owned by the user", %{user: user} do + test "disallows list stream that are not owned by the user", %{user: user, token: oauth_token} do another_user = insert(:user) {:ok, list} = List.create("Test", another_user) - assert {:error, _} = Streamer.get_topic("list:#{list.id}", user) - assert {:error, _} = Streamer.get_topic("list", user, %{"list" => list.id}) + + assert {:error, _} = Streamer.get_topic("list:#{list.id}", user, oauth_token) + assert {:error, _} = Streamer.get_topic("list", user, oauth_token, %{"list" => list.id}) end end describe "user streams" do setup do - user = insert(:user) + %{user: user, token: token} = oauth_access(["read"]) notify = insert(:notification, user: user, activity: build(:note_activity)) - {:ok, %{user: user, notify: notify}} + {:ok, %{user: user, notify: notify, token: token}} end - test "it streams the user's post in the 'user' stream", %{user: user} do - Streamer.get_topic_and_add_socket("user", user) + test "it streams the user's post in the 'user' stream", %{user: user, token: oauth_token} do + Streamer.get_topic_and_add_socket("user", user, oauth_token) {:ok, activity} = CommonAPI.post(user, %{status: "hey"}) + assert_receive {:render_with_user, _, _, ^activity} refute Streamer.filtered_by_user?(user, activity) end - test "it streams boosts of the user in the 'user' stream", %{user: user} do - Streamer.get_topic_and_add_socket("user", user) + test "it streams boosts of the user in the 'user' stream", %{user: user, token: oauth_token} do + Streamer.get_topic_and_add_socket("user", user, oauth_token) other_user = insert(:user) {:ok, activity} = CommonAPI.post(other_user, %{status: "hey"}) @@ -117,9 +181,10 @@ defmodule Pleroma.Web.StreamerTest do end test "it does not stream announces of the user's own posts in the 'user' stream", %{ - user: user + user: user, + token: oauth_token } do - Streamer.get_topic_and_add_socket("user", user) + Streamer.get_topic_and_add_socket("user", user, oauth_token) other_user = insert(:user) {:ok, activity} = CommonAPI.post(user, %{status: "hey"}) @@ -129,9 +194,10 @@ defmodule Pleroma.Web.StreamerTest do end test "it does stream notifications announces of the user's own posts in the 'user' stream", %{ - user: user + user: user, + token: oauth_token } do - Streamer.get_topic_and_add_socket("user", user) + Streamer.get_topic_and_add_socket("user", user, oauth_token) other_user = insert(:user) {:ok, activity} = CommonAPI.post(user, %{status: "hey"}) @@ -145,15 +211,18 @@ defmodule Pleroma.Web.StreamerTest do refute Streamer.filtered_by_user?(user, notification) end - test "it streams boosts of mastodon user in the 'user' stream", %{user: user} do - Streamer.get_topic_and_add_socket("user", user) + test "it streams boosts of mastodon user in the 'user' stream", %{ + user: user, + token: oauth_token + } do + Streamer.get_topic_and_add_socket("user", user, oauth_token) other_user = insert(:user) {:ok, activity} = CommonAPI.post(other_user, %{status: "hey"}) data = File.read!("test/fixtures/mastodon-announce.json") - |> Poison.decode!() + |> Jason.decode!() |> Map.put("object", activity.data["object"]) |> Map.put("actor", user.ap_id) @@ -164,30 +233,45 @@ defmodule Pleroma.Web.StreamerTest do refute Streamer.filtered_by_user?(user, announce) end - test "it sends notify to in the 'user' stream", %{user: user, notify: notify} do - Streamer.get_topic_and_add_socket("user", user) + test "it sends notify to in the 'user' stream", %{ + user: user, + token: oauth_token, + notify: notify + } do + Streamer.get_topic_and_add_socket("user", user, oauth_token) Streamer.stream("user", notify) + assert_receive {:render_with_user, _, _, ^notify} refute Streamer.filtered_by_user?(user, notify) end - test "it sends notify to in the 'user:notification' stream", %{user: user, notify: notify} do - Streamer.get_topic_and_add_socket("user:notification", user) + test "it sends notify to in the 'user:notification' stream", %{ + user: user, + token: oauth_token, + notify: notify + } do + Streamer.get_topic_and_add_socket("user:notification", user, oauth_token) Streamer.stream("user:notification", notify) + assert_receive {:render_with_user, _, _, ^notify} refute Streamer.filtered_by_user?(user, notify) end - test "it sends chat messages to the 'user:pleroma_chat' stream", %{user: user} do + test "it sends chat messages to the 'user:pleroma_chat' stream", %{ + user: user, + token: oauth_token + } do other_user = insert(:user) - {:ok, create_activity} = CommonAPI.post_chat_message(other_user, user, "hey cirno") - object = Object.normalize(create_activity, false) + {:ok, create_activity} = + CommonAPI.post_chat_message(other_user, user, "hey cirno", idempotency_key: "123") + + object = Object.normalize(create_activity, fetch: false) chat = Chat.get(user.id, other_user.ap_id) cm_ref = MessageReference.for_chat_and_object(chat, object) cm_ref = %{cm_ref | chat: chat, object: object} - Streamer.get_topic_and_add_socket("user:pleroma_chat", user) + Streamer.get_topic_and_add_socket("user:pleroma_chat", user, oauth_token) Streamer.stream("user:pleroma_chat", {user, cm_ref}) text = StreamerView.render("chat_update.json", %{chat_message_reference: cm_ref}) @@ -196,16 +280,16 @@ defmodule Pleroma.Web.StreamerTest do assert_receive {:text, ^text} end - test "it sends chat messages to the 'user' stream", %{user: user} do + test "it sends chat messages to the 'user' stream", %{user: user, token: oauth_token} do other_user = insert(:user) {:ok, create_activity} = CommonAPI.post_chat_message(other_user, user, "hey cirno") - object = Object.normalize(create_activity, false) + object = Object.normalize(create_activity, fetch: false) chat = Chat.get(user.id, other_user.ap_id) cm_ref = MessageReference.for_chat_and_object(chat, object) cm_ref = %{cm_ref | chat: chat, object: object} - Streamer.get_topic_and_add_socket("user", user) + Streamer.get_topic_and_add_socket("user", user, oauth_token) Streamer.stream("user", {user, cm_ref}) text = StreamerView.render("chat_update.json", %{chat_message_reference: cm_ref}) @@ -214,7 +298,10 @@ defmodule Pleroma.Web.StreamerTest do assert_receive {:text, ^text} end - test "it sends chat message notifications to the 'user:notification' stream", %{user: user} do + test "it sends chat message notifications to the 'user:notification' stream", %{ + user: user, + token: oauth_token + } do other_user = insert(:user) {:ok, create_activity} = CommonAPI.post_chat_message(other_user, user, "hey") @@ -223,19 +310,21 @@ defmodule Pleroma.Web.StreamerTest do Repo.get_by(Pleroma.Notification, user_id: user.id, activity_id: create_activity.id) |> Repo.preload(:activity) - Streamer.get_topic_and_add_socket("user:notification", user) + Streamer.get_topic_and_add_socket("user:notification", user, oauth_token) Streamer.stream("user:notification", notify) + assert_receive {:render_with_user, _, _, ^notify} refute Streamer.filtered_by_user?(user, notify) end test "it doesn't send notify to the 'user:notification' stream when a user is blocked", %{ - user: user + user: user, + token: oauth_token } do blocked = insert(:user) {:ok, _user_relationship} = User.block(user, blocked) - Streamer.get_topic_and_add_socket("user:notification", user) + Streamer.get_topic_and_add_socket("user:notification", user, oauth_token) {:ok, activity} = CommonAPI.post(user, %{status: ":("}) {:ok, _} = CommonAPI.favorite(blocked, activity.id) @@ -244,14 +333,15 @@ defmodule Pleroma.Web.StreamerTest do end test "it doesn't send notify to the 'user:notification' stream when a thread is muted", %{ - user: user + user: user, + token: oauth_token } do user2 = insert(:user) {:ok, activity} = CommonAPI.post(user, %{status: "super hot take"}) {:ok, _} = CommonAPI.add_mute(user, activity) - Streamer.get_topic_and_add_socket("user:notification", user) + Streamer.get_topic_and_add_socket("user:notification", user, oauth_token) {:ok, favorite_activity} = CommonAPI.favorite(user2, activity.id) @@ -260,12 +350,13 @@ defmodule Pleroma.Web.StreamerTest do end test "it sends favorite to 'user:notification' stream'", %{ - user: user + user: user, + token: oauth_token } do user2 = insert(:user, %{ap_id: "https://hecking-lewd-place.com/user/meanie"}) {:ok, activity} = CommonAPI.post(user, %{status: "super hot take"}) - Streamer.get_topic_and_add_socket("user:notification", user) + Streamer.get_topic_and_add_socket("user:notification", user, oauth_token) {:ok, favorite_activity} = CommonAPI.favorite(user2, activity.id) assert_receive {:render_with_user, _, "notification.json", notif} @@ -274,13 +365,14 @@ defmodule Pleroma.Web.StreamerTest do end test "it doesn't send the 'user:notification' stream' when a domain is blocked", %{ - user: user + user: user, + token: oauth_token } do user2 = insert(:user, %{ap_id: "https://hecking-lewd-place.com/user/meanie"}) {:ok, user} = User.block_domain(user, "hecking-lewd-place.com") {:ok, activity} = CommonAPI.post(user, %{status: "super hot take"}) - Streamer.get_topic_and_add_socket("user:notification", user) + Streamer.get_topic_and_add_socket("user:notification", user, oauth_token) {:ok, favorite_activity} = CommonAPI.favorite(user2, activity.id) refute_receive _ @@ -288,75 +380,117 @@ defmodule Pleroma.Web.StreamerTest do end test "it sends follow activities to the 'user:notification' stream", %{ - user: user + user: user, + token: oauth_token } do - user_url = user.ap_id user2 = insert(:user) - body = - File.read!("test/fixtures/users_mock/localhost.json") - |> String.replace("{{nickname}}", user.nickname) - |> Jason.encode!() - - Tesla.Mock.mock_global(fn - %{method: :get, url: ^user_url} -> - %Tesla.Env{status: 200, body: body} - end) - - Streamer.get_topic_and_add_socket("user:notification", user) + Streamer.get_topic_and_add_socket("user:notification", user, oauth_token) {:ok, _follower, _followed, follow_activity} = CommonAPI.follow(user2, user) assert_receive {:render_with_user, _, "notification.json", notif} assert notif.activity.id == follow_activity.id refute Streamer.filtered_by_user?(user, notif) end + + test "it sends follow relationships updates to the 'user' stream", %{ + user: user, + token: oauth_token + } do + user_id = user.id + other_user = insert(:user) + other_user_id = other_user.id + + Streamer.get_topic_and_add_socket("user", user, oauth_token) + {:ok, _follower, _followed, _follow_activity} = CommonAPI.follow(user, other_user) + + assert_receive {:text, event} + + assert %{"event" => "pleroma:follow_relationships_update", "payload" => payload} = + Jason.decode!(event) + + assert %{ + "follower" => %{ + "follower_count" => 0, + "following_count" => 0, + "id" => ^user_id + }, + "following" => %{ + "follower_count" => 0, + "following_count" => 0, + "id" => ^other_user_id + }, + "state" => "follow_pending" + } = Jason.decode!(payload) + + assert_receive {:text, event} + + assert %{"event" => "pleroma:follow_relationships_update", "payload" => payload} = + Jason.decode!(event) + + assert %{ + "follower" => %{ + "follower_count" => 0, + "following_count" => 1, + "id" => ^user_id + }, + "following" => %{ + "follower_count" => 1, + "following_count" => 0, + "id" => ^other_user_id + }, + "state" => "follow_accept" + } = Jason.decode!(payload) + end end - test "it sends to public authenticated" do - user = insert(:user) - other_user = insert(:user) + describe "public streams" do + test "it sends to public (authenticated)" do + %{user: user, token: oauth_token} = oauth_access(["read"]) + other_user = insert(:user) - Streamer.get_topic_and_add_socket("public", other_user) + Streamer.get_topic_and_add_socket("public", user, oauth_token) - {:ok, activity} = CommonAPI.post(user, %{status: "Test"}) - assert_receive {:render_with_user, _, _, ^activity} - refute Streamer.filtered_by_user?(user, activity) - end + {:ok, activity} = CommonAPI.post(other_user, %{status: "Test"}) + assert_receive {:render_with_user, _, _, ^activity} + refute Streamer.filtered_by_user?(other_user, activity) + end - test "works for deletions" do - user = insert(:user) - other_user = insert(:user) - {:ok, activity} = CommonAPI.post(other_user, %{status: "Test"}) + test "it sends to public (unauthenticated)" do + user = insert(:user) - Streamer.get_topic_and_add_socket("public", user) + Streamer.get_topic_and_add_socket("public", nil, nil) - {:ok, _} = CommonAPI.delete(activity.id, other_user) - activity_id = activity.id - assert_receive {:text, event} - assert %{"event" => "delete", "payload" => ^activity_id} = Jason.decode!(event) - end + {:ok, activity} = CommonAPI.post(user, %{status: "Test"}) + activity_id = activity.id + assert_receive {:text, event} + assert %{"event" => "update", "payload" => payload} = Jason.decode!(event) + assert %{"id" => ^activity_id} = Jason.decode!(payload) - test "it sends to public unauthenticated" do - user = insert(:user) + {:ok, _} = CommonAPI.delete(activity.id, user) + assert_receive {:text, event} + assert %{"event" => "delete", "payload" => ^activity_id} = Jason.decode!(event) + end - Streamer.get_topic_and_add_socket("public", nil) + test "handles deletions" do + %{user: user, token: oauth_token} = oauth_access(["read"]) + other_user = insert(:user) + {:ok, activity} = CommonAPI.post(other_user, %{status: "Test"}) - {:ok, activity} = CommonAPI.post(user, %{status: "Test"}) - activity_id = activity.id - assert_receive {:text, event} - assert %{"event" => "update", "payload" => payload} = Jason.decode!(event) - assert %{"id" => ^activity_id} = Jason.decode!(payload) + Streamer.get_topic_and_add_socket("public", user, oauth_token) - {:ok, _} = CommonAPI.delete(activity.id, user) - assert_receive {:text, event} - assert %{"event" => "delete", "payload" => ^activity_id} = Jason.decode!(event) + {:ok, _} = CommonAPI.delete(activity.id, other_user) + activity_id = activity.id + assert_receive {:text, event} + assert %{"event" => "delete", "payload" => ^activity_id} = Jason.decode!(event) + end end - describe "thread_containment" do + describe "thread_containment/2" do test "it filters to user if recipients invalid and thread containment is enabled" do - Pleroma.Config.put([:instance, :skip_thread_containment], false) + clear_config([:instance, :skip_thread_containment], false) author = insert(:user) - user = insert(:user) + %{user: user, token: oauth_token} = oauth_access(["read"]) User.follow(user, author, :follow_accept) activity = @@ -368,16 +502,16 @@ defmodule Pleroma.Web.StreamerTest do ) ) - Streamer.get_topic_and_add_socket("public", user) + Streamer.get_topic_and_add_socket("public", user, oauth_token) Streamer.stream("public", activity) assert_receive {:render_with_user, _, _, ^activity} assert Streamer.filtered_by_user?(user, activity) end test "it sends message if recipients invalid and thread containment is disabled" do - Pleroma.Config.put([:instance, :skip_thread_containment], true) + clear_config([:instance, :skip_thread_containment], true) author = insert(:user) - user = insert(:user) + %{user: user, token: oauth_token} = oauth_access(["read"]) User.follow(user, author, :follow_accept) activity = @@ -389,7 +523,7 @@ defmodule Pleroma.Web.StreamerTest do ) ) - Streamer.get_topic_and_add_socket("public", user) + Streamer.get_topic_and_add_socket("public", user, oauth_token) Streamer.stream("public", activity) assert_receive {:render_with_user, _, _, ^activity} @@ -397,9 +531,10 @@ defmodule Pleroma.Web.StreamerTest do end test "it sends message if recipients invalid and thread containment is enabled but user's thread containment is disabled" do - Pleroma.Config.put([:instance, :skip_thread_containment], false) + clear_config([:instance, :skip_thread_containment], false) author = insert(:user) user = insert(:user, skip_thread_containment: true) + %{token: oauth_token} = oauth_access(["read"], user: user) User.follow(user, author, :follow_accept) activity = @@ -411,7 +546,7 @@ defmodule Pleroma.Web.StreamerTest do ) ) - Streamer.get_topic_and_add_socket("public", user) + Streamer.get_topic_and_add_socket("public", user, oauth_token) Streamer.stream("public", activity) assert_receive {:render_with_user, _, _, ^activity} @@ -420,23 +555,26 @@ defmodule Pleroma.Web.StreamerTest do end describe "blocks" do - test "it filters messages involving blocked users" do - user = insert(:user) + setup do: oauth_access(["read"]) + + test "it filters messages involving blocked users", %{user: user, token: oauth_token} do blocked_user = insert(:user) {:ok, _user_relationship} = User.block(user, blocked_user) - Streamer.get_topic_and_add_socket("public", user) + Streamer.get_topic_and_add_socket("public", user, oauth_token) {:ok, activity} = CommonAPI.post(blocked_user, %{status: "Test"}) assert_receive {:render_with_user, _, _, ^activity} assert Streamer.filtered_by_user?(user, activity) end - test "it filters messages transitively involving blocked users" do - blocker = insert(:user) + test "it filters messages transitively involving blocked users", %{ + user: blocker, + token: blocker_token + } do blockee = insert(:user) friend = insert(:user) - Streamer.get_topic_and_add_socket("public", blocker) + Streamer.get_topic_and_add_socket("public", blocker, blocker_token) {:ok, _user_relationship} = User.block(blocker, blockee) @@ -458,17 +596,18 @@ defmodule Pleroma.Web.StreamerTest do end describe "lists" do - test "it doesn't send unwanted DMs to list" do - user_a = insert(:user) + setup do: oauth_access(["read"]) + + test "it doesn't send unwanted DMs to list", %{user: user_a, token: user_a_token} do user_b = insert(:user) user_c = insert(:user) - {:ok, user_a} = User.follow(user_a, user_b) + {:ok, user_a, user_b} = User.follow(user_a, user_b) {:ok, list} = List.create("Test", user_a) {:ok, list} = List.follow(list, user_b) - Streamer.get_topic_and_add_socket("list", user_a, %{"list" => list.id}) + Streamer.get_topic_and_add_socket("list", user_a, user_a_token, %{"list" => list.id}) {:ok, _activity} = CommonAPI.post(user_b, %{ @@ -479,14 +618,13 @@ defmodule Pleroma.Web.StreamerTest do refute_receive _ end - test "it doesn't send unwanted private posts to list" do - user_a = insert(:user) + test "it doesn't send unwanted private posts to list", %{user: user_a, token: user_a_token} do user_b = insert(:user) {:ok, list} = List.create("Test", user_a) {:ok, list} = List.follow(list, user_b) - Streamer.get_topic_and_add_socket("list", user_a, %{"list" => list.id}) + Streamer.get_topic_and_add_socket("list", user_a, user_a_token, %{"list" => list.id}) {:ok, _activity} = CommonAPI.post(user_b, %{ @@ -497,16 +635,15 @@ defmodule Pleroma.Web.StreamerTest do refute_receive _ end - test "it sends wanted private posts to list" do - user_a = insert(:user) + test "it sends wanted private posts to list", %{user: user_a, token: user_a_token} do user_b = insert(:user) - {:ok, user_a} = User.follow(user_a, user_b) + {:ok, user_a, user_b} = User.follow(user_a, user_b) {:ok, list} = List.create("Test", user_a) {:ok, list} = List.follow(list, user_b) - Streamer.get_topic_and_add_socket("list", user_a, %{"list" => list.id}) + Streamer.get_topic_and_add_socket("list", user_a, user_a_token, %{"list" => list.id}) {:ok, activity} = CommonAPI.post(user_b, %{ @@ -520,8 +657,9 @@ defmodule Pleroma.Web.StreamerTest do end describe "muted reblogs" do - test "it filters muted reblogs" do - user1 = insert(:user) + setup do: oauth_access(["read"]) + + test "it filters muted reblogs", %{user: user1, token: user1_token} do user2 = insert(:user) user3 = insert(:user) CommonAPI.follow(user1, user2) @@ -529,34 +667,38 @@ defmodule Pleroma.Web.StreamerTest do {:ok, create_activity} = CommonAPI.post(user3, %{status: "I'm kawen"}) - Streamer.get_topic_and_add_socket("user", user1) + Streamer.get_topic_and_add_socket("user", user1, user1_token) {:ok, announce_activity} = CommonAPI.repeat(create_activity.id, user2) assert_receive {:render_with_user, _, _, ^announce_activity} assert Streamer.filtered_by_user?(user1, announce_activity) end - test "it filters reblog notification for reblog-muted actors" do - user1 = insert(:user) + test "it filters reblog notification for reblog-muted actors", %{ + user: user1, + token: user1_token + } do user2 = insert(:user) CommonAPI.follow(user1, user2) CommonAPI.hide_reblogs(user1, user2) {:ok, create_activity} = CommonAPI.post(user1, %{status: "I'm kawen"}) - Streamer.get_topic_and_add_socket("user", user1) + Streamer.get_topic_and_add_socket("user", user1, user1_token) {:ok, _announce_activity} = CommonAPI.repeat(create_activity.id, user2) assert_receive {:render_with_user, _, "notification.json", notif} assert Streamer.filtered_by_user?(user1, notif) end - test "it send non-reblog notification for reblog-muted actors" do - user1 = insert(:user) + test "it send non-reblog notification for reblog-muted actors", %{ + user: user1, + token: user1_token + } do user2 = insert(:user) CommonAPI.follow(user1, user2) CommonAPI.hide_reblogs(user1, user2) {:ok, create_activity} = CommonAPI.post(user1, %{status: "I'm kawen"}) - Streamer.get_topic_and_add_socket("user", user1) + Streamer.get_topic_and_add_socket("user", user1, user1_token) {:ok, _favorite_activity} = CommonAPI.favorite(user2, create_activity.id) assert_receive {:render_with_user, _, "notification.json", notif} @@ -564,27 +706,28 @@ defmodule Pleroma.Web.StreamerTest do end end - test "it filters posts from muted threads" do - user = insert(:user) - user2 = insert(:user) - Streamer.get_topic_and_add_socket("user", user2) - {:ok, user2, user, _activity} = CommonAPI.follow(user2, user) - {:ok, activity} = CommonAPI.post(user, %{status: "super hot take"}) - {:ok, _} = CommonAPI.add_mute(user2, activity) - assert_receive {:render_with_user, _, _, ^activity} - assert Streamer.filtered_by_user?(user2, activity) + describe "muted threads" do + test "it filters posts from muted threads" do + user = insert(:user) + %{user: user2, token: user2_token} = oauth_access(["read"]) + Streamer.get_topic_and_add_socket("user", user2, user2_token) + + {:ok, user2, user, _activity} = CommonAPI.follow(user2, user) + {:ok, activity} = CommonAPI.post(user, %{status: "super hot take"}) + {:ok, _} = CommonAPI.add_mute(user2, activity) + + assert_receive {:render_with_user, _, _, ^activity} + assert Streamer.filtered_by_user?(user2, activity) + end end describe "direct streams" do - setup do - :ok - end + setup do: oauth_access(["read"]) - test "it sends conversation update to the 'direct' stream", %{} do - user = insert(:user) + test "it sends conversation update to the 'direct' stream", %{user: user, token: oauth_token} do another_user = insert(:user) - Streamer.get_topic_and_add_socket("direct", user) + Streamer.get_topic_and_add_socket("direct", user, oauth_token) {:ok, _create_activity} = CommonAPI.post(another_user, %{ @@ -602,11 +745,11 @@ defmodule Pleroma.Web.StreamerTest do assert last_status["pleroma"]["direct_conversation_id"] == participation.id end - test "it doesn't send conversation update to the 'direct' stream when the last message in the conversation is deleted" do - user = insert(:user) + test "it doesn't send conversation update to the 'direct' stream when the last message in the conversation is deleted", + %{user: user, token: oauth_token} do another_user = insert(:user) - Streamer.get_topic_and_add_socket("direct", user) + Streamer.get_topic_and_add_socket("direct", user, oauth_token) {:ok, create_activity} = CommonAPI.post(another_user, %{ @@ -629,10 +772,13 @@ defmodule Pleroma.Web.StreamerTest do refute_receive _ end - test "it sends conversation update to the 'direct' stream when a message is deleted" do - user = insert(:user) + @tag :erratic + test "it sends conversation update to the 'direct' stream when a message is deleted", %{ + user: user, + token: oauth_token + } do another_user = insert(:user) - Streamer.get_topic_and_add_socket("direct", user) + Streamer.get_topic_and_add_socket("direct", user, oauth_token) {:ok, create_activity} = CommonAPI.post(another_user, %{ diff --git a/test/web/twitter_api/twitter_api_controller_test.exs b/test/pleroma/web/twitter_api/controller_test.exs index 464d0ea2e..bca9e2dad 100644 --- a/test/web/twitter_api/twitter_api_controller_test.exs +++ b/test/pleroma/web/twitter_api/controller_test.exs @@ -1,75 +1,24 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.TwitterAPI.ControllerTest do - use Pleroma.Web.ConnCase + use Pleroma.Web.ConnCase, async: true - alias Pleroma.Builders.ActivityBuilder alias Pleroma.Repo alias Pleroma.User alias Pleroma.Web.OAuth.Token import Pleroma.Factory - describe "POST /api/qvitter/statuses/notifications/read" do - test "without valid credentials", %{conn: conn} do - conn = post(conn, "/api/qvitter/statuses/notifications/read", %{"latest_id" => 1_234_567}) - assert json_response(conn, 403) == %{"error" => "Invalid credentials."} - end - - test "with credentials, without any params" do - %{conn: conn} = oauth_access(["write:notifications"]) - - conn = post(conn, "/api/qvitter/statuses/notifications/read") - - assert json_response(conn, 400) == %{ - "error" => "You need to specify latest_id", - "request" => "/api/qvitter/statuses/notifications/read" - } - end - - test "with credentials, with params" do - %{user: current_user, conn: conn} = - oauth_access(["read:notifications", "write:notifications"]) - - other_user = insert(:user) - - {:ok, _activity} = - ActivityBuilder.insert(%{"to" => [current_user.ap_id]}, %{user: other_user}) - - response_conn = - conn - |> assign(:user, current_user) - |> get("/api/v1/notifications") - - [notification] = response = json_response(response_conn, 200) - - assert length(response) == 1 - - assert notification["pleroma"]["is_seen"] == false - - response_conn = - conn - |> assign(:user, current_user) - |> post("/api/qvitter/statuses/notifications/read", %{"latest_id" => notification["id"]}) - - [notification] = response = json_response(response_conn, 200) - - assert length(response) == 1 - - assert notification["pleroma"]["is_seen"] == true - end - end - describe "GET /api/account/confirm_email/:id/:token" do setup do {:ok, user} = insert(:user) - |> User.confirmation_changeset(need_confirmation: true) + |> User.confirmation_changeset(set_confirmation: false) |> Repo.update() - assert user.confirmation_pending + refute user.is_confirmed [user: user] end @@ -85,7 +34,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do user = User.get_cached_by_id(user.id) - refute user.confirmation_pending + assert user.is_confirmed refute user.confirmation_token end diff --git a/test/pleroma/web/twitter_api/password_controller_test.exs b/test/pleroma/web/twitter_api/password_controller_test.exs new file mode 100644 index 000000000..45ab10a8a --- /dev/null +++ b/test/pleroma/web/twitter_api/password_controller_test.exs @@ -0,0 +1,213 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.TwitterAPI.PasswordControllerTest do + use Pleroma.Web.ConnCase + + alias Pleroma.Config + alias Pleroma.PasswordResetToken + alias Pleroma.Repo + alias Pleroma.Tests.ObanHelpers + alias Pleroma.User + alias Pleroma.Web.OAuth.Token + import Pleroma.Factory + import Swoosh.TestAssertions + + describe "GET /api/pleroma/password_reset/token" do + test "it returns error when token invalid", %{conn: conn} do + response = + conn + |> get("/api/pleroma/password_reset/token") + |> html_response(:ok) + + assert response =~ "<h2>Invalid Token</h2>" + end + + test "it shows password reset form", %{conn: conn} do + user = insert(:user) + {:ok, token} = PasswordResetToken.create_token(user) + + response = + conn + |> get("/api/pleroma/password_reset/#{token.token}") + |> html_response(:ok) + + assert response =~ "<h2>Password Reset for #{user.nickname}</h2>" + end + + test "it returns an error when the token has expired", %{conn: conn} do + clear_config([:instance, :password_reset_token_validity], 0) + + user = insert(:user) + {:ok, token} = PasswordResetToken.create_token(user) + {:ok, token} = time_travel(token, -2) + + response = + conn + |> get("/api/pleroma/password_reset/#{token.token}") + |> html_response(:ok) + + assert response =~ "<h2>Invalid Token</h2>" + end + end + + describe "POST /api/pleroma/password_reset" do + test "it fails for an expired token", %{conn: conn} do + clear_config([:instance, :password_reset_token_validity], 0) + + user = insert(:user) + {:ok, token} = PasswordResetToken.create_token(user) + {:ok, token} = time_travel(token, -2) + {:ok, _access_token} = Token.create(insert(:oauth_app), user, %{}) + + params = %{ + "password" => "test", + password_confirmation: "test", + token: token.token + } + + response = + conn + |> assign(:user, user) + |> post("/api/pleroma/password_reset", %{data: params}) + |> html_response(:ok) + + refute response =~ "<h2>Password changed!</h2>" + end + + test "it returns HTTP 200", %{conn: conn} do + user = insert(:user) + {:ok, token} = PasswordResetToken.create_token(user) + {:ok, _access_token} = Token.create(insert(:oauth_app), user, %{}) + + params = %{ + "password" => "test", + password_confirmation: "test", + token: token.token + } + + response = + conn + |> assign(:user, user) + |> post("/api/pleroma/password_reset", %{data: params}) + |> html_response(:ok) + + assert response =~ "<h2>Password changed!</h2>" + + user = refresh_record(user) + assert Pleroma.Password.Pbkdf2.verify_pass("test", user.password_hash) + assert Enum.empty?(Token.get_user_tokens(user)) + end + + test "it sets password_reset_pending to false", %{conn: conn} do + user = insert(:user, password_reset_pending: true) + + {:ok, token} = PasswordResetToken.create_token(user) + {:ok, _access_token} = Token.create(insert(:oauth_app), user, %{}) + + params = %{ + "password" => "test", + password_confirmation: "test", + token: token.token + } + + conn + |> assign(:user, user) + |> post("/api/pleroma/password_reset", %{data: params}) + |> html_response(:ok) + + assert User.get_by_id(user.id).password_reset_pending == false + end + end + + describe "POST /auth/password, with valid parameters" do + setup %{conn: conn} do + user = insert(:user) + conn = post(conn, "/auth/password?email=#{user.email}") + %{conn: conn, user: user} + end + + test "it returns 204", %{conn: conn} do + assert empty_json_response(conn) + end + + test "it creates a PasswordResetToken record for user", %{user: user} do + token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id) + assert token_record + end + + test "it sends an email to user", %{user: user} do + ObanHelpers.perform_all() + token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id) + + email = Pleroma.Emails.UserEmail.password_reset_email(user, token_record.token) + notify_email = Config.get([:instance, :notify_email]) + instance_name = Config.get([:instance, :name]) + + assert_email_sent( + from: {instance_name, notify_email}, + to: {user.name, user.email}, + html_body: email.html_body + ) + end + end + + describe "POST /auth/password, with nickname" do + test "it returns 204", %{conn: conn} do + user = insert(:user) + + assert conn + |> post("/auth/password?nickname=#{user.nickname}") + |> empty_json_response() + + ObanHelpers.perform_all() + token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id) + + email = Pleroma.Emails.UserEmail.password_reset_email(user, token_record.token) + notify_email = Config.get([:instance, :notify_email]) + instance_name = Config.get([:instance, :name]) + + assert_email_sent( + from: {instance_name, notify_email}, + to: {user.name, user.email}, + html_body: email.html_body + ) + end + + test "it doesn't fail when a user has no email", %{conn: conn} do + user = insert(:user, %{email: nil}) + + assert conn + |> post("/auth/password?nickname=#{user.nickname}") + |> empty_json_response() + end + end + + describe "POST /auth/password, with invalid parameters" do + setup do + user = insert(:user) + {:ok, user: user} + end + + test "it returns 204 when user is not found", %{conn: conn, user: user} do + conn = post(conn, "/auth/password?email=nonexisting_#{user.email}") + + assert empty_json_response(conn) + end + + test "it returns 204 when user is not local", %{conn: conn, user: user} do + {:ok, user} = Repo.update(Ecto.Changeset.change(user, local: false)) + conn = post(conn, "/auth/password?email=#{user.email}") + + assert empty_json_response(conn) + end + + test "it returns 204 when user is deactivated", %{conn: conn, user: user} do + {:ok, user} = Repo.update(Ecto.Changeset.change(user, is_active: false, local: true)) + conn = post(conn, "/auth/password?email=#{user.email}") + + assert empty_json_response(conn) + end + end +end diff --git a/test/web/twitter_api/remote_follow_controller_test.exs b/test/pleroma/web/twitter_api/remote_follow_controller_test.exs index f7e54c26a..fa3b29006 100644 --- a/test/web/twitter_api/remote_follow_controller_test.exs +++ b/test/pleroma/web/twitter_api/remote_follow_controller_test.exs @@ -1,11 +1,10 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.TwitterAPI.RemoteFollowControllerTest do use Pleroma.Web.ConnCase - alias Pleroma.Config alias Pleroma.MFA alias Pleroma.MFA.TOTP alias Pleroma.User @@ -15,18 +14,37 @@ defmodule Pleroma.Web.TwitterAPI.RemoteFollowControllerTest do import Pleroma.Factory import Ecto.Query - setup do - Tesla.Mock.mock(fn env -> apply(HttpRequestMock, :request, [env]) end) - :ok - end - setup_all do: clear_config([:instance, :federating], true) - setup do: clear_config([:instance]) - setup do: clear_config([:frontend_configurations, :pleroma_fe]) setup do: clear_config([:user, :deny_follow_blocked]) describe "GET /ostatus_subscribe - remote_follow/2" do test "adds status to pleroma instance if the `acct` is a status", %{conn: conn} do + Tesla.Mock.mock(fn + %{method: :get, url: "https://mastodon.social/users/emelie/statuses/101849165031453009"} -> + %Tesla.Env{ + status: 200, + headers: [{"content-type", "application/activity+json"}], + body: File.read!("test/fixtures/tesla_mock/status.emelie.json") + } + + %{method: :get, url: "https://mastodon.social/users/emelie/collections/featured"} -> + %Tesla.Env{ + status: 200, + headers: [{"content-type", "application/activity+json"}], + body: + File.read!("test/fixtures/users_mock/masto_featured.json") + |> String.replace("{{domain}}", "mastodon.social") + |> String.replace("{{nickname}}", "emelie") + } + + %{method: :get, url: "https://mastodon.social/users/emelie"} -> + %Tesla.Env{ + status: 200, + headers: [{"content-type", "application/activity+json"}], + body: File.read!("test/fixtures/tesla_mock/emelie.json") + } + end) + assert conn |> get( remote_follow_path(conn, :follow, %{ @@ -37,6 +55,25 @@ defmodule Pleroma.Web.TwitterAPI.RemoteFollowControllerTest do end test "show follow account page if the `acct` is a account link", %{conn: conn} do + Tesla.Mock.mock(fn + %{method: :get, url: "https://mastodon.social/users/emelie"} -> + %Tesla.Env{ + status: 200, + headers: [{"content-type", "application/activity+json"}], + body: File.read!("test/fixtures/tesla_mock/emelie.json") + } + + %{method: :get, url: "https://mastodon.social/users/emelie/collections/featured"} -> + %Tesla.Env{ + status: 200, + headers: [{"content-type", "application/activity+json"}], + body: + File.read!("test/fixtures/users_mock/masto_featured.json") + |> String.replace("{{domain}}", "mastodon.social") + |> String.replace("{{nickname}}", "emelie") + } + end) + response = conn |> get(remote_follow_path(conn, :follow, %{acct: "https://mastodon.social/users/emelie"})) @@ -46,6 +83,25 @@ defmodule Pleroma.Web.TwitterAPI.RemoteFollowControllerTest do end test "show follow page if the `acct` is a account link", %{conn: conn} do + Tesla.Mock.mock(fn + %{method: :get, url: "https://mastodon.social/users/emelie"} -> + %Tesla.Env{ + status: 200, + headers: [{"content-type", "application/activity+json"}], + body: File.read!("test/fixtures/tesla_mock/emelie.json") + } + + %{method: :get, url: "https://mastodon.social/users/emelie/collections/featured"} -> + %Tesla.Env{ + status: 200, + headers: [{"content-type", "application/activity+json"}], + body: + File.read!("test/fixtures/users_mock/masto_featured.json") + |> String.replace("{{domain}}", "mastodon.social") + |> String.replace("{{nickname}}", "emelie") + } + end) + user = insert(:user) response = @@ -57,7 +113,14 @@ defmodule Pleroma.Web.TwitterAPI.RemoteFollowControllerTest do assert response =~ "Remote follow" end - test "show follow page with error when user cannot fecth by `acct` link", %{conn: conn} do + test "show follow page with error when user can not be fetched by `acct` link", %{conn: conn} do + Tesla.Mock.mock(fn + %{method: :get, url: "https://mastodon.social/users/not_found"} -> + %Tesla.Env{ + status: 404 + } + end) + user = insert(:user) assert capture_log(fn -> @@ -108,7 +171,7 @@ defmodule Pleroma.Web.TwitterAPI.RemoteFollowControllerTest do end test "returns error when user is deactivated", %{conn: conn} do - user = insert(:user, deactivated: true) + user = insert(:user, is_active: false) user2 = insert(:user) response = @@ -121,7 +184,7 @@ defmodule Pleroma.Web.TwitterAPI.RemoteFollowControllerTest do end test "returns error when user is blocked", %{conn: conn} do - Pleroma.Config.put([:user, :deny_follow_blocked], true) + clear_config([:user, :deny_follow_blocked], true) user = insert(:user) user2 = insert(:user) @@ -227,7 +290,7 @@ defmodule Pleroma.Web.TwitterAPI.RemoteFollowControllerTest do } ) - {:ok, %{token: token}} = MFA.Token.create_token(user) + {:ok, %{token: token}} = MFA.Token.create(user) user2 = insert(:user) otp_token = TOTP.generate_token(otp_secret) @@ -256,7 +319,7 @@ defmodule Pleroma.Web.TwitterAPI.RemoteFollowControllerTest do } ) - {:ok, %{token: token}} = MFA.Token.create_token(user) + {:ok, %{token: token}} = MFA.Token.create(user) user2 = insert(:user) otp_token = TOTP.generate_token(TOTP.generate_secret()) @@ -332,7 +395,7 @@ defmodule Pleroma.Web.TwitterAPI.RemoteFollowControllerTest do end test "returns error when user is blocked", %{conn: conn} do - Pleroma.Config.put([:user, :deny_follow_blocked], true) + clear_config([:user, :deny_follow_blocked], true) user = insert(:user) user2 = insert(:user) {:ok, _user_block} = Pleroma.User.block(user2, user) diff --git a/test/web/twitter_api/twitter_api_test.exs b/test/pleroma/web/twitter_api/twitter_api_test.exs index 20a45cb6f..2b8a4c3f5 100644 --- a/test/web/twitter_api/twitter_api_test.exs +++ b/test/pleroma/web/twitter_api/twitter_api_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do @@ -46,12 +46,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do end test "it sends confirmation email if :account_activation_required is specified in instance config" do - setting = Pleroma.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) - end + clear_config([:instance, :account_activation_required], true) data = %{ :username => "lain", @@ -65,7 +60,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do {:ok, user} = TwitterAPI.register_user(data) ObanHelpers.perform_all() - assert user.confirmation_pending + refute user.is_confirmed email = Pleroma.Emails.UserEmail.account_confirmation_email(user) @@ -80,13 +75,9 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do end test "it sends an admin email if :account_approval_required is specified in instance config" do - admin = insert(:user, is_admin: true) - setting = Pleroma.Config.get([:instance, :account_approval_required]) + clear_config([:instance, :account_approval_required], true) - unless setting do - Pleroma.Config.put([:instance, :account_approval_required], true) - on_exit(fn -> Pleroma.Config.put([:instance, :account_approval_required], setting) end) - end + admin = insert(:user, is_admin: true) data = %{ :username => "lain", @@ -101,17 +92,26 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do {:ok, user} = TwitterAPI.register_user(data) ObanHelpers.perform_all() - assert user.approval_pending + refute user.is_approved - email = Pleroma.Emails.AdminEmail.new_unapproved_registration(admin, user) + user_email = Pleroma.Emails.UserEmail.approval_pending_email(user) + admin_email = Pleroma.Emails.AdminEmail.new_unapproved_registration(admin, user) notify_email = Pleroma.Config.get([:instance, :notify_email]) instance_name = Pleroma.Config.get([:instance, :name]) + # User approval email + Swoosh.TestAssertions.assert_email_sent( + from: {instance_name, notify_email}, + to: {user.name, user.email}, + html_body: user_email.html_body + ) + + # Admin email Swoosh.TestAssertions.assert_email_sent( from: {instance_name, notify_email}, to: {admin.name, admin.email}, - html_body: email.html_body + html_body: admin_email.html_body ) end @@ -139,9 +139,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do {:ok, user2} = TwitterAPI.register_user(data2) expected_text = - ~s(<span class="h-card"><a class="u-url mention" data-user="#{user1.id}" href="#{ - user1.ap_id - }" rel="ugc">@<span>john</span></a></span> test) + ~s(<span class="h-card"><a class="u-url mention" data-user="#{user1.id}" href="#{user1.ap_id}" rel="ugc">@<span>john</span></a></span> test) assert user2.bio == expected_text end @@ -423,10 +421,4 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do assert is_binary(error) refute User.get_cached_by_nickname("lain") end - - setup do - Supervisor.terminate_child(Pleroma.Supervisor, Cachex) - Supervisor.restart_child(Pleroma.Supervisor, Cachex) - :ok - end end diff --git a/test/web/twitter_api/util_controller_test.exs b/test/pleroma/web/twitter_api/util_controller_test.exs index d164127ee..ee658ddf6 100644 --- a/test/web/twitter_api/util_controller_test.exs +++ b/test/pleroma/web/twitter_api/util_controller_test.exs @@ -1,12 +1,11 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do use Pleroma.Web.ConnCase use Oban.Testing, repo: Pleroma.Repo - alias Pleroma.Config alias Pleroma.Tests.ObanHelpers alias Pleroma.User @@ -21,180 +20,15 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do setup do: clear_config([:instance]) setup do: clear_config([:frontend_configurations, :pleroma_fe]) - describe "POST /api/pleroma/follow_import" do - setup do: oauth_access(["follow"]) - - test "it returns HTTP 200", %{conn: conn} do - user2 = insert(:user) - - response = - conn - |> post("/api/pleroma/follow_import", %{"list" => "#{user2.ap_id}"}) - |> json_response(:ok) - - assert response == "job started" - end - - test "it imports follow lists from file", %{user: user1, conn: conn} do - user2 = insert(:user) - - with_mocks([ - {File, [], - read!: fn "follow_list.txt" -> - "Account address,Show boosts\n#{user2.ap_id},true" - end} - ]) do - response = - conn - |> post("/api/pleroma/follow_import", %{"list" => %Plug.Upload{path: "follow_list.txt"}}) - |> json_response(:ok) - - assert response == "job started" - - assert ObanHelpers.member?( - %{ - "op" => "follow_import", - "follower_id" => user1.id, - "followed_identifiers" => [user2.ap_id] - }, - all_enqueued(worker: Pleroma.Workers.BackgroundWorker) - ) - end - end - - test "it imports new-style mastodon follow lists", %{conn: conn} do - user2 = insert(:user) - - response = - conn - |> post("/api/pleroma/follow_import", %{ - "list" => "Account address,Show boosts\n#{user2.ap_id},true" - }) - |> json_response(:ok) - - assert response == "job started" - end - - test "requires 'follow' or 'write:follows' permissions" do - token1 = insert(:oauth_token, scopes: ["read", "write"]) - token2 = insert(:oauth_token, scopes: ["follow"]) - token3 = insert(:oauth_token, scopes: ["something"]) - another_user = insert(:user) - - for token <- [token1, token2, token3] do - conn = - build_conn() - |> put_req_header("authorization", "Bearer #{token.token}") - |> post("/api/pleroma/follow_import", %{"list" => "#{another_user.ap_id}"}) - - if token == token3 do - assert %{"error" => "Insufficient permissions: follow | write:follows."} == - json_response(conn, 403) - else - assert json_response(conn, 200) - end - end - end - - test "it imports follows with different nickname variations", %{conn: conn} do - [user2, user3, user4, user5, user6] = insert_list(5, :user) - - identifiers = - [ - user2.ap_id, - user3.nickname, - " ", - "@" <> user4.nickname, - user5.nickname <> "@localhost", - "@" <> user6.nickname <> "@localhost" - ] - |> Enum.join("\n") - - response = - conn - |> post("/api/pleroma/follow_import", %{"list" => identifiers}) - |> json_response(:ok) - - assert response == "job started" - assert [{:ok, job_result}] = ObanHelpers.perform_all() - assert job_result == [user2, user3, user4, user5, user6] - end - end - - describe "POST /api/pleroma/blocks_import" do - # Note: "follow" or "write:blocks" permission is required - setup do: oauth_access(["write:blocks"]) - - test "it returns HTTP 200", %{conn: conn} do - user2 = insert(:user) - - response = - conn - |> post("/api/pleroma/blocks_import", %{"list" => "#{user2.ap_id}"}) - |> json_response(:ok) - - assert response == "job started" - end - - test "it imports blocks users from file", %{user: user1, conn: conn} do - user2 = insert(:user) - user3 = insert(:user) - - with_mocks([ - {File, [], read!: fn "blocks_list.txt" -> "#{user2.ap_id} #{user3.ap_id}" end} - ]) do - response = - conn - |> post("/api/pleroma/blocks_import", %{"list" => %Plug.Upload{path: "blocks_list.txt"}}) - |> json_response(:ok) - - assert response == "job started" - - assert ObanHelpers.member?( - %{ - "op" => "blocks_import", - "blocker_id" => user1.id, - "blocked_identifiers" => [user2.ap_id, user3.ap_id] - }, - all_enqueued(worker: Pleroma.Workers.BackgroundWorker) - ) - end - end - - test "it imports blocks with different nickname variations", %{conn: conn} do - [user2, user3, user4, user5, user6] = insert_list(5, :user) - - identifiers = - [ - user2.ap_id, - user3.nickname, - "@" <> user4.nickname, - user5.nickname <> "@localhost", - "@" <> user6.nickname <> "@localhost" - ] - |> Enum.join(" ") - - response = - conn - |> post("/api/pleroma/blocks_import", %{"list" => identifiers}) - |> json_response(:ok) - - assert response == "job started" - assert [{:ok, job_result}] = ObanHelpers.perform_all() - assert job_result == [user2, user3, user4, user5, user6] - end - end - describe "PUT /api/pleroma/notification_settings" do setup do: oauth_access(["write:accounts"]) test "it updates notification settings", %{user: user, conn: conn} do conn - |> put("/api/pleroma/notification_settings", %{ - "block_from_strangers" => true, - "bar" => 1 - }) - |> json_response(:ok) + |> put( + "/api/pleroma/notification_settings?#{URI.encode_query(%{block_from_strangers: true})}" + ) + |> json_response_and_validate_schema(:ok) user = refresh_record(user) @@ -206,8 +40,10 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do test "it updates notification settings to enable hiding contents", %{user: user, conn: conn} do conn - |> put("/api/pleroma/notification_settings", %{"hide_notification_contents" => "1"}) - |> json_response(:ok) + |> put( + "/api/pleroma/notification_settings?#{URI.encode_query(%{hide_notification_contents: 1})}" + ) + |> json_response_and_validate_schema(:ok) user = refresh_record(user) @@ -230,12 +66,12 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do } ] - Config.put(:frontend_configurations, config) + clear_config(:frontend_configurations, config) response = conn |> get("/api/pleroma/frontend_configurations") - |> json_response(:ok) + |> json_response_and_validate_schema(:ok) assert response == Jason.encode!(config |> Enum.into(%{})) |> Jason.decode!() end @@ -246,7 +82,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do emoji = conn |> get("/api/pleroma/emoji") - |> json_response(200) + |> json_response_and_validate_schema(200) assert Enum.all?(emoji, fn {_key, @@ -263,25 +99,25 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do setup do: clear_config([:instance, :healthcheck]) test "returns 503 when healthcheck disabled", %{conn: conn} do - Config.put([:instance, :healthcheck], false) + clear_config([:instance, :healthcheck], false) response = conn |> get("/api/pleroma/healthcheck") - |> json_response(503) + |> json_response_and_validate_schema(503) assert response == %{} end test "returns 200 when healthcheck enabled and all ok", %{conn: conn} do - Config.put([:instance, :healthcheck], true) + clear_config([:instance, :healthcheck], true) with_mock Pleroma.Healthcheck, system_info: fn -> %Pleroma.Healthcheck{healthy: true} end do response = conn |> get("/api/pleroma/healthcheck") - |> json_response(200) + |> json_response_and_validate_schema(200) assert %{ "active" => _, @@ -294,14 +130,14 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do end test "returns 503 when healthcheck enabled and health is false", %{conn: conn} do - Config.put([:instance, :healthcheck], true) + clear_config([:instance, :healthcheck], true) with_mock Pleroma.Healthcheck, system_info: fn -> %Pleroma.Healthcheck{healthy: false} end do response = conn |> get("/api/pleroma/healthcheck") - |> json_response(503) + |> json_response_and_validate_schema(503) assert %{ "active" => _, @@ -320,15 +156,15 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do test "with valid permissions and password, it disables the account", %{conn: conn, user: user} do response = conn - |> post("/api/pleroma/disable_account", %{"password" => "test"}) - |> json_response(:ok) + |> post("/api/pleroma/disable_account?password=test") + |> json_response_and_validate_schema(:ok) assert response == %{"status" => "success"} ObanHelpers.perform_all() user = User.get_cached_by_id(user.id) - assert user.deactivated == true + refute user.is_active end test "with valid permissions and invalid password, it returns an error", %{conn: conn} do @@ -336,13 +172,13 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do response = conn - |> post("/api/pleroma/disable_account", %{"password" => "test1"}) - |> json_response(:ok) + |> post("/api/pleroma/disable_account?password=test1") + |> json_response_and_validate_schema(:ok) assert response == %{"error" => "Invalid password."} user = User.get_cached_by_id(user.id) - refute user.deactivated + assert user.is_active end end @@ -417,54 +253,93 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do conn = conn |> assign(:token, nil) - |> post("/api/pleroma/change_email") + |> put_req_header("content-type", "multipart/form-data") + |> post("/api/pleroma/change_email", %{password: "hi", email: "test@test.com"}) - assert json_response(conn, 403) == %{"error" => "Insufficient permissions: write:accounts."} + assert json_response_and_validate_schema(conn, 403) == %{ + "error" => "Insufficient permissions: write:accounts." + } end test "with proper permissions and invalid password", %{conn: conn} do conn = - post(conn, "/api/pleroma/change_email", %{ - "password" => "hi", - "email" => "test@test.com" - }) + conn + |> put_req_header("content-type", "multipart/form-data") + |> post("/api/pleroma/change_email", %{password: "hi", email: "test@test.com"}) - assert json_response(conn, 200) == %{"error" => "Invalid password."} + assert json_response_and_validate_schema(conn, 200) == %{"error" => "Invalid password."} end test "with proper permissions, valid password and invalid email", %{ conn: conn } do conn = - post(conn, "/api/pleroma/change_email", %{ - "password" => "test", - "email" => "foobar" - }) + conn + |> put_req_header("content-type", "multipart/form-data") + |> post("/api/pleroma/change_email", %{password: "test", email: "foobar"}) - assert json_response(conn, 200) == %{"error" => "Email has invalid format."} + assert json_response_and_validate_schema(conn, 200) == %{ + "error" => "Email has invalid format." + } end test "with proper permissions, valid password and no email", %{ conn: conn } do conn = - post(conn, "/api/pleroma/change_email", %{ - "password" => "test" - }) + conn + |> put_req_header("content-type", "multipart/form-data") + |> post("/api/pleroma/change_email", %{password: "test"}) - assert json_response(conn, 200) == %{"error" => "Email can't be blank."} + assert %{"error" => "Missing field: email."} = json_response_and_validate_schema(conn, 400) end - test "with proper permissions, valid password and blank email", %{ - conn: conn - } do + test "with proper permissions, valid password and blank email, when instance requires user email", + %{ + conn: conn + } do + orig_account_activation_required = + Pleroma.Config.get([:instance, :account_activation_required]) + + Pleroma.Config.put([:instance, :account_activation_required], true) + + on_exit(fn -> + Pleroma.Config.put( + [:instance, :account_activation_required], + orig_account_activation_required + ) + end) + conn = - post(conn, "/api/pleroma/change_email", %{ - "password" => "test", - "email" => "" - }) + conn + |> put_req_header("content-type", "multipart/form-data") + |> post("/api/pleroma/change_email", %{password: "test", email: ""}) + + assert json_response_and_validate_schema(conn, 200) == %{"error" => "Email can't be blank."} + end + + test "with proper permissions, valid password and blank email, when instance does not require user email", + %{ + conn: conn + } do + orig_account_activation_required = + Pleroma.Config.get([:instance, :account_activation_required]) + + Pleroma.Config.put([:instance, :account_activation_required], false) + + on_exit(fn -> + Pleroma.Config.put( + [:instance, :account_activation_required], + orig_account_activation_required + ) + end) + + conn = + conn + |> put_req_header("content-type", "multipart/form-data") + |> post("/api/pleroma/change_email", %{password: "test", email: ""}) - assert json_response(conn, 200) == %{"error" => "Email can't be blank."} + assert json_response_and_validate_schema(conn, 200) == %{"status" => "success"} end test "with proper permissions, valid password and non unique email", %{ @@ -473,24 +348,24 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do user = insert(:user) conn = - post(conn, "/api/pleroma/change_email", %{ - "password" => "test", - "email" => user.email - }) + conn + |> put_req_header("content-type", "multipart/form-data") + |> post("/api/pleroma/change_email", %{password: "test", email: user.email}) - assert json_response(conn, 200) == %{"error" => "Email has already been taken."} + assert json_response_and_validate_schema(conn, 200) == %{ + "error" => "Email has already been taken." + } end test "with proper permissions, valid password and valid email", %{ conn: conn } do conn = - post(conn, "/api/pleroma/change_email", %{ - "password" => "test", - "email" => "cofe@foobar.com" - }) + conn + |> put_req_header("content-type", "multipart/form-data") + |> post("/api/pleroma/change_email", %{password: "test", email: "cofe@foobar.com"}) - assert json_response(conn, 200) == %{"status" => "success"} + assert json_response_and_validate_schema(conn, 200) == %{"status" => "success"} end end @@ -501,20 +376,29 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do conn = conn |> assign(:token, nil) - |> post("/api/pleroma/change_password") + |> put_req_header("content-type", "multipart/form-data") + |> post("/api/pleroma/change_password", %{ + "password" => "hi", + "new_password" => "newpass", + "new_password_confirmation" => "newpass" + }) - assert json_response(conn, 403) == %{"error" => "Insufficient permissions: write:accounts."} + assert json_response_and_validate_schema(conn, 403) == %{ + "error" => "Insufficient permissions: write:accounts." + } end test "with proper permissions and invalid password", %{conn: conn} do conn = - post(conn, "/api/pleroma/change_password", %{ + conn + |> put_req_header("content-type", "multipart/form-data") + |> post("/api/pleroma/change_password", %{ "password" => "hi", "new_password" => "newpass", "new_password_confirmation" => "newpass" }) - assert json_response(conn, 200) == %{"error" => "Invalid password."} + assert json_response_and_validate_schema(conn, 200) == %{"error" => "Invalid password."} end test "with proper permissions, valid password and new password and confirmation not matching", @@ -522,13 +406,15 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do conn: conn } do conn = - post(conn, "/api/pleroma/change_password", %{ + conn + |> put_req_header("content-type", "multipart/form-data") + |> post("/api/pleroma/change_password", %{ "password" => "test", "new_password" => "newpass", "new_password_confirmation" => "notnewpass" }) - assert json_response(conn, 200) == %{ + assert json_response_and_validate_schema(conn, 200) == %{ "error" => "New password does not match confirmation." } end @@ -537,13 +423,15 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do conn: conn } do conn = - post(conn, "/api/pleroma/change_password", %{ - "password" => "test", - "new_password" => "", - "new_password_confirmation" => "" + conn + |> put_req_header("content-type", "multipart/form-data") + |> post("/api/pleroma/change_password", %{ + password: "test", + new_password: "", + new_password_confirmation: "" }) - assert json_response(conn, 200) == %{ + assert json_response_and_validate_schema(conn, 200) == %{ "error" => "New password can't be blank." } end @@ -553,15 +441,20 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do user: user } do conn = - post(conn, "/api/pleroma/change_password", %{ - "password" => "test", - "new_password" => "newpass", - "new_password_confirmation" => "newpass" - }) - - assert json_response(conn, 200) == %{"status" => "success"} + conn + |> put_req_header("content-type", "multipart/form-data") + |> post( + "/api/pleroma/change_password", + %{ + password: "test", + new_password: "newpass", + new_password_confirmation: "newpass" + } + ) + + assert json_response_and_validate_schema(conn, 200) == %{"status" => "success"} fetched_user = User.get_cached_by_id(user.id) - assert Pbkdf2.verify_pass("newpass", fetched_user.password_hash) == true + assert Pleroma.Password.Pbkdf2.verify_pass("newpass", fetched_user.password_hash) == true end end @@ -574,25 +467,50 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do |> assign(:token, nil) |> post("/api/pleroma/delete_account") - assert json_response(conn, 403) == + assert json_response_and_validate_schema(conn, 403) == %{"error" => "Insufficient permissions: write:accounts."} end test "with proper permissions and wrong or missing password", %{conn: conn} do for params <- [%{"password" => "hi"}, %{}] do - ret_conn = post(conn, "/api/pleroma/delete_account", params) + ret_conn = + conn + |> put_req_header("content-type", "application/json") + |> post("/api/pleroma/delete_account", params) - assert json_response(ret_conn, 200) == %{"error" => "Invalid password."} + assert json_response_and_validate_schema(ret_conn, 200) == %{ + "error" => "Invalid password." + } end end - test "with proper permissions and valid password", %{conn: conn, user: user} do - conn = post(conn, "/api/pleroma/delete_account", %{"password" => "test"}) + test "with proper permissions and valid password (URL query)", %{conn: conn, user: user} do + conn = + conn + |> put_req_header("content-type", "application/json") + |> post("/api/pleroma/delete_account?password=test") + + ObanHelpers.perform_all() + assert json_response_and_validate_schema(conn, 200) == %{"status" => "success"} + + user = User.get_by_id(user.id) + refute user.is_active + assert user.name == nil + assert user.bio == "" + assert user.password_hash == nil + end + + test "with proper permissions and valid password (JSON body)", %{conn: conn, user: user} do + conn = + conn + |> put_req_header("content-type", "application/json") + |> post("/api/pleroma/delete_account", %{password: "test"}) + ObanHelpers.perform_all() - assert json_response(conn, 200) == %{"status" => "success"} + assert json_response_and_validate_schema(conn, 200) == %{"status" => "success"} user = User.get_by_id(user.id) - assert user.deactivated == true + refute user.is_active assert user.name == nil assert user.bio == "" assert user.password_hash == nil diff --git a/test/web/uploader_controller_test.exs b/test/pleroma/web/uploader_controller_test.exs index 21e518236..fc278004e 100644 --- a/test/web/uploader_controller_test.exs +++ b/test/pleroma/web/uploader_controller_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.UploaderControllerTest do - use Pleroma.Web.ConnCase + use Pleroma.Web.ConnCase, async: true alias Pleroma.Uploaders.Uploader describe "callback/2" do diff --git a/test/web/views/error_view_test.exs b/test/pleroma/web/views/error_view_test.exs index 8dbbd18b4..42da8f458 100644 --- a/test/web/views/error_view_test.exs +++ b/test/pleroma/web/views/error_view_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ErrorViewTest do diff --git a/test/web/web_finger/web_finger_controller_test.exs b/test/pleroma/web/web_finger/web_finger_controller_test.exs index 0023f1e81..66d79320f 100644 --- a/test/web/web_finger/web_finger_controller_test.exs +++ b/test/pleroma/web/web_finger/web_finger_controller_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.WebFinger.WebFingerControllerTest do @@ -24,20 +24,28 @@ defmodule Pleroma.Web.WebFinger.WebFingerControllerTest do assert response.status == 200 assert response.resp_body == - ~s(<?xml version="1.0" encoding="UTF-8"?><XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0"><Link rel="lrdd" template="#{ - Pleroma.Web.base_url() - }/.well-known/webfinger?resource={uri}" type="application/xrd+xml" /></XRD>) + ~s(<?xml version="1.0" encoding="UTF-8"?><XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0"><Link rel="lrdd" template="#{Pleroma.Web.Endpoint.url()}/.well-known/webfinger?resource={uri}" type="application/xrd+xml" /></XRD>) end test "Webfinger JRD" do - user = insert(:user) + user = + insert(:user, + ap_id: "https://hyrule.world/users/zelda", + also_known_as: ["https://mushroom.kingdom/users/toad"] + ) response = build_conn() |> put_req_header("accept", "application/jrd+json") |> get("/.well-known/webfinger?resource=acct:#{user.nickname}@localhost") + |> json_response(200) + + assert response["subject"] == "acct:#{user.nickname}@localhost" - assert json_response(response, 200)["subject"] == "acct:#{user.nickname}@localhost" + assert response["aliases"] == [ + "https://hyrule.world/users/zelda", + "https://mushroom.kingdom/users/toad" + ] end test "it returns 404 when user isn't found (JSON)" do @@ -51,14 +59,20 @@ defmodule Pleroma.Web.WebFinger.WebFingerControllerTest do end test "Webfinger XML" do - user = insert(:user) + user = + insert(:user, + ap_id: "https://hyrule.world/users/zelda", + also_known_as: ["https://mushroom.kingdom/users/toad"] + ) response = build_conn() |> put_req_header("accept", "application/xrd+xml") |> get("/.well-known/webfinger?resource=acct:#{user.nickname}@localhost") + |> response(200) - assert response(response, 200) + assert response =~ "<Alias>https://hyrule.world/users/zelda</Alias>" + assert response =~ "<Alias>https://mushroom.kingdom/users/toad</Alias>" end test "it returns 404 when user isn't found (XML)" do diff --git a/test/web/web_finger/web_finger_test.exs b/test/pleroma/web/web_finger_test.exs index 96fc0bbaa..0a36d57e6 100644 --- a/test/web/web_finger/web_finger_test.exs +++ b/test/pleroma/web/web_finger_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.WebFingerTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true alias Pleroma.Web.WebFinger import Pleroma.Factory import Tesla.Mock @@ -17,7 +17,7 @@ defmodule Pleroma.Web.WebFingerTest do test "returns a link to the xml lrdd" do host_info = WebFinger.host_meta() - assert String.contains?(host_info, Pleroma.Web.base_url()) + assert String.contains?(host_info, Pleroma.Web.Endpoint.url()) end end @@ -45,6 +45,26 @@ defmodule Pleroma.Web.WebFingerTest do assert {:error, _} = WebFinger.finger("pleroma.social") end + test "returns error when there is no content-type header" do + Tesla.Mock.mock(fn + %{url: "http://social.heldscal.la/.well-known/host-meta"} -> + {:ok, + %Tesla.Env{ + status: 200, + body: File.read!("test/fixtures/tesla_mock/social.heldscal.la_host_meta") + }} + + %{ + url: + "https://social.heldscal.la/.well-known/webfinger?resource=acct:invalid_content@social.heldscal.la" + } -> + {:ok, %Tesla.Env{status: 200, body: ""}} + end) + + user = "invalid_content@social.heldscal.la" + assert {:error, {:content_type, nil}} = WebFinger.finger(user) + end + test "returns error when fails parse xml or json" do user = "invalid_content@social.heldscal.la" assert {:error, %Jason.DecodeError{}} = WebFinger.finger(user) @@ -56,12 +76,13 @@ defmodule Pleroma.Web.WebFingerTest do {:ok, _data} = WebFinger.finger(user) end - test "returns the ActivityPub actor URI for an ActivityPub user with the ld+json mimetype" do + test "returns the ActivityPub actor URI and subscribe address for an ActivityPub user with the ld+json mimetype" do user = "kaniini@gerzilla.de" {:ok, data} = WebFinger.finger(user) assert data["ap_id"] == "https://gerzilla.de/channel/kaniini" + assert data["subscribe_address"] == "https://gerzilla.de/follow?f=&url={uri}" end test "it work for AP-only user" do @@ -112,5 +133,52 @@ defmodule Pleroma.Web.WebFingerTest do ap_id = "https://" <> to_string(:idna.encode("zetsubou.みんな")) <> "/users/lain" {:ok, _data} = WebFinger.finger(ap_id) end + + test "respects json content-type" do + Tesla.Mock.mock(fn + %{ + url: + "https://mastodon.social/.well-known/webfinger?resource=acct:emelie@mastodon.social" + } -> + {:ok, + %Tesla.Env{ + status: 200, + body: File.read!("test/fixtures/tesla_mock/webfinger_emelie.json"), + headers: [{"content-type", "application/jrd+json"}] + }} + + %{url: "http://mastodon.social/.well-known/host-meta"} -> + {:ok, + %Tesla.Env{ + status: 200, + body: File.read!("test/fixtures/tesla_mock/mastodon.social_host_meta") + }} + end) + + {:ok, _data} = WebFinger.finger("emelie@mastodon.social") + end + + test "respects xml content-type" do + Tesla.Mock.mock(fn + %{ + url: "https://pawoo.net/.well-known/webfinger?resource=acct:pekorino@pawoo.net" + } -> + {:ok, + %Tesla.Env{ + status: 200, + body: File.read!("test/fixtures/tesla_mock/https___pawoo.net_users_pekorino.xml"), + headers: [{"content-type", "application/xrd+xml"}] + }} + + %{url: "http://pawoo.net/.well-known/host-meta"} -> + {:ok, + %Tesla.Env{ + status: 200, + body: File.read!("test/fixtures/tesla_mock/pawoo.net_host_meta") + }} + end) + + {:ok, _data} = WebFinger.finger("pekorino@pawoo.net") + end end end diff --git a/test/workers/cron/digest_emails_worker_test.exs b/test/pleroma/workers/cron/digest_emails_worker_test.exs index 65887192e..b3ca6235b 100644 --- a/test/workers/cron/digest_emails_worker_test.exs +++ b/test/pleroma/workers/cron/digest_emails_worker_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Workers.Cron.DigestEmailsWorkerTest do @@ -14,7 +14,7 @@ defmodule Pleroma.Workers.Cron.DigestEmailsWorkerTest do setup do: clear_config([:email_notifications, :digest]) setup do - Pleroma.Config.put([:email_notifications, :digest], %{ + clear_config([:email_notifications, :digest], %{ active: true, inactivity_threshold: 7, interval: 7 diff --git a/test/workers/cron/new_users_digest_worker_test.exs b/test/pleroma/workers/cron/new_users_digest_worker_test.exs index 129534cb1..f9ef265c2 100644 --- a/test/workers/cron/new_users_digest_worker_test.exs +++ b/test/pleroma/workers/cron/new_users_digest_worker_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Workers.Cron.NewUsersDigestWorkerTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true import Pleroma.Factory alias Pleroma.Tests.ObanHelpers @@ -28,7 +28,7 @@ defmodule Pleroma.Workers.Cron.NewUsersDigestWorkerTest do assert email.html_body =~ user.nickname assert email.html_body =~ user2.nickname assert email.html_body =~ "cofe" - assert email.html_body =~ "#{Pleroma.Web.Endpoint.url()}/static/logo.png" + assert email.html_body =~ "#{Pleroma.Web.Endpoint.url()}/static/logo.svg" end test "it doesn't fail when admin has no email" do diff --git a/test/pleroma/workers/purge_expired_activity_test.exs b/test/pleroma/workers/purge_expired_activity_test.exs new file mode 100644 index 000000000..98f30f61f --- /dev/null +++ b/test/pleroma/workers/purge_expired_activity_test.exs @@ -0,0 +1,59 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Workers.PurgeExpiredActivityTest do + use Pleroma.DataCase, async: true + use Oban.Testing, repo: Pleroma.Repo + + import Pleroma.Factory + + alias Pleroma.Workers.PurgeExpiredActivity + + test "enqueue job" do + activity = insert(:note_activity) + + assert {:ok, _} = + PurgeExpiredActivity.enqueue(%{ + activity_id: activity.id, + expires_at: DateTime.add(DateTime.utc_now(), 3601) + }) + + assert_enqueued( + worker: Pleroma.Workers.PurgeExpiredActivity, + args: %{activity_id: activity.id} + ) + + assert {:ok, _} = + perform_job(Pleroma.Workers.PurgeExpiredActivity, %{activity_id: activity.id}) + + assert %Oban.Job{} = Pleroma.Workers.PurgeExpiredActivity.get_expiration(activity.id) + end + + test "error if user was not found" do + activity = insert(:note_activity) + + assert {:ok, _} = + PurgeExpiredActivity.enqueue(%{ + activity_id: activity.id, + expires_at: DateTime.add(DateTime.utc_now(), 3601) + }) + + user = Pleroma.User.get_by_ap_id(activity.actor) + Pleroma.Repo.delete(user) + + assert {:error, :user_not_found} = + perform_job(Pleroma.Workers.PurgeExpiredActivity, %{activity_id: activity.id}) + end + + test "error if actiivity was not found" do + assert {:ok, _} = + PurgeExpiredActivity.enqueue(%{ + activity_id: "some_id", + expires_at: DateTime.add(DateTime.utc_now(), 3601) + }) + + assert {:error, :activity_not_found} = + perform_job(Pleroma.Workers.PurgeExpiredActivity, %{activity_id: "some_if"}) + end +end diff --git a/test/pleroma/workers/purge_expired_filter_test.exs b/test/pleroma/workers/purge_expired_filter_test.exs new file mode 100644 index 000000000..d10586be9 --- /dev/null +++ b/test/pleroma/workers/purge_expired_filter_test.exs @@ -0,0 +1,30 @@ +defmodule Pleroma.Workers.PurgeExpiredFilterTest do + use Pleroma.DataCase, async: true + use Oban.Testing, repo: Repo + + import Pleroma.Factory + + test "purges expired filter" do + %{id: user_id} = insert(:user) + + {:ok, %{id: id}} = + Pleroma.Filter.create(%{ + user_id: user_id, + phrase: "cofe", + context: ["home"], + expires_in: 600 + }) + + assert_enqueued( + worker: Pleroma.Workers.PurgeExpiredFilter, + args: %{filter_id: id} + ) + + assert {:ok, %{id: ^id}} = + perform_job(Pleroma.Workers.PurgeExpiredFilter, %{ + filter_id: id + }) + + assert Repo.aggregate(Pleroma.Filter, :count, :id) == 0 + end +end diff --git a/test/pleroma/workers/purge_expired_token_test.exs b/test/pleroma/workers/purge_expired_token_test.exs new file mode 100644 index 000000000..00cbd40cd --- /dev/null +++ b/test/pleroma/workers/purge_expired_token_test.exs @@ -0,0 +1,51 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Workers.PurgeExpiredTokenTest do + use Pleroma.DataCase, async: true + use Oban.Testing, repo: Pleroma.Repo + + import Pleroma.Factory + + setup do: clear_config([:oauth2, :clean_expired_tokens], true) + + test "purges expired oauth token" do + user = insert(:user) + app = insert(:oauth_app) + + {:ok, %{id: id}} = Pleroma.Web.OAuth.Token.create(app, user) + + assert_enqueued( + worker: Pleroma.Workers.PurgeExpiredToken, + args: %{token_id: id, mod: Pleroma.Web.OAuth.Token} + ) + + assert {:ok, %{id: ^id}} = + perform_job(Pleroma.Workers.PurgeExpiredToken, %{ + token_id: id, + mod: Pleroma.Web.OAuth.Token + }) + + assert Repo.aggregate(Pleroma.Web.OAuth.Token, :count, :id) == 0 + end + + test "purges expired mfa token" do + authorization = insert(:oauth_authorization) + + {:ok, %{id: id}} = Pleroma.MFA.Token.create(authorization.user, authorization) + + assert_enqueued( + worker: Pleroma.Workers.PurgeExpiredToken, + args: %{token_id: id, mod: Pleroma.MFA.Token} + ) + + assert {:ok, %{id: ^id}} = + perform_job(Pleroma.Workers.PurgeExpiredToken, %{ + token_id: id, + mod: Pleroma.MFA.Token + }) + + assert Repo.aggregate(Pleroma.MFA.Token, :count, :id) == 0 + end +end diff --git a/test/workers/scheduled_activity_worker_test.exs b/test/pleroma/workers/scheduled_activity_worker_test.exs index f3eddf7b1..5558d5b5f 100644 --- a/test/workers/scheduled_activity_worker_test.exs +++ b/test/pleroma/workers/scheduled_activity_worker_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Workers.ScheduledActivityWorkerTest do @@ -11,10 +11,9 @@ defmodule Pleroma.Workers.ScheduledActivityWorkerTest do import Pleroma.Factory import ExUnit.CaptureLog - setup do: clear_config([ScheduledActivity, :enabled]) + setup do: clear_config([ScheduledActivity, :enabled], true) test "creates a status from the scheduled activity" do - Pleroma.Config.put([ScheduledActivity, :enabled], true) user = insert(:user) naive_datetime = @@ -32,18 +31,22 @@ defmodule Pleroma.Workers.ScheduledActivityWorkerTest do params: %{status: "hi"} ) - ScheduledActivityWorker.perform(%Oban.Job{args: %{"activity_id" => scheduled_activity.id}}) + {:ok, %{id: activity_id}} = + ScheduledActivityWorker.perform(%Oban.Job{args: %{"activity_id" => scheduled_activity.id}}) refute Repo.get(ScheduledActivity, scheduled_activity.id) - activity = Repo.all(Pleroma.Activity) |> Enum.find(&(&1.actor == user.ap_id)) - assert Pleroma.Object.normalize(activity).data["content"] == "hi" - end - test "adds log message if ScheduledActivity isn't find" do - Pleroma.Config.put([ScheduledActivity, :enabled], true) + object = + Pleroma.Activity + |> Repo.get(activity_id) + |> Pleroma.Object.normalize() + + assert object.data["content"] == "hi" + end + test "error message for non-existent scheduled activity" do assert capture_log([level: :error], fn -> ScheduledActivityWorker.perform(%Oban.Job{args: %{"activity_id" => 42}}) - end) =~ "Couldn't find scheduled activity" + end) =~ "Couldn't find scheduled activity: 42" end end diff --git a/test/xml_builder_test.exs b/test/pleroma/xml_builder_test.exs index 059384c34..9aae32cdc 100644 --- a/test/xml_builder_test.exs +++ b/test/pleroma/xml_builder_test.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.XmlBuilderTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: true alias Pleroma.XmlBuilder test "Build a basic xml string from a tuple" do diff --git a/test/plugs/ensure_user_key_plug_test.exs b/test/plugs/ensure_user_key_plug_test.exs deleted file mode 100644 index 633c05447..000000000 --- a/test/plugs/ensure_user_key_plug_test.exs +++ /dev/null @@ -1,29 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Plugs.EnsureUserKeyPlugTest do - use Pleroma.Web.ConnCase, async: true - - alias Pleroma.Plugs.EnsureUserKeyPlug - - test "if the conn has a user key set, it does nothing", %{conn: conn} do - conn = - conn - |> assign(:user, 1) - - ret_conn = - conn - |> EnsureUserKeyPlug.call(%{}) - - assert conn == ret_conn - end - - test "if the conn has no key set, it sets it to nil", %{conn: conn} do - conn = - conn - |> EnsureUserKeyPlug.call(%{}) - - assert Map.has_key?(conn.assigns, :user) - end -end diff --git a/test/plugs/frontend_static_test.exs b/test/plugs/frontend_static_test.exs deleted file mode 100644 index 6f4923048..000000000 --- a/test/plugs/frontend_static_test.exs +++ /dev/null @@ -1,57 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.FrontendStaticPlugTest do - alias Pleroma.Plugs.FrontendStatic - use Pleroma.Web.ConnCase - - @dir "test/tmp/instance_static" - - setup do - File.mkdir_p!(@dir) - on_exit(fn -> File.rm_rf(@dir) end) - end - - setup do: clear_config([:instance, :static_dir], @dir) - - test "init will give a static plug config + the frontend type" do - opts = - [ - at: "/admin", - frontend_type: :admin - ] - |> FrontendStatic.init() - - assert opts[:at] == ["admin"] - assert opts[:frontend_type] == :admin - end - - test "overrides existing static files", %{conn: conn} do - name = "pelmora" - ref = "uguu" - - clear_config([:frontends, :primary], %{"name" => name, "ref" => ref}) - path = "#{@dir}/frontends/#{name}/#{ref}" - - File.mkdir_p!(path) - File.write!("#{path}/index.html", "from frontend plug") - - index = get(conn, "/") - assert html_response(index, 200) == "from frontend plug" - end - - test "overrides existing static files for the `pleroma/admin` path", %{conn: conn} do - name = "pelmora" - ref = "uguu" - - clear_config([:frontends, :admin], %{"name" => name, "ref" => ref}) - path = "#{@dir}/frontends/#{name}/#{ref}" - - File.mkdir_p!(path) - File.write!("#{path}/index.html", "from frontend plug") - - index = get(conn, "/pleroma/admin/") - assert html_response(index, 200) == "from frontend plug" - end -end diff --git a/test/plugs/legacy_authentication_plug_test.exs b/test/plugs/legacy_authentication_plug_test.exs deleted file mode 100644 index 3b8c07627..000000000 --- a/test/plugs/legacy_authentication_plug_test.exs +++ /dev/null @@ -1,82 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Plugs.LegacyAuthenticationPlugTest do - use Pleroma.Web.ConnCase - - import Pleroma.Factory - - alias Pleroma.Plugs.LegacyAuthenticationPlug - alias Pleroma.Plugs.OAuthScopesPlug - alias Pleroma.Plugs.PlugHelper - alias Pleroma.User - - setup do - user = - insert(:user, - password: "password", - password_hash: - "$6$9psBWV8gxkGOZWBz$PmfCycChoxeJ3GgGzwvhlgacb9mUoZ.KUXNCssekER4SJ7bOK53uXrHNb2e4i8yPFgSKyzaW9CcmrDXWIEMtD1" - ) - - %{user: user} - end - - test "it does nothing if a user is assigned", %{conn: conn, user: user} do - conn = - conn - |> assign(:auth_credentials, %{username: "dude", password: "password"}) - |> assign(:auth_user, user) - |> assign(:user, %User{}) - - ret_conn = - conn - |> LegacyAuthenticationPlug.call(%{}) - - assert ret_conn == conn - end - - @tag :skip_on_mac - test "if `auth_user` is present and password is correct, " <> - "it authenticates the user, resets the password, marks OAuthScopesPlug as skipped", - %{ - conn: conn, - user: user - } do - conn = - conn - |> assign(:auth_credentials, %{username: "dude", password: "password"}) - |> assign(:auth_user, user) - - conn = LegacyAuthenticationPlug.call(conn, %{}) - - assert conn.assigns.user.id == user.id - assert PlugHelper.plug_skipped?(conn, OAuthScopesPlug) - end - - @tag :skip_on_mac - test "it does nothing if the password is wrong", %{ - conn: conn, - user: user - } do - conn = - conn - |> assign(:auth_credentials, %{username: "dude", password: "wrong_password"}) - |> assign(:auth_user, user) - - ret_conn = - conn - |> LegacyAuthenticationPlug.call(%{}) - - assert conn == ret_conn - end - - test "with no credentials or user it does nothing", %{conn: conn} do - ret_conn = - conn - |> LegacyAuthenticationPlug.call(%{}) - - assert ret_conn == conn - end -end diff --git a/test/plugs/oauth_plug_test.exs b/test/plugs/oauth_plug_test.exs deleted file mode 100644 index f74c068cd..000000000 --- a/test/plugs/oauth_plug_test.exs +++ /dev/null @@ -1,80 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Plugs.OAuthPlugTest do - use Pleroma.Web.ConnCase, async: true - - alias Pleroma.Plugs.OAuthPlug - import Pleroma.Factory - - @session_opts [ - store: :cookie, - key: "_test", - signing_salt: "cooldude" - ] - - setup %{conn: conn} do - user = insert(:user) - {:ok, %{token: token}} = Pleroma.Web.OAuth.Token.create_token(insert(:oauth_app), user) - %{user: user, token: token, conn: conn} - end - - test "with valid token(uppercase), it assigns the user", %{conn: conn} = opts do - conn = - conn - |> put_req_header("authorization", "BEARER #{opts[:token]}") - |> OAuthPlug.call(%{}) - - assert conn.assigns[:user] == opts[:user] - end - - test "with valid token(downcase), it assigns the user", %{conn: conn} = opts do - conn = - conn - |> put_req_header("authorization", "bearer #{opts[:token]}") - |> OAuthPlug.call(%{}) - - assert conn.assigns[:user] == opts[:user] - end - - test "with valid token(downcase) in url parameters, it assigns the user", opts do - conn = - :get - |> build_conn("/?access_token=#{opts[:token]}") - |> put_req_header("content-type", "application/json") - |> fetch_query_params() - |> OAuthPlug.call(%{}) - - assert conn.assigns[:user] == opts[:user] - end - - test "with valid token(downcase) in body parameters, it assigns the user", opts do - conn = - :post - |> build_conn("/api/v1/statuses", access_token: opts[:token], status: "test") - |> OAuthPlug.call(%{}) - - assert conn.assigns[:user] == opts[:user] - end - - test "with invalid token, it not assigns the user", %{conn: conn} do - conn = - conn - |> put_req_header("authorization", "bearer TTTTT") - |> OAuthPlug.call(%{}) - - refute conn.assigns[:user] - end - - test "when token is missed but token in session, it assigns the user", %{conn: conn} = opts do - conn = - conn - |> Plug.Session.call(Plug.Session.init(@session_opts)) - |> fetch_session() - |> put_session(:oauth_token, opts[:token]) - |> OAuthPlug.call(%{}) - - assert conn.assigns[:user] == opts[:user] - end -end diff --git a/test/plugs/remote_ip_test.exs b/test/plugs/remote_ip_test.exs deleted file mode 100644 index 752ab32e7..000000000 --- a/test/plugs/remote_ip_test.exs +++ /dev/null @@ -1,75 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Plugs.RemoteIpTest do - use ExUnit.Case, async: true - use Plug.Test - - alias Pleroma.Plugs.RemoteIp - - import Pleroma.Tests.Helpers, only: [clear_config: 1, clear_config: 2] - setup do: clear_config(RemoteIp) - - test "disabled" do - Pleroma.Config.put(RemoteIp, enabled: false) - - %{remote_ip: remote_ip} = conn(:get, "/") - - conn = - conn(:get, "/") - |> put_req_header("x-forwarded-for", "1.1.1.1") - |> RemoteIp.call(nil) - - assert conn.remote_ip == remote_ip - end - - test "enabled" do - Pleroma.Config.put(RemoteIp, enabled: true) - - conn = - conn(:get, "/") - |> put_req_header("x-forwarded-for", "1.1.1.1") - |> RemoteIp.call(nil) - - assert conn.remote_ip == {1, 1, 1, 1} - end - - test "custom headers" do - Pleroma.Config.put(RemoteIp, enabled: true, headers: ["cf-connecting-ip"]) - - conn = - conn(:get, "/") - |> put_req_header("x-forwarded-for", "1.1.1.1") - |> RemoteIp.call(nil) - - refute conn.remote_ip == {1, 1, 1, 1} - - conn = - conn(:get, "/") - |> put_req_header("cf-connecting-ip", "1.1.1.1") - |> RemoteIp.call(nil) - - assert conn.remote_ip == {1, 1, 1, 1} - end - - test "custom proxies" do - Pleroma.Config.put(RemoteIp, enabled: true) - - conn = - conn(:get, "/") - |> put_req_header("x-forwarded-for", "173.245.48.1, 1.1.1.1, 173.245.48.2") - |> RemoteIp.call(nil) - - refute conn.remote_ip == {1, 1, 1, 1} - - Pleroma.Config.put([RemoteIp, :proxies], ["173.245.48.0/20"]) - - conn = - conn(:get, "/") - |> put_req_header("x-forwarded-for", "173.245.48.1, 1.1.1.1, 173.245.48.2") - |> RemoteIp.call(nil) - - assert conn.remote_ip == {1, 1, 1, 1} - end -end diff --git a/test/plugs/session_authentication_plug_test.exs b/test/plugs/session_authentication_plug_test.exs deleted file mode 100644 index 0949ecfed..000000000 --- a/test/plugs/session_authentication_plug_test.exs +++ /dev/null @@ -1,63 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Plugs.SessionAuthenticationPlugTest do - use Pleroma.Web.ConnCase, async: true - - alias Pleroma.Plugs.SessionAuthenticationPlug - alias Pleroma.User - - setup %{conn: conn} do - session_opts = [ - store: :cookie, - key: "_test", - signing_salt: "cooldude" - ] - - conn = - conn - |> Plug.Session.call(Plug.Session.init(session_opts)) - |> fetch_session - |> assign(:auth_user, %User{id: 1}) - - %{conn: conn} - end - - test "it does nothing if a user is assigned", %{conn: conn} do - conn = - conn - |> assign(:user, %User{}) - - ret_conn = - conn - |> SessionAuthenticationPlug.call(%{}) - - assert ret_conn == conn - end - - test "if the auth_user has the same id as the user_id in the session, it assigns the user", %{ - conn: conn - } do - conn = - conn - |> put_session(:user_id, conn.assigns.auth_user.id) - |> SessionAuthenticationPlug.call(%{}) - - assert conn.assigns.user == conn.assigns.auth_user - end - - test "if the auth_user has a different id as the user_id in the session, it does nothing", %{ - conn: conn - } do - conn = - conn - |> put_session(:user_id, -1) - - ret_conn = - conn - |> SessionAuthenticationPlug.call(%{}) - - assert ret_conn == conn - end -end diff --git a/test/support/api_spec_helpers.ex b/test/support/api_spec_helpers.ex index 46388f92c..886e72d73 100644 --- a/test/support/api_spec_helpers.ex +++ b/test/support/api_spec_helpers.ex @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Tests.ApiSpecHelpers do @@ -29,9 +29,7 @@ defmodule Pleroma.Tests.ApiSpecHelpers do end) flunk( - "Value does not conform to schema #{schema.title}: #{Enum.join(errors, "\n")}\n#{ - inspect(value) - }" + "Value does not conform to schema #{schema.title}: #{Enum.join(errors, "\n")}\n#{inspect(value)}" ) end end diff --git a/test/support/builders/user_builder.ex b/test/support/builders/user_builder.ex index 0c687c029..6bccbb35a 100644 --- a/test/support/builders/user_builder.ex +++ b/test/support/builders/user_builder.ex @@ -7,7 +7,7 @@ defmodule Pleroma.Builders.UserBuilder do email: "test@example.org", name: "Test Name", nickname: "testname", - password_hash: Pbkdf2.hash_pwd_salt("test"), + password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt("test"), bio: "A tester.", ap_id: "some id", last_digest_emailed_at: NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second), diff --git a/test/support/cachex_proxy.ex b/test/support/cachex_proxy.ex new file mode 100644 index 000000000..de1f1c766 --- /dev/null +++ b/test/support/cachex_proxy.ex @@ -0,0 +1,40 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.CachexProxy do + @behaviour Pleroma.Caching + + @impl true + defdelegate get!(cache, key), to: Cachex + + @impl true + defdelegate stream!(cache, key), to: Cachex + + @impl true + defdelegate put(cache, key, value, options), to: Cachex + + @impl true + defdelegate put(cache, key, value), to: Cachex + + @impl true + defdelegate get_and_update(cache, key, func), to: Cachex + + @impl true + defdelegate get(cache, key), to: Cachex + + @impl true + defdelegate fetch!(cache, key, func), to: Cachex + + @impl true + defdelegate expire_at(cache, str, num), to: Cachex + + @impl true + defdelegate exists?(cache, key), to: Cachex + + @impl true + defdelegate del(cache, key), to: Cachex + + @impl true + defdelegate execute!(cache, func), to: Cachex +end diff --git a/test/support/captcha_mock.ex b/test/support/captcha/mock.ex index 2ed2ba3b4..175ade131 100644 --- a/test/support/captcha_mock.ex +++ b/test/support/captcha/mock.ex @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Captcha.Mock do diff --git a/test/support/channel_case.ex b/test/support/channel_case.ex index d63a0f06b..1fbf6f100 100644 --- a/test/support/channel_case.ex +++ b/test/support/channel_case.ex @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ChannelCase do @@ -22,7 +22,7 @@ defmodule Pleroma.Web.ChannelCase do using do quote do # Import conveniences for testing with channels - use Phoenix.ChannelTest + import Phoenix.ChannelTest use Pleroma.Tests.Helpers # The default endpoint for testing @@ -30,13 +30,5 @@ defmodule Pleroma.Web.ChannelCase do end end - setup tags do - :ok = Ecto.Adapters.SQL.Sandbox.checkout(Pleroma.Repo) - - unless tags[:async] do - Ecto.Adapters.SQL.Sandbox.mode(Pleroma.Repo, {:shared, self()}) - end - - :ok - end + setup tags, do: Pleroma.DataCase.setup_multi_process_mode(tags) end diff --git a/test/support/conn_case.ex b/test/support/conn_case.ex index 7ef681258..eab469833 100644 --- a/test/support/conn_case.ex +++ b/test/support/conn_case.ex @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ConnCase do @@ -19,10 +19,13 @@ defmodule Pleroma.Web.ConnCase do use ExUnit.CaseTemplate + alias Pleroma.DataCase + using do quote do # Import conveniences for testing with connections - use Phoenix.ConnTest + import Plug.Conn + import Phoenix.ConnTest use Pleroma.Tests.Helpers import Pleroma.Web.Router.Helpers @@ -64,13 +67,11 @@ defmodule Pleroma.Web.ConnCase do end defp json_response_and_validate_schema( - %{ - private: %{ - open_api_spex: %{operation_id: op_id, operation_lookup: lookup, spec: spec} - } - } = conn, + %{private: %{operation_id: op_id}} = conn, status ) do + {spec, lookup} = OpenApiSpex.Plug.PutApiSpec.get_spec_and_operation_lookup(conn) + content_type = conn |> Plug.Conn.get_resp_header("content-type") @@ -101,9 +102,7 @@ defmodule Pleroma.Web.ConnCase do end) flunk( - "Response does not conform to schema of #{op_id} operation: #{ - Enum.join(errors, "\n") - }\n#{inspect(json)}" + "Response does not conform to schema of #{op_id} operation: #{Enum.join(errors, "\n")}\n#{inspect(json)}" ) end end @@ -111,47 +110,15 @@ defmodule Pleroma.Web.ConnCase do defp json_response_and_validate_schema(conn, _status) do flunk("Response schema not found for #{conn.method} #{conn.request_path} #{conn.status}") end - - defp ensure_federating_or_authenticated(conn, url, user) do - initial_setting = Config.get([:instance, :federating]) - on_exit(fn -> Config.put([:instance, :federating], initial_setting) end) - - Config.put([:instance, :federating], false) - - conn - |> get(url) - |> response(403) - - conn - |> assign(:user, user) - |> get(url) - |> response(200) - - Config.put([:instance, :federating], true) - - conn - |> get(url) - |> response(200) - end end end setup tags do - Cachex.clear(:user_cache) - Cachex.clear(:object_cache) - :ok = Ecto.Adapters.SQL.Sandbox.checkout(Pleroma.Repo) + DataCase.setup_multi_process_mode(tags) + DataCase.setup_streamer(tags) + DataCase.stub_pipeline() - unless tags[:async] do - Ecto.Adapters.SQL.Sandbox.mode(Pleroma.Repo, {:shared, self()}) - end - - if tags[:needs_streamer] do - start_supervised(%{ - id: Pleroma.Web.Streamer.registry(), - start: - {Registry, :start_link, [[keys: :duplicate, name: Pleroma.Web.Streamer.registry()]]} - }) - end + Mox.verify_on_exit!() {:ok, conn: Phoenix.ConnTest.build_conn()} end diff --git a/test/support/data_case.ex b/test/support/data_case.ex index ba8848952..0ee2aa4a2 100644 --- a/test/support/data_case.ex +++ b/test/support/data_case.ex @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.DataCase do @@ -18,6 +18,8 @@ defmodule Pleroma.DataCase do use ExUnit.CaseTemplate + import Pleroma.Tests.Helpers, only: [clear_config: 2] + using do quote do alias Pleroma.Repo @@ -27,18 +29,59 @@ defmodule Pleroma.DataCase do import Ecto.Query import Pleroma.DataCase use Pleroma.Tests.Helpers + + # Sets up OAuth access with specified scopes + defp oauth_access(scopes, opts \\ []) do + user = + Keyword.get_lazy(opts, :user, fn -> + Pleroma.Factory.insert(:user) + end) + + token = + Keyword.get_lazy(opts, :oauth_token, fn -> + Pleroma.Factory.insert(:oauth_token, user: user, scopes: scopes) + end) + + %{user: user, token: token} + end end end - setup tags do - Cachex.clear(:user_cache) - Cachex.clear(:object_cache) + def clear_cachex do + Pleroma.Supervisor + |> Supervisor.which_children() + |> Enum.each(fn + {name, _, _, [Cachex]} -> + name + |> to_string + |> String.trim_leading("cachex_") + |> Kernel.<>("_cache") + |> String.to_existing_atom() + |> Cachex.clear() + + _ -> + nil + end) + end + + def setup_multi_process_mode(tags) do :ok = Ecto.Adapters.SQL.Sandbox.checkout(Pleroma.Repo) - unless tags[:async] do + if tags[:async] do + Mox.stub_with(Pleroma.CachexMock, Pleroma.NullCache) + Mox.set_mox_private() + else Ecto.Adapters.SQL.Sandbox.mode(Pleroma.Repo, {:shared, self()}) + + Mox.set_mox_global() + Mox.stub_with(Pleroma.CachexMock, Pleroma.CachexProxy) + clear_cachex() end + :ok + end + + def setup_streamer(tags) do if tags[:needs_streamer] do start_supervised(%{ id: Pleroma.Web.Streamer.registry(), @@ -50,18 +93,35 @@ defmodule Pleroma.DataCase do :ok end - def ensure_local_uploader(context) do - test_uploader = Map.get(context, :uploader, Pleroma.Uploaders.Local) - uploader = Pleroma.Config.get([Pleroma.Upload, :uploader]) - filters = Pleroma.Config.get([Pleroma.Upload, :filters]) + setup tags do + setup_multi_process_mode(tags) + setup_streamer(tags) + stub_pipeline() - Pleroma.Config.put([Pleroma.Upload, :uploader], test_uploader) - Pleroma.Config.put([Pleroma.Upload, :filters], []) + Mox.verify_on_exit!() - on_exit(fn -> - Pleroma.Config.put([Pleroma.Upload, :uploader], uploader) - Pleroma.Config.put([Pleroma.Upload, :filters], filters) - end) + :ok + end + + def stub_pipeline do + Mox.stub_with(Pleroma.Web.ActivityPub.SideEffectsMock, Pleroma.Web.ActivityPub.SideEffects) + + Mox.stub_with( + Pleroma.Web.ActivityPub.ObjectValidatorMock, + Pleroma.Web.ActivityPub.ObjectValidator + ) + + Mox.stub_with(Pleroma.Web.ActivityPub.MRFMock, Pleroma.Web.ActivityPub.MRF) + Mox.stub_with(Pleroma.Web.ActivityPub.ActivityPubMock, Pleroma.Web.ActivityPub.ActivityPub) + Mox.stub_with(Pleroma.Web.FederatorMock, Pleroma.Web.Federator) + Mox.stub_with(Pleroma.ConfigMock, Pleroma.Config) + end + + def ensure_local_uploader(context) do + test_uploader = Map.get(context, :uploader) || Pleroma.Uploaders.Local + + clear_config([Pleroma.Upload, :uploader], test_uploader) + clear_config([Pleroma.Upload, :filters], []) :ok end diff --git a/test/support/factory.ex b/test/support/factory.ex index 486eda8da..4a78425ce 100644 --- a/test/support/factory.ex +++ b/test/support/factory.ex @@ -1,9 +1,12 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Factory do use ExMachina.Ecto, repo: Pleroma.Repo + + require Pleroma.Constants + alias Pleroma.Object alias Pleroma.User @@ -24,13 +27,14 @@ defmodule Pleroma.Factory do } end - def user_factory do + def user_factory(attrs \\ %{}) do user = %User{ name: sequence(:name, &"Test テスト User #{&1}"), email: sequence(:email, &"user#{&1}@example.com"), nickname: sequence(:nickname, &"nick#{&1}"), - password_hash: Pbkdf2.hash_pwd_salt("test"), + password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt("test"), bio: sequence(:bio, &"Tester Number #{&1}"), + is_discoverable: true, last_digest_emailed_at: NaiveDateTime.utc_now(), last_refreshed_at: NaiveDateTime.utc_now(), notification_settings: %Pleroma.User.NotificationSetting{}, @@ -38,13 +42,33 @@ defmodule Pleroma.Factory do ap_enabled: true } - %{ - user - | ap_id: User.ap_id(user), - follower_address: User.ap_followers(user), - following_address: User.ap_following(user), - raw_bio: user.bio - } + urls = + if attrs[:local] == false do + base_domain = attrs[:domain] || Enum.random(["domain1.com", "domain2.com", "domain3.com"]) + + ap_id = "https://#{base_domain}/users/#{user.nickname}" + + %{ + ap_id: ap_id, + follower_address: ap_id <> "/followers", + following_address: ap_id <> "/following", + featured_address: ap_id <> "/collections/featured" + } + else + %{ + ap_id: User.ap_id(user), + follower_address: User.ap_followers(user), + following_address: User.ap_following(user), + featured_address: User.ap_featured_collection(user) + } + end + + attrs = Map.delete(attrs, :domain) + + user + |> Map.put(:raw_bio, user.bio) + |> Map.merge(urls) + |> merge_attributes(attrs) end def user_relationship_factory(attrs \\ %{}) do @@ -87,6 +111,42 @@ defmodule Pleroma.Factory do } end + def attachment_note_factory(attrs \\ %{}) do + user = attrs[:user] || insert(:user) + {length, attrs} = Map.pop(attrs, :length, 1) + + data = %{ + "attachment" => + Stream.repeatedly(fn -> attachment_data(user.ap_id, attrs[:href]) end) + |> Enum.take(length) + } + + build(:note, Map.put(attrs, :data, data)) + end + + defp attachment_data(ap_id, href) do + href = href || sequence(:href, &"#{Pleroma.Web.Endpoint.url()}/media/#{&1}.jpg") + + %{ + "url" => [ + %{ + "href" => href, + "type" => "Link", + "mediaType" => "image/jpeg" + } + ], + "name" => "some name", + "type" => "Document", + "actor" => ap_id, + "mediaType" => "image/jpeg" + } + end + + def followers_only_note_factory(attrs \\ %{}) do + %Pleroma.Object{data: data} = note_factory(attrs) + %Pleroma.Object{data: Map.merge(data, %{"to" => [data["actor"] <> "/followers"]})} + end + def audio_factory(attrs \\ %{}) do text = sequence(:text, &"lain radio episode #{&1}") @@ -136,8 +196,8 @@ defmodule Pleroma.Factory do end def article_factory do - note_factory() - |> Map.put("type", "Article") + %Pleroma.Object{data: data} = note_factory() + %Pleroma.Object{data: Map.merge(data, %{"type" => "Article"})} end def tombstone_factory do @@ -153,6 +213,38 @@ defmodule Pleroma.Factory do } end + def question_factory(attrs \\ %{}) do + user = attrs[:user] || insert(:user) + + data = %{ + "id" => Pleroma.Web.ActivityPub.Utils.generate_object_id(), + "type" => "Question", + "actor" => user.ap_id, + "attributedTo" => user.ap_id, + "attachment" => [], + "to" => ["https://www.w3.org/ns/activitystreams#Public"], + "cc" => [user.follower_address], + "context" => Pleroma.Web.ActivityPub.Utils.generate_context_id(), + "closed" => DateTime.utc_now() |> DateTime.add(86_400) |> DateTime.to_iso8601(), + "oneOf" => [ + %{ + "type" => "Note", + "name" => "chocolate", + "replies" => %{"totalItems" => 0, "type" => "Collection"} + }, + %{ + "type" => "Note", + "name" => "vanilla", + "replies" => %{"totalItems" => 0, "type" => "Collection"} + } + ] + } + + %Pleroma.Object{ + data: merge_attributes(data, Map.get(attrs, :data, %{})) + } + end + def direct_note_activity_factory do dm = insert(:direct_note) @@ -173,10 +265,49 @@ defmodule Pleroma.Factory do } end - def note_activity_factory(attrs \\ %{}) do + def add_activity_factory(attrs \\ %{}) do + featured_collection_activity(attrs, "Add") + end + + def remove_activity_factor(attrs \\ %{}) do + featured_collection_activity(attrs, "Remove") + end + + defp featured_collection_activity(attrs, type) do user = attrs[:user] || insert(:user) note = attrs[:note] || insert(:note, user: user) + data_attrs = + attrs + |> Map.get(:data_attrs, %{}) + |> Map.put(:type, type) + + attrs = Map.drop(attrs, [:user, :note, :data_attrs]) + + data = + %{ + "id" => Pleroma.Web.ActivityPub.Utils.generate_activity_id(), + "target" => user.featured_address, + "object" => note.data["object"], + "actor" => note.data["actor"], + "type" => "Add", + "to" => [Pleroma.Constants.as_public()], + "cc" => [user.follower_address] + } + |> Map.merge(data_attrs) + + %Pleroma.Activity{ + data: data, + actor: data["actor"], + recipients: data["to"] + } + |> Map.merge(attrs) + end + + def followers_only_note_activity_factory(attrs \\ %{}) do + user = attrs[:user] || insert(:user) + note = insert(:followers_only_note, user: user) + data_attrs = attrs[:data_attrs] || %{} attrs = Map.drop(attrs, [:user, :note, :data_attrs]) @@ -186,7 +317,7 @@ defmodule Pleroma.Factory do "type" => "Create", "actor" => note.data["actor"], "to" => note.data["to"], - "object" => note.data["id"], + "object" => note.data, "published" => DateTime.utc_now() |> DateTime.to_iso8601(), "context" => note.data["context"] } @@ -200,23 +331,31 @@ defmodule Pleroma.Factory do |> Map.merge(attrs) end - defp expiration_offset_by_minutes(attrs, minutes) do - scheduled_at = - NaiveDateTime.utc_now() - |> NaiveDateTime.add(:timer.minutes(minutes), :millisecond) - |> NaiveDateTime.truncate(:second) + def note_activity_factory(attrs \\ %{}) do + user = attrs[:user] || insert(:user) + note = attrs[:note] || insert(:note, user: user) - %Pleroma.ActivityExpiration{} - |> Map.merge(attrs) - |> Map.put(:scheduled_at, scheduled_at) - end + data_attrs = attrs[:data_attrs] || %{} + attrs = Map.drop(attrs, [:user, :note, :data_attrs]) - def expiration_in_the_past_factory(attrs \\ %{}) do - expiration_offset_by_minutes(attrs, -60) - end + data = + %{ + "id" => Pleroma.Web.ActivityPub.Utils.generate_activity_id(), + "type" => "Create", + "actor" => note.data["actor"], + "to" => note.data["to"], + "object" => note.data["id"], + "published" => DateTime.utc_now() |> DateTime.to_iso8601(), + "context" => note.data["context"] + } + |> Map.merge(data_attrs) - def expiration_in_the_future_factory(attrs \\ %{}) do - expiration_offset_by_minutes(attrs, 61) + %Pleroma.Activity{ + data: data, + actor: data["actor"], + recipients: data["to"] + } + |> Map.merge(attrs) end def article_activity_factory do @@ -261,7 +400,7 @@ defmodule Pleroma.Factory do def like_activity_factory(attrs \\ %{}) do note_activity = attrs[:note_activity] || insert(:note_activity) - object = Object.normalize(note_activity) + object = Object.normalize(note_activity, fetch: false) user = insert(:user) data = @@ -321,6 +460,33 @@ defmodule Pleroma.Factory do } end + def question_activity_factory(attrs \\ %{}) do + user = attrs[:user] || insert(:user) + question = attrs[:question] || insert(:question, user: user) + + data_attrs = attrs[:data_attrs] || %{} + attrs = Map.drop(attrs, [:user, :question, :data_attrs]) + + data = + %{ + "id" => Pleroma.Web.ActivityPub.Utils.generate_activity_id(), + "type" => "Create", + "actor" => question.data["actor"], + "to" => question.data["to"], + "object" => question.data["id"], + "published" => DateTime.utc_now() |> DateTime.to_iso8601(), + "context" => question.data["context"] + } + |> Map.merge(data_attrs) + + %Pleroma.Activity{ + data: data, + actor: data["actor"], + recipients: data["to"] + } + |> Map.merge(attrs) + end + def oauth_app_factory do %Pleroma.Web.OAuth.App{ client_name: sequence(:client_name, &"Some client #{&1}"), @@ -457,7 +623,8 @@ defmodule Pleroma.Factory do %Pleroma.Filter{ user: build(:user), filter_id: sequence(:filter_id, & &1), - phrase: "cofe" + phrase: "cofe", + context: ["home"] } end end diff --git a/test/support/helpers.ex b/test/support/helpers.ex index ecd4b1e18..34f1505d0 100644 --- a/test/support/helpers.ex +++ b/test/support/helpers.ex @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Tests.Helpers do @@ -8,6 +8,8 @@ defmodule Pleroma.Tests.Helpers do """ alias Pleroma.Config + require Logger + defmacro clear_config(config_path) do quote do clear_config(unquote(config_path)) do @@ -18,6 +20,7 @@ defmodule Pleroma.Tests.Helpers do defmacro clear_config(config_path, do: yield) do quote do initial_setting = Config.fetch(unquote(config_path)) + unquote(yield) on_exit(fn -> @@ -35,6 +38,14 @@ defmodule Pleroma.Tests.Helpers do end defmacro clear_config(config_path, temp_setting) do + # NOTE: `clear_config([section, key], value)` != `clear_config([section], key: value)` (!) + # Displaying a warning to prevent unintentional clearing of all but one keys in section + if Keyword.keyword?(temp_setting) and length(temp_setting) == 1 do + Logger.warn( + "Please change `clear_config([section], key: value)` to `clear_config([section, key], value)`" + ) + end + quote do clear_config(unquote(config_path)) do Config.put(unquote(config_path), unquote(temp_setting)) @@ -55,6 +66,14 @@ defmodule Pleroma.Tests.Helpers do clear_config: 2 ] + def time_travel(entity, seconds) do + new_time = NaiveDateTime.add(entity.inserted_at, seconds) + + entity + |> Ecto.Changeset.change(%{inserted_at: new_time, updated_at: new_time}) + |> Pleroma.Repo.update() + end + def to_datetime(%NaiveDateTime{} = naive_datetime) do naive_datetime |> DateTime.from_naive!("Etc/UTC") @@ -85,8 +104,8 @@ defmodule Pleroma.Tests.Helpers do assigns = Map.new(assigns) view.render(template, assigns) - |> Poison.encode!() - |> Poison.decode!() + |> Jason.encode!() + |> Jason.decode!() end def stringify_keys(nil), do: nil diff --git a/test/support/http_request_mock.ex b/test/support/http_request_mock.ex index a0ebf65d9..94900dc14 100644 --- a/test/support/http_request_mock.ex +++ b/test/support/http_request_mock.ex @@ -1,10 +1,12 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule HttpRequestMock do require Logger + def activitypub_object_headers, do: [{"content-type", "application/activity+json"}] + def request( %Tesla.Env{ url: url, @@ -34,7 +36,8 @@ defmodule HttpRequestMock do {:ok, %Tesla.Env{ status: 200, - body: File.read!("test/fixtures/tesla_mock/https___osada.macgirvin.com_channel_mike.json") + body: File.read!("test/fixtures/tesla_mock/https___osada.macgirvin.com_channel_mike.json"), + headers: activitypub_object_headers() }} end @@ -42,7 +45,8 @@ defmodule HttpRequestMock do {:ok, %Tesla.Env{ status: 200, - body: File.read!("test/fixtures/tesla_mock/moonman@shitposter.club.json") + body: File.read!("test/fixtures/tesla_mock/moonman@shitposter.club.json"), + headers: activitypub_object_headers() }} end @@ -50,7 +54,8 @@ defmodule HttpRequestMock do {:ok, %Tesla.Env{ status: 200, - body: File.read!("test/fixtures/tesla_mock/status.emelie.json") + body: File.read!("test/fixtures/tesla_mock/status.emelie.json"), + headers: activitypub_object_headers() }} end @@ -66,7 +71,8 @@ defmodule HttpRequestMock do {:ok, %Tesla.Env{ status: 200, - body: File.read!("test/fixtures/tesla_mock/emelie.json") + body: File.read!("test/fixtures/tesla_mock/emelie.json"), + headers: activitypub_object_headers() }} end @@ -78,7 +84,20 @@ defmodule HttpRequestMock do {:ok, %Tesla.Env{ status: 200, - body: File.read!("test/fixtures/tesla_mock/rinpatch.json") + body: File.read!("test/fixtures/tesla_mock/rinpatch.json"), + headers: activitypub_object_headers() + }} + end + + def get("https://mastodon.sdf.org/users/rinpatch/collections/featured", _, _, _) do + {:ok, + %Tesla.Env{ + status: 200, + body: + File.read!("test/fixtures/users_mock/masto_featured.json") + |> String.replace("{{domain}}", "mastodon.sdf.org") + |> String.replace("{{nickname}}", "rinpatch"), + headers: [{"content-type", "application/activity+json"}] }} end @@ -86,7 +105,8 @@ defmodule HttpRequestMock do {:ok, %Tesla.Env{ status: 200, - body: File.read!("test/fixtures/tesla_mock/poll_attachment.json") + body: File.read!("test/fixtures/tesla_mock/poll_attachment.json"), + headers: activitypub_object_headers() }} end @@ -99,15 +119,8 @@ defmodule HttpRequestMock do {:ok, %Tesla.Env{ status: 200, - body: File.read!("test/fixtures/tesla_mock/webfinger_emelie.json") - }} - end - - def get("https://mastodon.social/users/emelie.atom", _, _, _) do - {:ok, - %Tesla.Env{ - status: 200, - body: File.read!("test/fixtures/tesla_mock/emelie.atom") + body: File.read!("test/fixtures/tesla_mock/webfinger_emelie.json"), + headers: activitypub_object_headers() }} end @@ -120,7 +133,8 @@ defmodule HttpRequestMock do {:ok, %Tesla.Env{ status: 200, - body: File.read!("test/fixtures/tesla_mock/mike@osada.macgirvin.com.json") + body: File.read!("test/fixtures/tesla_mock/mike@osada.macgirvin.com.json"), + headers: [{"content-type", "application/jrd+json"}] }} end @@ -137,14 +151,6 @@ defmodule HttpRequestMock do }} end - def get("https://pawoo.net/users/pekorino.atom", _, _, _) do - {:ok, - %Tesla.Env{ - status: 200, - body: File.read!("test/fixtures/tesla_mock/https___pawoo.net_users_pekorino.atom") - }} - end - def get( "https://pawoo.net/.well-known/webfinger?resource=acct:https://pawoo.net/users/pekorino", _, @@ -159,19 +165,6 @@ defmodule HttpRequestMock do end def get( - "https://social.stopwatchingus-heidelberg.de/api/statuses/user_timeline/18330.atom", - _, - _, - _ - ) do - {:ok, - %Tesla.Env{ - status: 200, - body: File.read!("test/fixtures/tesla_mock/atarifrosch_feed.xml") - }} - end - - def get( "https://social.stopwatchingus-heidelberg.de/.well-known/webfinger?resource=acct:https://social.stopwatchingus-heidelberg.de/user/18330", _, _, @@ -184,27 +177,6 @@ defmodule HttpRequestMock do }} end - def get("https://mamot.fr/users/Skruyb.atom", _, _, _) do - {:ok, - %Tesla.Env{ - status: 200, - body: File.read!("test/fixtures/tesla_mock/https___mamot.fr_users_Skruyb.atom") - }} - end - - def get( - "https://mamot.fr/.well-known/webfinger?resource=acct:https://mamot.fr/users/Skruyb", - _, - _, - [{"accept", "application/xrd+xml,application/jrd+json"}] - ) do - {:ok, - %Tesla.Env{ - status: 200, - body: File.read!("test/fixtures/tesla_mock/skruyb@mamot.fr.atom") - }} - end - def get( "https://social.heldscal.la/.well-known/webfinger?resource=nonexistant@social.heldscal.la", _, @@ -227,7 +199,8 @@ defmodule HttpRequestMock do {:ok, %Tesla.Env{ status: 200, - body: File.read!("test/fixtures/tesla_mock/lain_squeet.me_webfinger.xml") + body: File.read!("test/fixtures/tesla_mock/lain_squeet.me_webfinger.xml"), + headers: [{"content-type", "application/xrd+xml"}] }} end @@ -240,7 +213,8 @@ defmodule HttpRequestMock do {:ok, %Tesla.Env{ status: 200, - body: File.read!("test/fixtures/tesla_mock/lucifermysticus.json") + body: File.read!("test/fixtures/tesla_mock/lucifermysticus.json"), + headers: activitypub_object_headers() }} end @@ -248,7 +222,8 @@ defmodule HttpRequestMock do {:ok, %Tesla.Env{ status: 200, - body: File.read!("test/fixtures/tesla_mock/https___prismo.news__mxb.json") + body: File.read!("test/fixtures/tesla_mock/https___prismo.news__mxb.json"), + headers: activitypub_object_headers() }} end @@ -261,7 +236,8 @@ defmodule HttpRequestMock do {:ok, %Tesla.Env{ status: 200, - body: File.read!("test/fixtures/tesla_mock/kaniini@hubzilla.example.org.json") + body: File.read!("test/fixtures/tesla_mock/kaniini@hubzilla.example.org.json"), + headers: activitypub_object_headers() }} end @@ -269,7 +245,8 @@ defmodule HttpRequestMock do {:ok, %Tesla.Env{ status: 200, - body: File.read!("test/fixtures/tesla_mock/rye.json") + body: File.read!("test/fixtures/tesla_mock/rye.json"), + headers: activitypub_object_headers() }} end @@ -277,7 +254,8 @@ defmodule HttpRequestMock do {:ok, %Tesla.Env{ status: 200, - body: File.read!("test/fixtures/tesla_mock/rye.json") + body: File.read!("test/fixtures/tesla_mock/rye.json"), + headers: activitypub_object_headers() }} end @@ -296,7 +274,8 @@ defmodule HttpRequestMock do {:ok, %Tesla.Env{ status: 200, - body: File.read!("test/fixtures/tesla_mock/puckipedia.com.json") + body: File.read!("test/fixtures/tesla_mock/puckipedia.com.json"), + headers: activitypub_object_headers() }} end @@ -304,7 +283,17 @@ defmodule HttpRequestMock do {:ok, %Tesla.Env{ status: 200, - body: File.read!("test/fixtures/tesla_mock/7even.json") + body: File.read!("test/fixtures/tesla_mock/7even.json"), + headers: activitypub_object_headers() + }} + end + + def get("https://peertube.stream/accounts/createurs", _, _, _) do + {:ok, + %Tesla.Env{ + status: 200, + body: File.read!("test/fixtures/peertube/actor-person.json"), + headers: activitypub_object_headers() }} end @@ -312,7 +301,8 @@ defmodule HttpRequestMock do {:ok, %Tesla.Env{ status: 200, - body: File.read!("test/fixtures/tesla_mock/peertube.moe-vid.json") + body: File.read!("test/fixtures/tesla_mock/peertube.moe-vid.json"), + headers: activitypub_object_headers() }} end @@ -320,7 +310,8 @@ defmodule HttpRequestMock do {:ok, %Tesla.Env{ status: 200, - body: File.read!("test/fixtures/tesla_mock/https___framatube.org_accounts_framasoft.json") + body: File.read!("test/fixtures/tesla_mock/https___framatube.org_accounts_framasoft.json"), + headers: activitypub_object_headers() }} end @@ -328,7 +319,8 @@ defmodule HttpRequestMock do {:ok, %Tesla.Env{ status: 200, - body: File.read!("test/fixtures/tesla_mock/framatube.org-video.json") + body: File.read!("test/fixtures/tesla_mock/framatube.org-video.json"), + headers: activitypub_object_headers() }} end @@ -336,7 +328,8 @@ defmodule HttpRequestMock do {:ok, %Tesla.Env{ status: 200, - body: File.read!("test/fixtures/tesla_mock/craigmaloney.json") + body: File.read!("test/fixtures/tesla_mock/craigmaloney.json"), + headers: activitypub_object_headers() }} end @@ -344,7 +337,8 @@ defmodule HttpRequestMock do {:ok, %Tesla.Env{ status: 200, - body: File.read!("test/fixtures/tesla_mock/peertube-social.json") + body: File.read!("test/fixtures/tesla_mock/peertube-social.json"), + headers: activitypub_object_headers() }} end @@ -354,7 +348,8 @@ defmodule HttpRequestMock do {:ok, %Tesla.Env{ status: 200, - body: File.read!("test/fixtures/tesla_mock/mobilizon.org-event.json") + body: File.read!("test/fixtures/tesla_mock/mobilizon.org-event.json"), + headers: activitypub_object_headers() }} end @@ -362,7 +357,8 @@ defmodule HttpRequestMock do {:ok, %Tesla.Env{ status: 200, - body: File.read!("test/fixtures/tesla_mock/mobilizon.org-user.json") + body: File.read!("test/fixtures/tesla_mock/mobilizon.org-user.json"), + headers: activitypub_object_headers() }} end @@ -370,7 +366,8 @@ defmodule HttpRequestMock do {:ok, %Tesla.Env{ status: 200, - body: File.read!("test/fixtures/tesla_mock/baptiste.gelex.xyz-user.json") + body: File.read!("test/fixtures/tesla_mock/baptiste.gelex.xyz-user.json"), + headers: activitypub_object_headers() }} end @@ -378,7 +375,8 @@ defmodule HttpRequestMock do {:ok, %Tesla.Env{ status: 200, - body: File.read!("test/fixtures/tesla_mock/baptiste.gelex.xyz-article.json") + body: File.read!("test/fixtures/tesla_mock/baptiste.gelex.xyz-article.json"), + headers: activitypub_object_headers() }} end @@ -386,7 +384,8 @@ defmodule HttpRequestMock do {:ok, %Tesla.Env{ status: 200, - body: File.read!("test/fixtures/tesla_mock/wedistribute-article.json") + body: File.read!("test/fixtures/tesla_mock/wedistribute-article.json"), + headers: activitypub_object_headers() }} end @@ -394,7 +393,8 @@ defmodule HttpRequestMock do {:ok, %Tesla.Env{ status: 200, - body: File.read!("test/fixtures/tesla_mock/wedistribute-user.json") + body: File.read!("test/fixtures/tesla_mock/wedistribute-user.json"), + headers: activitypub_object_headers() }} end @@ -402,7 +402,8 @@ defmodule HttpRequestMock do {:ok, %Tesla.Env{ status: 200, - body: File.read!("test/fixtures/tesla_mock/admin@mastdon.example.org.json") + body: File.read!("test/fixtures/tesla_mock/admin@mastdon.example.org.json"), + headers: activitypub_object_headers() }} end @@ -412,7 +413,8 @@ defmodule HttpRequestMock do {:ok, %Tesla.Env{ status: 200, - body: File.read!("test/fixtures/tesla_mock/relay@mastdon.example.org.json") + body: File.read!("test/fixtures/tesla_mock/relay@mastdon.example.org.json"), + headers: activitypub_object_headers() }} end @@ -507,19 +509,6 @@ defmodule HttpRequestMock do }} end - def get( - "https://mamot.fr/.well-known/webfinger?resource=https://mamot.fr/users/Skruyb", - _, - _, - _ - ) do - {:ok, - %Tesla.Env{ - status: 200, - body: File.read!("test/fixtures/tesla_mock/skruyb@mamot.fr.atom") - }} - end - def get("http://pawoo.net/.well-known/host-meta", _, _, _) do {:ok, %Tesla.Env{ @@ -545,23 +534,8 @@ defmodule HttpRequestMock do {:ok, %Tesla.Env{ status: 200, - body: File.read!("test/fixtures/tesla_mock/pekorino@pawoo.net_host_meta.json") - }} - end - - def get("http://zetsubou.xn--q9jyb4c/.well-known/host-meta", _, _, _) do - {:ok, - %Tesla.Env{ - status: 200, - body: File.read!("test/fixtures/tesla_mock/xn--q9jyb4c_host_meta") - }} - end - - def get("https://zetsubou.xn--q9jyb4c/.well-known/host-meta", _, _, _) do - {:ok, - %Tesla.Env{ - status: 200, - body: File.read!("test/fixtures/tesla_mock/xn--q9jyb4c_host_meta") + body: File.read!("test/fixtures/tesla_mock/pekorino@pawoo.net_host_meta.json"), + headers: activitypub_object_headers() }} end @@ -606,7 +580,8 @@ defmodule HttpRequestMock do {:ok, %Tesla.Env{ status: 200, - body: File.read!("test/fixtures/mastodon-note-object.json") + body: File.read!("test/fixtures/mastodon-note-object.json"), + headers: activitypub_object_headers() }} end @@ -630,7 +605,8 @@ defmodule HttpRequestMock do {:ok, %Tesla.Env{ status: 200, - body: File.read!("test/fixtures/tesla_mock/mayumayu.json") + body: File.read!("test/fixtures/tesla_mock/mayumayu.json"), + headers: activitypub_object_headers() }} end @@ -643,18 +619,8 @@ defmodule HttpRequestMock do {:ok, %Tesla.Env{ status: 200, - body: File.read!("test/fixtures/tesla_mock/mayumayupost.json") - }} - end - - def get("https://pleroma.soykaf.com/users/lain/feed.atom", _, _, _) do - {:ok, - %Tesla.Env{ - status: 200, - body: - File.read!( - "test/fixtures/tesla_mock/https___pleroma.soykaf.com_users_lain_feed.atom.xml" - ) + body: File.read!("test/fixtures/tesla_mock/mayumayupost.json"), + headers: activitypub_object_headers() }} end @@ -670,17 +636,6 @@ defmodule HttpRequestMock do }} end - def get("https://shitposter.club/api/statuses/user_timeline/1.atom", _, _, _) do - {:ok, - %Tesla.Env{ - status: 200, - body: - File.read!( - "test/fixtures/tesla_mock/https___shitposter.club_api_statuses_user_timeline_1.atom.xml" - ) - }} - end - def get( "https://shitposter.club/.well-known/webfinger?resource=https://shitposter.club/user/1", _, @@ -694,37 +649,10 @@ defmodule HttpRequestMock do }} end - def get("https://shitposter.club/notice/2827873", _, _, _) do - {:ok, - %Tesla.Env{ - status: 200, - body: File.read!("test/fixtures/tesla_mock/https___shitposter.club_notice_2827873.json") - }} - end - - def get("https://shitposter.club/api/statuses/show/2827873.atom", _, _, _) do - {:ok, - %Tesla.Env{ - status: 200, - body: - File.read!( - "test/fixtures/tesla_mock/https___shitposter.club_api_statuses_show_2827873.atom.xml" - ) - }} - end - def get("https://testing.pleroma.lol/objects/b319022a-4946-44c5-9de9-34801f95507b", _, _, _) do {:ok, %Tesla.Env{status: 200}} end - def get("https://shitposter.club/api/statuses/user_timeline/5381.atom", _, _, _) do - {:ok, - %Tesla.Env{ - status: 200, - body: File.read!("test/fixtures/tesla_mock/spc_5381.atom") - }} - end - def get( "https://shitposter.club/.well-known/webfinger?resource=https://shitposter.club/user/5381", _, @@ -746,14 +674,6 @@ defmodule HttpRequestMock do }} end - def get("https://shitposter.club/api/statuses/show/7369654.atom", _, _, _) do - {:ok, - %Tesla.Env{ - status: 200, - body: File.read!("test/fixtures/tesla_mock/7369654.atom") - }} - end - def get("https://shitposter.club/notice/4027863", _, _, _) do {:ok, %Tesla.Env{ @@ -762,14 +682,6 @@ defmodule HttpRequestMock do }} end - def get("https://social.sakamoto.gq/users/eal/feed.atom", _, _, _) do - {:ok, - %Tesla.Env{ - status: 200, - body: File.read!("test/fixtures/tesla_mock/sakamoto_eal_feed.atom") - }} - end - def get("http://social.sakamoto.gq/.well-known/host-meta", _, _, _) do {:ok, %Tesla.Env{ @@ -791,15 +703,6 @@ defmodule HttpRequestMock do }} end - def get( - "https://social.sakamoto.gq/objects/0ccc1a2c-66b0-4305-b23a-7f7f2b040056", - _, - _, - [{"accept", "application/atom+xml"}] - ) do - {:ok, %Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/sakamoto.atom")}} - end - def get("http://mastodon.social/.well-known/host-meta", _, _, _) do {:ok, %Tesla.Env{ @@ -853,28 +756,6 @@ defmodule HttpRequestMock do {:ok, %Tesla.Env{status: 406, body: ""}} end - def get("http://gs.example.org/index.php/api/statuses/user_timeline/1.atom", _, _, _) do - {:ok, - %Tesla.Env{ - status: 200, - body: - File.read!( - "test/fixtures/tesla_mock/http__gs.example.org_index.php_api_statuses_user_timeline_1.atom.xml" - ) - }} - end - - def get("https://social.heldscal.la/api/statuses/user_timeline/29191.atom", _, _, _) do - {:ok, - %Tesla.Env{ - status: 200, - body: - File.read!( - "test/fixtures/tesla_mock/https___social.heldscal.la_api_statuses_user_timeline_29191.atom.xml" - ) - }} - end - def get("http://squeet.me/.well-known/host-meta", _, _, _) do {:ok, %Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/squeet.me_host_meta")}} @@ -902,7 +783,8 @@ defmodule HttpRequestMock do {:ok, %Tesla.Env{ status: 200, - body: File.read!("test/fixtures/tesla_mock/shp@social.heldscal.la.xml") + body: File.read!("test/fixtures/tesla_mock/shp@social.heldscal.la.xml"), + headers: [{"content-type", "application/xrd+xml"}] }} end @@ -912,7 +794,7 @@ defmodule HttpRequestMock do _, [{"accept", "application/xrd+xml,application/jrd+json"}] ) do - {:ok, %Tesla.Env{status: 200, body: ""}} + {:ok, %Tesla.Env{status: 200, body: "", headers: [{"content-type", "application/jrd+json"}]}} end def get("http://framatube.org/.well-known/host-meta", _, _, _) do @@ -932,7 +814,7 @@ defmodule HttpRequestMock do {:ok, %Tesla.Env{ status: 200, - headers: [{"content-type", "application/json"}], + headers: [{"content-type", "application/jrd+json"}], body: File.read!("test/fixtures/tesla_mock/framasoft@framatube.org.json") }} end @@ -954,7 +836,8 @@ defmodule HttpRequestMock do {:ok, %Tesla.Env{ status: 200, - body: File.read!("test/fixtures/tesla_mock/winterdienst_webfinger.json") + body: File.read!("test/fixtures/tesla_mock/winterdienst_webfinger.json"), + headers: activitypub_object_headers() }} end @@ -991,22 +874,11 @@ defmodule HttpRequestMock do {:ok, %Tesla.Env{ status: 200, - headers: [{"content-type", "application/json"}], + headers: [{"content-type", "application/jrd+json"}], body: File.read!("test/fixtures/tesla_mock/kaniini@gerzilla.de.json") }} end - def get("https://social.heldscal.la/api/statuses/user_timeline/23211.atom", _, _, _) do - {:ok, - %Tesla.Env{ - status: 200, - body: - File.read!( - "test/fixtures/tesla_mock/https___social.heldscal.la_api_statuses_user_timeline_23211.atom.xml" - ) - }} - end - def get( "https://social.heldscal.la/.well-known/webfinger?resource=https://social.heldscal.la/user/23211", _, @@ -1036,17 +908,34 @@ defmodule HttpRequestMock do }} end - def get("https://mastodon.social/users/lambadalambda.atom", _, _, _) do - {:ok, %Tesla.Env{status: 200, body: File.read!("test/fixtures/lambadalambda.atom")}} + def get("https://mastodon.social/users/lambadalambda", _, _, _) do + {:ok, + %Tesla.Env{ + status: 200, + body: File.read!("test/fixtures/lambadalambda.json"), + headers: activitypub_object_headers() + }} end - def get("https://mastodon.social/users/lambadalambda", _, _, _) do - {:ok, %Tesla.Env{status: 200, body: File.read!("test/fixtures/lambadalambda.json")}} + def get("https://mastodon.social/users/lambadalambda/collections/featured", _, _, _) do + {:ok, + %Tesla.Env{ + status: 200, + body: + File.read!("test/fixtures/users_mock/masto_featured.json") + |> String.replace("{{domain}}", "mastodon.social") + |> String.replace("{{nickname}}", "lambadalambda"), + headers: activitypub_object_headers() + }} end def get("https://apfed.club/channel/indio", _, _, _) do {:ok, - %Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/osada-user-indio.json")}} + %Tesla.Env{ + status: 200, + body: File.read!("test/fixtures/tesla_mock/osada-user-indio.json"), + headers: activitypub_object_headers() + }} end def get("https://social.heldscal.la/user/23211", _, _, [{"accept", "application/activity+json"}]) do @@ -1069,7 +958,8 @@ defmodule HttpRequestMock do {:ok, %Tesla.Env{ status: 200, - body: File.read!("test/fixtures/users_mock/masto_closed_followers.json") + body: File.read!("test/fixtures/users_mock/masto_closed_followers.json"), + headers: activitypub_object_headers() }} end @@ -1077,7 +967,8 @@ defmodule HttpRequestMock do {:ok, %Tesla.Env{ status: 200, - body: File.read!("test/fixtures/users_mock/masto_closed_followers_page.json") + body: File.read!("test/fixtures/users_mock/masto_closed_followers_page.json"), + headers: activitypub_object_headers() }} end @@ -1085,7 +976,8 @@ defmodule HttpRequestMock do {:ok, %Tesla.Env{ status: 200, - body: File.read!("test/fixtures/users_mock/masto_closed_following.json") + body: File.read!("test/fixtures/users_mock/masto_closed_following.json"), + headers: activitypub_object_headers() }} end @@ -1093,7 +985,8 @@ defmodule HttpRequestMock do {:ok, %Tesla.Env{ status: 200, - body: File.read!("test/fixtures/users_mock/masto_closed_following_page.json") + body: File.read!("test/fixtures/users_mock/masto_closed_following_page.json"), + headers: activitypub_object_headers() }} end @@ -1101,7 +994,8 @@ defmodule HttpRequestMock do {:ok, %Tesla.Env{ status: 200, - body: File.read!("test/fixtures/users_mock/friendica_followers.json") + body: File.read!("test/fixtures/users_mock/friendica_followers.json"), + headers: activitypub_object_headers() }} end @@ -1109,7 +1003,8 @@ defmodule HttpRequestMock do {:ok, %Tesla.Env{ status: 200, - body: File.read!("test/fixtures/users_mock/friendica_following.json") + body: File.read!("test/fixtures/users_mock/friendica_following.json"), + headers: activitypub_object_headers() }} end @@ -1117,7 +1012,8 @@ defmodule HttpRequestMock do {:ok, %Tesla.Env{ status: 200, - body: File.read!("test/fixtures/users_mock/pleroma_followers.json") + body: File.read!("test/fixtures/users_mock/pleroma_followers.json"), + headers: activitypub_object_headers() }} end @@ -1125,7 +1021,8 @@ defmodule HttpRequestMock do {:ok, %Tesla.Env{ status: 200, - body: File.read!("test/fixtures/users_mock/pleroma_following.json") + body: File.read!("test/fixtures/users_mock/pleroma_following.json"), + headers: activitypub_object_headers() }} end @@ -1187,7 +1084,8 @@ defmodule HttpRequestMock do {:ok, %Tesla.Env{ status: 200, - body: File.read!("test/fixtures/lain.xml") + body: File.read!("test/fixtures/lain.xml"), + headers: [{"content-type", "application/xrd+xml"}] }} end @@ -1200,7 +1098,16 @@ defmodule HttpRequestMock do {:ok, %Tesla.Env{ status: 200, - body: File.read!("test/fixtures/lain.xml") + body: File.read!("test/fixtures/lain.xml"), + headers: [{"content-type", "application/xrd+xml"}] + }} + end + + def get("http://zetsubou.xn--q9jyb4c/.well-known/host-meta", _, _, _) do + {:ok, + %Tesla.Env{ + status: 200, + body: File.read!("test/fixtures/host-meta-zetsubou.xn--q9jyb4c.xml") }} end @@ -1223,7 +1130,8 @@ defmodule HttpRequestMock do {:ok, %Tesla.Env{ status: 200, - body: File.read!("test/fixtures/tesla_mock/https__info.pleroma.site_activity.json") + body: File.read!("test/fixtures/tesla_mock/https__info.pleroma.site_activity.json"), + headers: activitypub_object_headers() }} end @@ -1237,7 +1145,8 @@ defmodule HttpRequestMock do {:ok, %Tesla.Env{ status: 200, - body: File.read!("test/fixtures/tesla_mock/https__info.pleroma.site_activity2.json") + body: File.read!("test/fixtures/tesla_mock/https__info.pleroma.site_activity2.json"), + headers: activitypub_object_headers() }} end @@ -1251,7 +1160,8 @@ defmodule HttpRequestMock do {:ok, %Tesla.Env{ status: 200, - body: File.read!("test/fixtures/tesla_mock/https__info.pleroma.site_activity3.json") + body: File.read!("test/fixtures/tesla_mock/https__info.pleroma.site_activity3.json"), + headers: activitypub_object_headers() }} end @@ -1263,7 +1173,8 @@ defmodule HttpRequestMock do {:ok, %Tesla.Env{ status: 200, - body: File.read!("test/fixtures/tesla_mock/kpherox@mstdn.jp.xml") + body: File.read!("test/fixtures/tesla_mock/kpherox@mstdn.jp.xml"), + headers: [{"content-type", "application/xrd+xml"}] }} end @@ -1284,7 +1195,12 @@ defmodule HttpRequestMock do end def get("http://mastodon.example.org/@admin/99541947525187367", _, _, _) do - {:ok, %Tesla.Env{status: 200, body: File.read!("test/fixtures/mastodon-post-activity.json")}} + {:ok, + %Tesla.Env{ + status: 200, + body: File.read!("test/fixtures/mastodon-post-activity.json"), + headers: activitypub_object_headers() + }} end def get("https://info.pleroma.site/activity4.json", _, _, _) do @@ -1311,7 +1227,8 @@ defmodule HttpRequestMock do {:ok, %Tesla.Env{ status: 200, - body: File.read!("test/fixtures/tesla_mock/misskey_poll_no_end_date.json") + body: File.read!("test/fixtures/tesla_mock/misskey_poll_no_end_date.json"), + headers: activitypub_object_headers() }} end @@ -1320,11 +1237,21 @@ defmodule HttpRequestMock do end def get("https://skippers-bin.com/users/7v1w1r8ce6", _, _, _) do - {:ok, %Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/sjw.json")}} + {:ok, + %Tesla.Env{ + status: 200, + body: File.read!("test/fixtures/tesla_mock/sjw.json"), + headers: activitypub_object_headers() + }} end def get("https://patch.cx/users/rin", _, _, _) do - {:ok, %Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/rin.json")}} + {:ok, + %Tesla.Env{ + status: 200, + body: File.read!("test/fixtures/tesla_mock/rin.json"), + headers: activitypub_object_headers() + }} end def get( @@ -1334,12 +1261,20 @@ defmodule HttpRequestMock do _ ) do {:ok, - %Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/funkwhale_audio.json")}} + %Tesla.Env{ + status: 200, + body: File.read!("test/fixtures/tesla_mock/funkwhale_audio.json"), + headers: activitypub_object_headers() + }} end def get("https://channels.tests.funkwhale.audio/federation/actors/compositions", _, _, _) do {:ok, - %Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/funkwhale_channel.json")}} + %Tesla.Env{ + status: 200, + body: File.read!("test/fixtures/tesla_mock/funkwhale_channel.json"), + headers: activitypub_object_headers() + }} end def get("http://example.com/rel_me/error", _, _, _) do @@ -1347,7 +1282,12 @@ defmodule HttpRequestMock do end def get("https://relay.mastodon.host/actor", _, _, _) do - {:ok, %Tesla.Env{status: 200, body: File.read!("test/fixtures/relay/relay.json")}} + {:ok, + %Tesla.Env{ + status: 200, + body: File.read!("test/fixtures/relay/relay.json"), + headers: activitypub_object_headers() + }} end def get("http://localhost:4001/", _, "", [{"accept", "text/html"}]) do @@ -1362,11 +1302,18 @@ defmodule HttpRequestMock do }} end + def get("https://patch.cx/objects/a399c28e-c821-4820-bc3e-4afeb044c16f", _, _, _) do + {:ok, + %Tesla.Env{ + status: 200, + body: File.read!("test/fixtures/tesla_mock/emoji-in-summary.json"), + headers: activitypub_object_headers() + }} + end + def get(url, query, body, headers) do {:error, - "Mock response not implemented for GET #{inspect(url)}, #{query}, #{inspect(body)}, #{ - inspect(headers) - }"} + "Mock response not implemented for GET #{inspect(url)}, #{query}, #{inspect(body)}, #{inspect(headers)}"} end # POST Requests @@ -1432,8 +1379,21 @@ defmodule HttpRequestMock do def post(url, query, body, headers) do {:error, - "Mock response not implemented for POST #{inspect(url)}, #{query}, #{inspect(body)}, #{ - inspect(headers) - }"} + "Mock response not implemented for POST #{inspect(url)}, #{query}, #{inspect(body)}, #{inspect(headers)}"} + end + + # Most of the rich media mocks are missing HEAD requests, so we just return 404. + @rich_media_mocks [ + "https://example.com/ogp", + "https://example.com/ogp-missing-data", + "https://example.com/twitter-card" + ] + def head(url, _query, _body, _headers) when url in @rich_media_mocks do + {:ok, %Tesla.Env{status: 404, body: ""}} + end + + def head(url, query, body, headers) do + {:error, + "Mock response not implemented for HEAD #{inspect(url)}, #{query}, #{inspect(body)}, #{inspect(headers)}"} end end diff --git a/test/support/mocks.ex b/test/support/mocks.ex new file mode 100644 index 000000000..fd8f825b3 --- /dev/null +++ b/test/support/mocks.ex @@ -0,0 +1,30 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +Mox.defmock(Pleroma.CachexMock, for: Pleroma.Caching) + +Mox.defmock(Pleroma.Web.ActivityPub.ObjectValidatorMock, + for: Pleroma.Web.ActivityPub.ObjectValidator.Validating +) + +Mox.defmock(Pleroma.Web.ActivityPub.MRFMock, + for: Pleroma.Web.ActivityPub.MRF.PipelineFiltering +) + +Mox.defmock(Pleroma.Web.ActivityPub.ActivityPubMock, + for: [ + Pleroma.Web.ActivityPub.ActivityPub.Persisting, + Pleroma.Web.ActivityPub.ActivityPub.Streaming + ] +) + +Mox.defmock(Pleroma.Web.ActivityPub.SideEffectsMock, + for: Pleroma.Web.ActivityPub.SideEffects.Handling +) + +Mox.defmock(Pleroma.Web.FederatorMock, for: Pleroma.Web.Federator.Publishing) + +Mox.defmock(Pleroma.ConfigMock, for: Pleroma.Config.Getting) + +Mox.defmock(Pleroma.LoggerMock, for: Pleroma.Logging) diff --git a/test/support/mrf_module_mock.ex b/test/support/mrf_module_mock.ex index 028ea542a..4d21d7fe0 100644 --- a/test/support/mrf_module_mock.ex +++ b/test/support/mrf_module_mock.ex @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule MRFModuleMock do - @behaviour Pleroma.Web.ActivityPub.MRF + @behaviour Pleroma.Web.ActivityPub.MRF.Policy @impl true def filter(message), do: {:ok, message} diff --git a/test/support/null_cache.ex b/test/support/null_cache.ex new file mode 100644 index 000000000..47c10ebb6 --- /dev/null +++ b/test/support/null_cache.ex @@ -0,0 +1,49 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.NullCache do + @moduledoc """ + A module simulating a permanently empty cache. + """ + @behaviour Pleroma.Caching + + @impl true + def get!(_, _), do: nil + + @impl true + def put(_, _, _, _ \\ nil), do: {:ok, true} + + @impl true + def stream!(_, _), do: [] + + @impl true + def get(_, _), do: {:ok, nil} + + @impl true + def fetch!(_, key, func) do + case func.(key) do + {_, res} -> res + res -> res + end + end + + @impl true + def get_and_update(_, _, func) do + func.(nil) + end + + @impl true + def expire_at(_, _, _), do: {:ok, true} + + @impl true + def exists?(_, _), do: {:ok, false} + + @impl true + def execute!(_, func) do + func.(:nothing) + end + + @impl true + def del(_, _), do: {:ok, true} +end diff --git a/test/support/oban_helpers.ex b/test/support/oban_helpers.ex index 9f90a821c..9b6e5256e 100644 --- a/test/support/oban_helpers.ex +++ b/test/support/oban_helpers.ex @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Tests.ObanHelpers do @@ -7,6 +7,8 @@ defmodule Pleroma.Tests.ObanHelpers do Oban test helpers. """ + require Ecto.Query + alias Pleroma.Repo def wipe_all do @@ -15,6 +17,7 @@ defmodule Pleroma.Tests.ObanHelpers do def perform_all do Oban.Job + |> Ecto.Query.where(state: "available") |> Repo.all() |> perform() end diff --git a/test/support/web_push_http_client_mock.ex b/test/support/web_push_http_client_mock.ex deleted file mode 100644 index 3cd12957d..000000000 --- a/test/support/web_push_http_client_mock.ex +++ /dev/null @@ -1,23 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.WebPushHttpClientMock do - def get(url, headers \\ [], options \\ []) do - { - res, - %Tesla.Env{status: status} - } = Pleroma.HTTP.request(:get, url, "", headers, options) - - {res, %{status_code: status}} - end - - def post(url, body, headers \\ [], options \\ []) do - { - res, - %Tesla.Env{status: status} - } = Pleroma.HTTP.request(:post, url, body, headers, options) - - {res, %{status_code: status}} - end -end diff --git a/test/support/websocket_client.ex b/test/support/websocket_client.ex index 8c9d4b2b4..34b955474 100644 --- a/test/support/websocket_client.ex +++ b/test/support/websocket_client.ex @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Integration.WebsocketClient do diff --git a/test/tasks/config_test.exs b/test/tasks/config_test.exs deleted file mode 100644 index fb12e7fb3..000000000 --- a/test/tasks/config_test.exs +++ /dev/null @@ -1,176 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Mix.Tasks.Pleroma.ConfigTest do - use Pleroma.DataCase - - import Pleroma.Factory - - alias Pleroma.ConfigDB - alias Pleroma.Repo - - setup_all do - Mix.shell(Mix.Shell.Process) - - on_exit(fn -> - Mix.shell(Mix.Shell.IO) - Application.delete_env(:pleroma, :first_setting) - Application.delete_env(:pleroma, :second_setting) - end) - - :ok - end - - setup_all do: clear_config(:configurable_from_database, true) - - test "error if file with custom settings doesn't exist" do - Mix.Tasks.Pleroma.Config.migrate_to_db("config/not_existance_config_file.exs") - - assert_receive {:mix_shell, :info, - [ - "To migrate settings, you must define custom settings in config/not_existance_config_file.exs." - ]}, - 15 - end - - describe "migrate_to_db/1" do - setup do - initial = Application.get_env(:quack, :level) - on_exit(fn -> Application.put_env(:quack, :level, initial) end) - end - - test "filtered settings are migrated to db" do - assert Repo.all(ConfigDB) == [] - - Mix.Tasks.Pleroma.Config.migrate_to_db("test/fixtures/config/temp.secret.exs") - - config1 = ConfigDB.get_by_params(%{group: ":pleroma", key: ":first_setting"}) - config2 = ConfigDB.get_by_params(%{group: ":pleroma", key: ":second_setting"}) - config3 = ConfigDB.get_by_params(%{group: ":quack", key: ":level"}) - refute ConfigDB.get_by_params(%{group: ":pleroma", key: "Pleroma.Repo"}) - refute ConfigDB.get_by_params(%{group: ":postgrex", key: ":json_library"}) - refute ConfigDB.get_by_params(%{group: ":pleroma", key: ":database"}) - - assert config1.value == [key: "value", key2: [Repo]] - assert config2.value == [key: "value2", key2: ["Activity"]] - assert config3.value == :info - end - - test "config table is truncated before migration" do - insert(:config, key: :first_setting, value: [key: "value", key2: ["Activity"]]) - assert Repo.aggregate(ConfigDB, :count, :id) == 1 - - Mix.Tasks.Pleroma.Config.migrate_to_db("test/fixtures/config/temp.secret.exs") - - config = ConfigDB.get_by_params(%{group: ":pleroma", key: ":first_setting"}) - assert config.value == [key: "value", key2: [Repo]] - end - end - - describe "with deletion temp file" do - setup do - temp_file = "config/temp.exported_from_db.secret.exs" - - on_exit(fn -> - :ok = File.rm(temp_file) - end) - - {:ok, temp_file: temp_file} - end - - test "settings are migrated to file and deleted from db", %{temp_file: temp_file} do - insert(:config, key: :setting_first, value: [key: "value", key2: ["Activity"]]) - insert(:config, key: :setting_second, value: [key: "value2", key2: [Repo]]) - insert(:config, group: :quack, key: :level, value: :info) - - Mix.Tasks.Pleroma.Config.run(["migrate_from_db", "--env", "temp", "-d"]) - - assert Repo.all(ConfigDB) == [] - - file = File.read!(temp_file) - assert file =~ "config :pleroma, :setting_first," - assert file =~ "config :pleroma, :setting_second," - assert file =~ "config :quack, :level, :info" - end - - test "load a settings with large values and pass to file", %{temp_file: temp_file} do - insert(:config, - key: :instance, - value: [ - name: "Pleroma", - email: "example@example.com", - notify_email: "noreply@example.com", - description: "A Pleroma instance, an alternative fediverse server", - limit: 5_000, - chat_limit: 5_000, - remote_limit: 100_000, - upload_limit: 16_000_000, - avatar_upload_limit: 2_000_000, - background_upload_limit: 4_000_000, - banner_upload_limit: 4_000_000, - poll_limits: %{ - max_options: 20, - max_option_chars: 200, - min_expiration: 0, - max_expiration: 365 * 24 * 60 * 60 - }, - registrations_open: true, - federating: true, - federation_incoming_replies_max_depth: 100, - federation_reachability_timeout_days: 7, - federation_publisher_modules: [Pleroma.Web.ActivityPub.Publisher], - allow_relay: true, - public: true, - quarantined_instances: [], - managed_config: true, - static_dir: "instance/static/", - allowed_post_formats: ["text/plain", "text/html", "text/markdown", "text/bbcode"], - autofollowed_nicknames: [], - max_pinned_statuses: 1, - attachment_links: false, - max_report_comment_size: 1000, - safe_dm_mentions: false, - healthcheck: false, - remote_post_retention_days: 90, - skip_thread_containment: true, - limit_to_local_content: :unauthenticated, - user_bio_length: 5000, - user_name_length: 100, - max_account_fields: 10, - max_remote_account_fields: 20, - account_field_name_length: 512, - account_field_value_length: 2048, - external_user_synchronization: true, - extended_nickname_format: true, - multi_factor_authentication: [ - totp: [ - digits: 6, - period: 30 - ], - backup_codes: [ - number: 2, - length: 6 - ] - ] - ] - ) - - Mix.Tasks.Pleroma.Config.run(["migrate_from_db", "--env", "temp", "-d"]) - - assert Repo.all(ConfigDB) == [] - assert File.exists?(temp_file) - {:ok, file} = File.read(temp_file) - - header = - if Code.ensure_loaded?(Config.Reader) do - "import Config" - else - "use Mix.Config" - end - - assert file == - "#{header}\n\nconfig :pleroma, :instance,\n name: \"Pleroma\",\n email: \"example@example.com\",\n notify_email: \"noreply@example.com\",\n description: \"A Pleroma instance, an alternative fediverse server\",\n limit: 5000,\n chat_limit: 5000,\n remote_limit: 100_000,\n upload_limit: 16_000_000,\n avatar_upload_limit: 2_000_000,\n background_upload_limit: 4_000_000,\n banner_upload_limit: 4_000_000,\n poll_limits: %{\n max_expiration: 31_536_000,\n max_option_chars: 200,\n max_options: 20,\n min_expiration: 0\n },\n registrations_open: true,\n federating: true,\n federation_incoming_replies_max_depth: 100,\n federation_reachability_timeout_days: 7,\n federation_publisher_modules: [Pleroma.Web.ActivityPub.Publisher],\n allow_relay: true,\n public: true,\n quarantined_instances: [],\n managed_config: true,\n static_dir: \"instance/static/\",\n allowed_post_formats: [\"text/plain\", \"text/html\", \"text/markdown\", \"text/bbcode\"],\n autofollowed_nicknames: [],\n max_pinned_statuses: 1,\n attachment_links: false,\n max_report_comment_size: 1000,\n safe_dm_mentions: false,\n healthcheck: false,\n remote_post_retention_days: 90,\n skip_thread_containment: true,\n limit_to_local_content: :unauthenticated,\n user_bio_length: 5000,\n user_name_length: 100,\n max_account_fields: 10,\n max_remote_account_fields: 20,\n account_field_name_length: 512,\n account_field_value_length: 2048,\n external_user_synchronization: true,\n extended_nickname_format: true,\n multi_factor_authentication: [\n totp: [digits: 6, period: 30],\n backup_codes: [number: 2, length: 6]\n ]\n" - end - end -end diff --git a/test/tasks/email_test.exs b/test/tasks/email_test.exs deleted file mode 100644 index c3af7ef68..000000000 --- a/test/tasks/email_test.exs +++ /dev/null @@ -1,54 +0,0 @@ -defmodule Mix.Tasks.Pleroma.EmailTest do - use Pleroma.DataCase - - import Swoosh.TestAssertions - - alias Pleroma.Config - alias Pleroma.Tests.ObanHelpers - - setup_all do - Mix.shell(Mix.Shell.Process) - - on_exit(fn -> - Mix.shell(Mix.Shell.IO) - end) - - :ok - end - - setup do: clear_config([Pleroma.Emails.Mailer, :enabled], true) - - describe "pleroma.email test" do - test "Sends test email with no given address" do - mail_to = Config.get([:instance, :email]) - - :ok = Mix.Tasks.Pleroma.Email.run(["test"]) - - ObanHelpers.perform_all() - - assert_receive {:mix_shell, :info, [message]} - assert message =~ "Test email has been sent" - - assert_email_sent( - to: mail_to, - html_body: ~r/a test email was requested./i - ) - end - - test "Sends test email with given address" do - mail_to = "hewwo@example.com" - - :ok = Mix.Tasks.Pleroma.Email.run(["test", "--to", mail_to]) - - ObanHelpers.perform_all() - - assert_receive {:mix_shell, :info, [message]} - assert message =~ "Test email has been sent" - - assert_email_sent( - to: mail_to, - html_body: ~r/a test email was requested./i - ) - end - end -end diff --git a/test/test_helper.exs b/test/test_helper.exs index ee880e226..9fb41e985 100644 --- a/test/test_helper.exs +++ b/test/test_helper.exs @@ -1,9 +1,9 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only os_exclude = if :os.type() == {:unix, :darwin}, do: [skip_on_mac: true], else: [] -ExUnit.start(exclude: [:federated | os_exclude]) +ExUnit.start(exclude: [:federated, :erratic] ++ os_exclude) Ecto.Adapters.SQL.Sandbox.mode(Pleroma.Repo, :manual) diff --git a/test/web/activity_pub/mrf/steal_emoji_policy_test.exs b/test/web/activity_pub/mrf/steal_emoji_policy_test.exs deleted file mode 100644 index 3f8222736..000000000 --- a/test/web/activity_pub/mrf/steal_emoji_policy_test.exs +++ /dev/null @@ -1,68 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.ActivityPub.MRF.StealEmojiPolicyTest do - use Pleroma.DataCase - - alias Pleroma.Config - alias Pleroma.Web.ActivityPub.MRF.StealEmojiPolicy - - setup_all do - Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) - :ok - end - - setup do - emoji_path = Path.join(Config.get([:instance, :static_dir]), "emoji/stolen") - File.rm_rf!(emoji_path) - File.mkdir!(emoji_path) - - Pleroma.Emoji.reload() - - on_exit(fn -> - File.rm_rf!(emoji_path) - end) - - :ok - end - - test "does nothing by default" do - installed_emoji = Pleroma.Emoji.get_all() |> Enum.map(fn {k, _} -> k end) - refute "firedfox" in installed_emoji - - message = %{ - "type" => "Create", - "object" => %{ - "emoji" => [{"firedfox", "https://example.org/emoji/firedfox.png"}], - "actor" => "https://example.org/users/admin" - } - } - - assert {:ok, message} == StealEmojiPolicy.filter(message) - - installed_emoji = Pleroma.Emoji.get_all() |> Enum.map(fn {k, _} -> k end) - refute "firedfox" in installed_emoji - end - - test "Steals emoji on unknown shortcode from allowed remote host" do - installed_emoji = Pleroma.Emoji.get_all() |> Enum.map(fn {k, _} -> k end) - refute "firedfox" in installed_emoji - - message = %{ - "type" => "Create", - "object" => %{ - "emoji" => [{"firedfox", "https://example.org/emoji/firedfox.png"}], - "actor" => "https://example.org/users/admin" - } - } - - clear_config([:mrf_steal_emoji, :hosts], ["example.org"]) - clear_config([:mrf_steal_emoji, :size_limit], 284_468) - - assert {:ok, message} == StealEmojiPolicy.filter(message) - - installed_emoji = Pleroma.Emoji.get_all() |> Enum.map(fn {k, _} -> k end) - assert "firedfox" in installed_emoji - end -end diff --git a/test/web/activity_pub/pipeline_test.exs b/test/web/activity_pub/pipeline_test.exs deleted file mode 100644 index f2a231eaf..000000000 --- a/test/web/activity_pub/pipeline_test.exs +++ /dev/null @@ -1,179 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.ActivityPub.PipelineTest do - use Pleroma.DataCase - - import Mock - import Pleroma.Factory - - describe "common_pipeline/2" do - setup do - clear_config([:instance, :federating], true) - :ok - end - - test "when given an `object_data` in meta, Federation will receive a the original activity with the `object` field set to this embedded object" do - activity = insert(:note_activity) - object = %{"id" => "1", "type" => "Love"} - meta = [local: true, object_data: object] - - activity_with_object = %{activity | data: Map.put(activity.data, "object", object)} - - with_mocks([ - {Pleroma.Web.ActivityPub.ObjectValidator, [], [validate: fn o, m -> {:ok, o, m} end]}, - { - Pleroma.Web.ActivityPub.MRF, - [], - [filter: fn o -> {:ok, o} end] - }, - { - Pleroma.Web.ActivityPub.ActivityPub, - [], - [persist: fn o, m -> {:ok, o, m} end] - }, - { - Pleroma.Web.ActivityPub.SideEffects, - [], - [ - handle: fn o, m -> {:ok, o, m} end, - handle_after_transaction: fn m -> m end - ] - }, - { - Pleroma.Web.Federator, - [], - [publish: fn _o -> :ok end] - } - ]) do - assert {:ok, ^activity, ^meta} = - Pleroma.Web.ActivityPub.Pipeline.common_pipeline(activity, meta) - - assert_called(Pleroma.Web.ActivityPub.ObjectValidator.validate(activity, meta)) - assert_called(Pleroma.Web.ActivityPub.MRF.filter(activity)) - assert_called(Pleroma.Web.ActivityPub.ActivityPub.persist(activity, meta)) - assert_called(Pleroma.Web.ActivityPub.SideEffects.handle(activity, meta)) - refute called(Pleroma.Web.Federator.publish(activity)) - assert_called(Pleroma.Web.Federator.publish(activity_with_object)) - end - end - - test "it goes through validation, filtering, persisting, side effects and federation for local activities" do - activity = insert(:note_activity) - meta = [local: true] - - with_mocks([ - {Pleroma.Web.ActivityPub.ObjectValidator, [], [validate: fn o, m -> {:ok, o, m} end]}, - { - Pleroma.Web.ActivityPub.MRF, - [], - [filter: fn o -> {:ok, o} end] - }, - { - Pleroma.Web.ActivityPub.ActivityPub, - [], - [persist: fn o, m -> {:ok, o, m} end] - }, - { - Pleroma.Web.ActivityPub.SideEffects, - [], - [ - handle: fn o, m -> {:ok, o, m} end, - handle_after_transaction: fn m -> m end - ] - }, - { - Pleroma.Web.Federator, - [], - [publish: fn _o -> :ok end] - } - ]) do - assert {:ok, ^activity, ^meta} = - Pleroma.Web.ActivityPub.Pipeline.common_pipeline(activity, meta) - - assert_called(Pleroma.Web.ActivityPub.ObjectValidator.validate(activity, meta)) - assert_called(Pleroma.Web.ActivityPub.MRF.filter(activity)) - assert_called(Pleroma.Web.ActivityPub.ActivityPub.persist(activity, meta)) - assert_called(Pleroma.Web.ActivityPub.SideEffects.handle(activity, meta)) - assert_called(Pleroma.Web.Federator.publish(activity)) - end - end - - test "it goes through validation, filtering, persisting, side effects without federation for remote activities" do - activity = insert(:note_activity) - meta = [local: false] - - with_mocks([ - {Pleroma.Web.ActivityPub.ObjectValidator, [], [validate: fn o, m -> {:ok, o, m} end]}, - { - Pleroma.Web.ActivityPub.MRF, - [], - [filter: fn o -> {:ok, o} end] - }, - { - Pleroma.Web.ActivityPub.ActivityPub, - [], - [persist: fn o, m -> {:ok, o, m} end] - }, - { - Pleroma.Web.ActivityPub.SideEffects, - [], - [handle: fn o, m -> {:ok, o, m} end, handle_after_transaction: fn m -> m end] - }, - { - Pleroma.Web.Federator, - [], - [] - } - ]) do - assert {:ok, ^activity, ^meta} = - Pleroma.Web.ActivityPub.Pipeline.common_pipeline(activity, meta) - - assert_called(Pleroma.Web.ActivityPub.ObjectValidator.validate(activity, meta)) - assert_called(Pleroma.Web.ActivityPub.MRF.filter(activity)) - assert_called(Pleroma.Web.ActivityPub.ActivityPub.persist(activity, meta)) - assert_called(Pleroma.Web.ActivityPub.SideEffects.handle(activity, meta)) - end - end - - test "it goes through validation, filtering, persisting, side effects without federation for local activities if federation is deactivated" do - clear_config([:instance, :federating], false) - - activity = insert(:note_activity) - meta = [local: true] - - with_mocks([ - {Pleroma.Web.ActivityPub.ObjectValidator, [], [validate: fn o, m -> {:ok, o, m} end]}, - { - Pleroma.Web.ActivityPub.MRF, - [], - [filter: fn o -> {:ok, o} end] - }, - { - Pleroma.Web.ActivityPub.ActivityPub, - [], - [persist: fn o, m -> {:ok, o, m} end] - }, - { - Pleroma.Web.ActivityPub.SideEffects, - [], - [handle: fn o, m -> {:ok, o, m} end, handle_after_transaction: fn m -> m end] - }, - { - Pleroma.Web.Federator, - [], - [] - } - ]) do - assert {:ok, ^activity, ^meta} = - Pleroma.Web.ActivityPub.Pipeline.common_pipeline(activity, meta) - - assert_called(Pleroma.Web.ActivityPub.ObjectValidator.validate(activity, meta)) - assert_called(Pleroma.Web.ActivityPub.MRF.filter(activity)) - assert_called(Pleroma.Web.ActivityPub.ActivityPub.persist(activity, meta)) - assert_called(Pleroma.Web.ActivityPub.SideEffects.handle(activity, meta)) - end - end - end -end diff --git a/test/web/activity_pub/transmogrifier_test.exs b/test/web/activity_pub/transmogrifier_test.exs deleted file mode 100644 index 3fa41b0c7..000000000 --- a/test/web/activity_pub/transmogrifier_test.exs +++ /dev/null @@ -1,1379 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do - use Oban.Testing, repo: Pleroma.Repo - use Pleroma.DataCase - - alias Pleroma.Activity - alias Pleroma.Object - alias Pleroma.Object.Fetcher - alias Pleroma.Tests.ObanHelpers - alias Pleroma.User - alias Pleroma.Web.ActivityPub.Transmogrifier - alias Pleroma.Web.AdminAPI.AccountView - alias Pleroma.Web.CommonAPI - - import Mock - import Pleroma.Factory - import ExUnit.CaptureLog - - setup_all do - Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) - :ok - end - - setup do: clear_config([:instance, :max_remote_account_fields]) - - describe "handle_incoming" do - test "it works for incoming notices with tag not being an array (kroeg)" do - data = File.read!("test/fixtures/kroeg-array-less-emoji.json") |> Poison.decode!() - - {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) - object = Object.normalize(data["object"]) - - assert object.data["emoji"] == %{ - "icon_e_smile" => "https://puckipedia.com/forum/images/smilies/icon_e_smile.png" - } - - data = File.read!("test/fixtures/kroeg-array-less-hashtag.json") |> Poison.decode!() - - {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) - object = Object.normalize(data["object"]) - - assert "test" in object.data["tag"] - end - - test "it works for incoming notices with url not being a string (prismo)" do - data = File.read!("test/fixtures/prismo-url-map.json") |> Poison.decode!() - - {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) - object = Object.normalize(data["object"]) - - assert object.data["url"] == "https://prismo.news/posts/83" - end - - test "it cleans up incoming notices which are not really DMs" do - user = insert(:user) - other_user = insert(:user) - - to = [user.ap_id, other_user.ap_id] - - data = - File.read!("test/fixtures/mastodon-post-activity.json") - |> Poison.decode!() - |> Map.put("to", to) - |> Map.put("cc", []) - - object = - data["object"] - |> Map.put("to", to) - |> Map.put("cc", []) - - data = Map.put(data, "object", object) - - {:ok, %Activity{data: data, local: false} = activity} = Transmogrifier.handle_incoming(data) - - assert data["to"] == [] - assert data["cc"] == to - - object_data = Object.normalize(activity).data - - assert object_data["to"] == [] - assert object_data["cc"] == to - end - - test "it ignores an incoming notice if we already have it" do - activity = insert(:note_activity) - - data = - File.read!("test/fixtures/mastodon-post-activity.json") - |> Poison.decode!() - |> Map.put("object", Object.normalize(activity).data) - - {:ok, returned_activity} = Transmogrifier.handle_incoming(data) - - assert activity == returned_activity - end - - @tag capture_log: true - test "it fetches reply-to activities if we don't have them" do - data = - File.read!("test/fixtures/mastodon-post-activity.json") - |> Poison.decode!() - - object = - data["object"] - |> Map.put("inReplyTo", "https://shitposter.club/notice/2827873") - - data = Map.put(data, "object", object) - {:ok, returned_activity} = Transmogrifier.handle_incoming(data) - returned_object = Object.normalize(returned_activity, false) - - assert activity = - Activity.get_create_by_object_ap_id( - "tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment" - ) - - assert returned_object.data["inReplyToAtomUri"] == "https://shitposter.club/notice/2827873" - end - - test "it does not fetch reply-to activities beyond max replies depth limit" do - data = - File.read!("test/fixtures/mastodon-post-activity.json") - |> Poison.decode!() - - object = - data["object"] - |> Map.put("inReplyTo", "https://shitposter.club/notice/2827873") - - data = Map.put(data, "object", object) - - with_mock Pleroma.Web.Federator, - allowed_thread_distance?: fn _ -> false end do - {:ok, returned_activity} = Transmogrifier.handle_incoming(data) - - returned_object = Object.normalize(returned_activity, false) - - refute Activity.get_create_by_object_ap_id( - "tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment" - ) - - assert returned_object.data["inReplyToAtomUri"] == - "https://shitposter.club/notice/2827873" - end - end - - test "it does not crash if the object in inReplyTo can't be fetched" do - data = - File.read!("test/fixtures/mastodon-post-activity.json") - |> Poison.decode!() - - object = - data["object"] - |> Map.put("inReplyTo", "https://404.site/whatever") - - data = - data - |> Map.put("object", object) - - assert capture_log(fn -> - {:ok, _returned_activity} = Transmogrifier.handle_incoming(data) - end) =~ "[warn] Couldn't fetch \"https://404.site/whatever\", error: nil" - end - - test "it does not work for deactivated users" do - data = File.read!("test/fixtures/mastodon-post-activity.json") |> Poison.decode!() - - insert(:user, ap_id: data["actor"], deactivated: true) - - assert {:error, _} = Transmogrifier.handle_incoming(data) - end - - test "it works for incoming notices" do - data = File.read!("test/fixtures/mastodon-post-activity.json") |> Poison.decode!() - - {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) - - assert data["id"] == - "http://mastodon.example.org/users/admin/statuses/99512778738411822/activity" - - assert data["context"] == - "tag:mastodon.example.org,2018-02-12:objectId=20:objectType=Conversation" - - assert data["to"] == ["https://www.w3.org/ns/activitystreams#Public"] - - assert data["cc"] == [ - "http://mastodon.example.org/users/admin/followers", - "http://localtesting.pleroma.lol/users/lain" - ] - - assert data["actor"] == "http://mastodon.example.org/users/admin" - - object_data = Object.normalize(data["object"]).data - - assert object_data["id"] == - "http://mastodon.example.org/users/admin/statuses/99512778738411822" - - assert object_data["to"] == ["https://www.w3.org/ns/activitystreams#Public"] - - assert object_data["cc"] == [ - "http://mastodon.example.org/users/admin/followers", - "http://localtesting.pleroma.lol/users/lain" - ] - - assert object_data["actor"] == "http://mastodon.example.org/users/admin" - assert object_data["attributedTo"] == "http://mastodon.example.org/users/admin" - - assert object_data["context"] == - "tag:mastodon.example.org,2018-02-12:objectId=20:objectType=Conversation" - - assert object_data["sensitive"] == true - - user = User.get_cached_by_ap_id(object_data["actor"]) - - assert user.note_count == 1 - end - - test "it works for incoming notices with hashtags" do - data = File.read!("test/fixtures/mastodon-post-activity-hashtag.json") |> Poison.decode!() - - {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) - object = Object.normalize(data["object"]) - - assert Enum.at(object.data["tag"], 2) == "moo" - end - - test "it works for incoming notices with contentMap" do - data = - File.read!("test/fixtures/mastodon-post-activity-contentmap.json") |> Poison.decode!() - - {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) - object = Object.normalize(data["object"]) - - assert object.data["content"] == - "<p><span class=\"h-card\"><a href=\"http://localtesting.pleroma.lol/users/lain\" class=\"u-url mention\">@<span>lain</span></a></span></p>" - end - - test "it works for incoming notices with to/cc not being an array (kroeg)" do - data = File.read!("test/fixtures/kroeg-post-activity.json") |> Poison.decode!() - - {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) - object = Object.normalize(data["object"]) - - assert object.data["content"] == - "<p>henlo from my Psion netBook</p><p>message sent from my Psion netBook</p>" - end - - test "it ensures that as:Public activities make it to their followers collection" do - user = insert(:user) - - data = - File.read!("test/fixtures/mastodon-post-activity.json") - |> Poison.decode!() - |> Map.put("actor", user.ap_id) - |> Map.put("to", ["https://www.w3.org/ns/activitystreams#Public"]) - |> Map.put("cc", []) - - object = - data["object"] - |> Map.put("attributedTo", user.ap_id) - |> Map.put("to", ["https://www.w3.org/ns/activitystreams#Public"]) - |> Map.put("cc", []) - |> Map.put("id", user.ap_id <> "/activities/12345678") - - data = Map.put(data, "object", object) - - {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) - - assert data["cc"] == [User.ap_followers(user)] - end - - test "it ensures that address fields become lists" do - user = insert(:user) - - data = - File.read!("test/fixtures/mastodon-post-activity.json") - |> Poison.decode!() - |> Map.put("actor", user.ap_id) - |> Map.put("to", nil) - |> Map.put("cc", nil) - - object = - data["object"] - |> Map.put("attributedTo", user.ap_id) - |> Map.put("to", nil) - |> Map.put("cc", nil) - |> Map.put("id", user.ap_id <> "/activities/12345678") - - data = Map.put(data, "object", object) - - {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) - - assert !is_nil(data["to"]) - assert !is_nil(data["cc"]) - end - - test "it strips internal likes" do - data = - File.read!("test/fixtures/mastodon-post-activity.json") - |> Poison.decode!() - - likes = %{ - "first" => - "http://mastodon.example.org/objects/dbdbc507-52c8-490d-9b7c-1e1d52e5c132/likes?page=1", - "id" => "http://mastodon.example.org/objects/dbdbc507-52c8-490d-9b7c-1e1d52e5c132/likes", - "totalItems" => 3, - "type" => "OrderedCollection" - } - - object = Map.put(data["object"], "likes", likes) - data = Map.put(data, "object", object) - - {:ok, %Activity{object: object}} = Transmogrifier.handle_incoming(data) - - refute Map.has_key?(object.data, "likes") - end - - test "it strips internal reactions" do - user = insert(:user) - {:ok, activity} = CommonAPI.post(user, %{status: "#cofe"}) - {:ok, _} = CommonAPI.react_with_emoji(activity.id, user, "📢") - - %{object: object} = Activity.get_by_id_with_object(activity.id) - assert Map.has_key?(object.data, "reactions") - assert Map.has_key?(object.data, "reaction_count") - - object_data = Transmogrifier.strip_internal_fields(object.data) - refute Map.has_key?(object_data, "reactions") - refute Map.has_key?(object_data, "reaction_count") - end - - test "it works for incoming unfollows with an existing follow" do - user = insert(:user) - - follow_data = - File.read!("test/fixtures/mastodon-follow-activity.json") - |> Poison.decode!() - |> Map.put("object", user.ap_id) - - {:ok, %Activity{data: _, local: false}} = Transmogrifier.handle_incoming(follow_data) - - data = - File.read!("test/fixtures/mastodon-unfollow-activity.json") - |> Poison.decode!() - |> Map.put("object", follow_data) - - {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) - - assert data["type"] == "Undo" - assert data["object"]["type"] == "Follow" - assert data["object"]["object"] == user.ap_id - assert data["actor"] == "http://mastodon.example.org/users/admin" - - refute User.following?(User.get_cached_by_ap_id(data["actor"]), user) - end - - test "skip converting the content when it is nil" do - object_id = "https://peertube.social/videos/watch/278d2b7c-0f38-4aaa-afe6-9ecc0c4a34fe" - - {:ok, object} = Fetcher.fetch_and_contain_remote_object_from_id(object_id) - - result = - Pleroma.Web.ActivityPub.Transmogrifier.fix_object(Map.merge(object, %{"content" => nil})) - - assert result["content"] == nil - end - - test "it converts content of object to html" do - object_id = "https://peertube.social/videos/watch/278d2b7c-0f38-4aaa-afe6-9ecc0c4a34fe" - - {:ok, %{"content" => content_markdown}} = - Fetcher.fetch_and_contain_remote_object_from_id(object_id) - - {:ok, %Pleroma.Object{data: %{"content" => content}} = object} = - Fetcher.fetch_object_from_id(object_id) - - assert content_markdown == - "Support this and our other Michigan!/usr/group videos and meetings. Learn more at http://mug.org/membership\n\nTwenty Years in Jail: FreeBSD's Jails, Then and Now\n\nJails started as a limited virtualization system, but over the last two years they've..." - - assert content == - "<p>Support this and our other Michigan!/usr/group videos and meetings. Learn more at <a href=\"http://mug.org/membership\">http://mug.org/membership</a></p><p>Twenty Years in Jail: FreeBSD’s Jails, Then and Now</p><p>Jails started as a limited virtualization system, but over the last two years they’ve…</p>" - - assert object.data["mediaType"] == "text/html" - end - - test "it remaps video URLs as attachments if necessary" do - {:ok, object} = - Fetcher.fetch_object_from_id( - "https://peertube.moe/videos/watch/df5f464b-be8d-46fb-ad81-2d4c2d1630e3" - ) - - assert object.data["url"] == - "https://peertube.moe/videos/watch/df5f464b-be8d-46fb-ad81-2d4c2d1630e3" - - assert object.data["attachment"] == [ - %{ - "type" => "Link", - "mediaType" => "video/mp4", - "url" => [ - %{ - "href" => - "https://peertube.moe/static/webseed/df5f464b-be8d-46fb-ad81-2d4c2d1630e3-480.mp4", - "mediaType" => "video/mp4", - "type" => "Link" - } - ] - } - ] - - {:ok, object} = - Fetcher.fetch_object_from_id( - "https://framatube.org/videos/watch/6050732a-8a7a-43d4-a6cd-809525a1d206" - ) - - assert object.data["attachment"] == [ - %{ - "type" => "Link", - "mediaType" => "video/mp4", - "url" => [ - %{ - "href" => - "https://framatube.org/static/webseed/6050732a-8a7a-43d4-a6cd-809525a1d206-1080.mp4", - "mediaType" => "video/mp4", - "type" => "Link" - } - ] - } - ] - - assert object.data["url"] == - "https://framatube.org/videos/watch/6050732a-8a7a-43d4-a6cd-809525a1d206" - end - - test "it accepts Flag activities" do - user = insert(:user) - other_user = insert(:user) - - {:ok, activity} = CommonAPI.post(user, %{status: "test post"}) - object = Object.normalize(activity) - - note_obj = %{ - "type" => "Note", - "id" => activity.data["id"], - "content" => "test post", - "published" => object.data["published"], - "actor" => AccountView.render("show.json", %{user: user, skip_visibility_check: true}) - } - - message = %{ - "@context" => "https://www.w3.org/ns/activitystreams", - "cc" => [user.ap_id], - "object" => [user.ap_id, activity.data["id"]], - "type" => "Flag", - "content" => "blocked AND reported!!!", - "actor" => other_user.ap_id - } - - assert {:ok, activity} = Transmogrifier.handle_incoming(message) - - assert activity.data["object"] == [user.ap_id, note_obj] - assert activity.data["content"] == "blocked AND reported!!!" - assert activity.data["actor"] == other_user.ap_id - assert activity.data["cc"] == [user.ap_id] - end - - test "it correctly processes messages with non-array to field" do - user = insert(:user) - - message = %{ - "@context" => "https://www.w3.org/ns/activitystreams", - "to" => "https://www.w3.org/ns/activitystreams#Public", - "type" => "Create", - "object" => %{ - "content" => "blah blah blah", - "type" => "Note", - "attributedTo" => user.ap_id, - "inReplyTo" => nil - }, - "actor" => user.ap_id - } - - assert {:ok, activity} = Transmogrifier.handle_incoming(message) - - assert ["https://www.w3.org/ns/activitystreams#Public"] == activity.data["to"] - end - - test "it correctly processes messages with non-array cc field" do - user = insert(:user) - - message = %{ - "@context" => "https://www.w3.org/ns/activitystreams", - "to" => user.follower_address, - "cc" => "https://www.w3.org/ns/activitystreams#Public", - "type" => "Create", - "object" => %{ - "content" => "blah blah blah", - "type" => "Note", - "attributedTo" => user.ap_id, - "inReplyTo" => nil - }, - "actor" => user.ap_id - } - - assert {:ok, activity} = Transmogrifier.handle_incoming(message) - - assert ["https://www.w3.org/ns/activitystreams#Public"] == activity.data["cc"] - assert [user.follower_address] == activity.data["to"] - end - - test "it correctly processes messages with weirdness in address fields" do - user = insert(:user) - - message = %{ - "@context" => "https://www.w3.org/ns/activitystreams", - "to" => [nil, user.follower_address], - "cc" => ["https://www.w3.org/ns/activitystreams#Public", ["¿"]], - "type" => "Create", - "object" => %{ - "content" => "…", - "type" => "Note", - "attributedTo" => user.ap_id, - "inReplyTo" => nil - }, - "actor" => user.ap_id - } - - assert {:ok, activity} = Transmogrifier.handle_incoming(message) - - assert ["https://www.w3.org/ns/activitystreams#Public"] == activity.data["cc"] - assert [user.follower_address] == activity.data["to"] - end - - test "it accepts Move activities" do - old_user = insert(:user) - new_user = insert(:user) - - message = %{ - "@context" => "https://www.w3.org/ns/activitystreams", - "type" => "Move", - "actor" => old_user.ap_id, - "object" => old_user.ap_id, - "target" => new_user.ap_id - } - - assert :error = Transmogrifier.handle_incoming(message) - - {:ok, _new_user} = User.update_and_set_cache(new_user, %{also_known_as: [old_user.ap_id]}) - - assert {:ok, %Activity{} = activity} = Transmogrifier.handle_incoming(message) - assert activity.actor == old_user.ap_id - assert activity.data["actor"] == old_user.ap_id - assert activity.data["object"] == old_user.ap_id - assert activity.data["target"] == new_user.ap_id - assert activity.data["type"] == "Move" - end - end - - describe "`handle_incoming/2`, Mastodon format `replies` handling" do - setup do: clear_config([:activitypub, :note_replies_output_limit], 5) - setup do: clear_config([:instance, :federation_incoming_replies_max_depth]) - - setup do - data = - "test/fixtures/mastodon-post-activity.json" - |> File.read!() - |> Poison.decode!() - - items = get_in(data, ["object", "replies", "first", "items"]) - assert length(items) > 0 - - %{data: data, items: items} - end - - test "schedules background fetching of `replies` items if max thread depth limit allows", %{ - data: data, - items: items - } do - Pleroma.Config.put([:instance, :federation_incoming_replies_max_depth], 10) - - {:ok, _activity} = Transmogrifier.handle_incoming(data) - - for id <- items do - job_args = %{"op" => "fetch_remote", "id" => id, "depth" => 1} - assert_enqueued(worker: Pleroma.Workers.RemoteFetcherWorker, args: job_args) - end - end - - test "does NOT schedule background fetching of `replies` beyond max thread depth limit allows", - %{data: data} do - Pleroma.Config.put([:instance, :federation_incoming_replies_max_depth], 0) - - {:ok, _activity} = Transmogrifier.handle_incoming(data) - - assert all_enqueued(worker: Pleroma.Workers.RemoteFetcherWorker) == [] - end - end - - describe "`handle_incoming/2`, Pleroma format `replies` handling" do - setup do: clear_config([:activitypub, :note_replies_output_limit], 5) - setup do: clear_config([:instance, :federation_incoming_replies_max_depth]) - - setup do - user = insert(:user) - - {:ok, activity} = CommonAPI.post(user, %{status: "post1"}) - - {:ok, reply1} = - CommonAPI.post(user, %{status: "reply1", in_reply_to_status_id: activity.id}) - - {:ok, reply2} = - CommonAPI.post(user, %{status: "reply2", in_reply_to_status_id: activity.id}) - - replies_uris = Enum.map([reply1, reply2], fn a -> a.object.data["id"] end) - - {:ok, federation_output} = Transmogrifier.prepare_outgoing(activity.data) - - Repo.delete(activity.object) - Repo.delete(activity) - - %{federation_output: federation_output, replies_uris: replies_uris} - end - - test "schedules background fetching of `replies` items if max thread depth limit allows", %{ - federation_output: federation_output, - replies_uris: replies_uris - } do - Pleroma.Config.put([:instance, :federation_incoming_replies_max_depth], 1) - - {:ok, _activity} = Transmogrifier.handle_incoming(federation_output) - - for id <- replies_uris do - job_args = %{"op" => "fetch_remote", "id" => id, "depth" => 1} - assert_enqueued(worker: Pleroma.Workers.RemoteFetcherWorker, args: job_args) - end - end - - test "does NOT schedule background fetching of `replies` beyond max thread depth limit allows", - %{federation_output: federation_output} do - Pleroma.Config.put([:instance, :federation_incoming_replies_max_depth], 0) - - {:ok, _activity} = Transmogrifier.handle_incoming(federation_output) - - assert all_enqueued(worker: Pleroma.Workers.RemoteFetcherWorker) == [] - end - end - - describe "prepare outgoing" do - test "it inlines private announced objects" do - user = insert(:user) - - {:ok, activity} = CommonAPI.post(user, %{status: "hey", visibility: "private"}) - - {:ok, announce_activity} = CommonAPI.repeat(activity.id, user) - - {:ok, modified} = Transmogrifier.prepare_outgoing(announce_activity.data) - - assert modified["object"]["content"] == "hey" - assert modified["object"]["actor"] == modified["object"]["attributedTo"] - end - - test "it turns mentions into tags" do - user = insert(:user) - other_user = insert(:user) - - {:ok, activity} = - CommonAPI.post(user, %{status: "hey, @#{other_user.nickname}, how are ya? #2hu"}) - - with_mock Pleroma.Notification, - get_notified_from_activity: fn _, _ -> [] end do - {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) - - object = modified["object"] - - expected_mention = %{ - "href" => other_user.ap_id, - "name" => "@#{other_user.nickname}", - "type" => "Mention" - } - - expected_tag = %{ - "href" => Pleroma.Web.Endpoint.url() <> "/tags/2hu", - "type" => "Hashtag", - "name" => "#2hu" - } - - refute called(Pleroma.Notification.get_notified_from_activity(:_, :_)) - assert Enum.member?(object["tag"], expected_tag) - assert Enum.member?(object["tag"], expected_mention) - end - end - - test "it adds the sensitive property" do - user = insert(:user) - - {:ok, activity} = CommonAPI.post(user, %{status: "#nsfw hey"}) - {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) - - assert modified["object"]["sensitive"] - end - - test "it adds the json-ld context and the conversation property" do - user = insert(:user) - - {:ok, activity} = CommonAPI.post(user, %{status: "hey"}) - {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) - - assert modified["@context"] == - Pleroma.Web.ActivityPub.Utils.make_json_ld_header()["@context"] - - assert modified["object"]["conversation"] == modified["context"] - end - - test "it sets the 'attributedTo' property to the actor of the object if it doesn't have one" do - user = insert(:user) - - {:ok, activity} = CommonAPI.post(user, %{status: "hey"}) - {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) - - assert modified["object"]["actor"] == modified["object"]["attributedTo"] - end - - test "it strips internal hashtag data" do - user = insert(:user) - - {:ok, activity} = CommonAPI.post(user, %{status: "#2hu"}) - - expected_tag = %{ - "href" => Pleroma.Web.Endpoint.url() <> "/tags/2hu", - "type" => "Hashtag", - "name" => "#2hu" - } - - {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) - - assert modified["object"]["tag"] == [expected_tag] - end - - test "it strips internal fields" do - user = insert(:user) - - {:ok, activity} = CommonAPI.post(user, %{status: "#2hu :firefox:"}) - - {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) - - assert length(modified["object"]["tag"]) == 2 - - assert is_nil(modified["object"]["emoji"]) - assert is_nil(modified["object"]["like_count"]) - assert is_nil(modified["object"]["announcements"]) - assert is_nil(modified["object"]["announcement_count"]) - assert is_nil(modified["object"]["context_id"]) - end - - test "it strips internal fields of article" do - activity = insert(:article_activity) - - {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) - - assert length(modified["object"]["tag"]) == 2 - - assert is_nil(modified["object"]["emoji"]) - assert is_nil(modified["object"]["like_count"]) - assert is_nil(modified["object"]["announcements"]) - assert is_nil(modified["object"]["announcement_count"]) - assert is_nil(modified["object"]["context_id"]) - assert is_nil(modified["object"]["likes"]) - end - - test "the directMessage flag is present" do - user = insert(:user) - other_user = insert(:user) - - {:ok, activity} = CommonAPI.post(user, %{status: "2hu :moominmamma:"}) - - {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) - - assert modified["directMessage"] == false - - {:ok, activity} = CommonAPI.post(user, %{status: "@#{other_user.nickname} :moominmamma:"}) - - {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) - - assert modified["directMessage"] == false - - {:ok, activity} = - CommonAPI.post(user, %{ - status: "@#{other_user.nickname} :moominmamma:", - visibility: "direct" - }) - - {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) - - assert modified["directMessage"] == true - end - - test "it strips BCC field" do - user = insert(:user) - {:ok, list} = Pleroma.List.create("foo", user) - - {:ok, activity} = CommonAPI.post(user, %{status: "foobar", visibility: "list:#{list.id}"}) - - {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) - - assert is_nil(modified["bcc"]) - end - - test "it can handle Listen activities" do - listen_activity = insert(:listen) - - {:ok, modified} = Transmogrifier.prepare_outgoing(listen_activity.data) - - assert modified["type"] == "Listen" - - user = insert(:user) - - {:ok, activity} = CommonAPI.listen(user, %{"title" => "lain radio episode 1"}) - - {:ok, _modified} = Transmogrifier.prepare_outgoing(activity.data) - end - end - - describe "user upgrade" do - test "it upgrades a user to activitypub" do - user = - insert(:user, %{ - nickname: "rye@niu.moe", - local: false, - ap_id: "https://niu.moe/users/rye", - follower_address: User.ap_followers(%User{nickname: "rye@niu.moe"}) - }) - - user_two = insert(:user) - Pleroma.FollowingRelationship.follow(user_two, user, :follow_accept) - - {:ok, activity} = CommonAPI.post(user, %{status: "test"}) - {:ok, unrelated_activity} = CommonAPI.post(user_two, %{status: "test"}) - assert "http://localhost:4001/users/rye@niu.moe/followers" in activity.recipients - - user = User.get_cached_by_id(user.id) - assert user.note_count == 1 - - {:ok, user} = Transmogrifier.upgrade_user_from_ap_id("https://niu.moe/users/rye") - ObanHelpers.perform_all() - - assert user.ap_enabled - assert user.note_count == 1 - assert user.follower_address == "https://niu.moe/users/rye/followers" - assert user.following_address == "https://niu.moe/users/rye/following" - - user = User.get_cached_by_id(user.id) - assert user.note_count == 1 - - activity = Activity.get_by_id(activity.id) - assert user.follower_address in activity.recipients - - assert %{ - "url" => [ - %{ - "href" => - "https://cdn.niu.moe/accounts/avatars/000/033/323/original/fd7f8ae0b3ffedc9.jpeg" - } - ] - } = user.avatar - - assert %{ - "url" => [ - %{ - "href" => - "https://cdn.niu.moe/accounts/headers/000/033/323/original/850b3448fa5fd477.png" - } - ] - } = user.banner - - refute "..." in activity.recipients - - unrelated_activity = Activity.get_by_id(unrelated_activity.id) - refute user.follower_address in unrelated_activity.recipients - - user_two = User.get_cached_by_id(user_two.id) - assert User.following?(user_two, user) - refute "..." in User.following(user_two) - end - end - - describe "actor rewriting" do - test "it fixes the actor URL property to be a proper URI" do - data = %{ - "url" => %{"href" => "http://example.com"} - } - - rewritten = Transmogrifier.maybe_fix_user_object(data) - assert rewritten["url"] == "http://example.com" - end - end - - describe "actor origin containment" do - test "it rejects activities which reference objects with bogus origins" do - data = %{ - "@context" => "https://www.w3.org/ns/activitystreams", - "id" => "http://mastodon.example.org/users/admin/activities/1234", - "actor" => "http://mastodon.example.org/users/admin", - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "object" => "https://info.pleroma.site/activity.json", - "type" => "Announce" - } - - assert capture_log(fn -> - {:error, _} = Transmogrifier.handle_incoming(data) - end) =~ "Object containment failed" - end - - test "it rejects activities which reference objects that have an incorrect attribution (variant 1)" do - data = %{ - "@context" => "https://www.w3.org/ns/activitystreams", - "id" => "http://mastodon.example.org/users/admin/activities/1234", - "actor" => "http://mastodon.example.org/users/admin", - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "object" => "https://info.pleroma.site/activity2.json", - "type" => "Announce" - } - - assert capture_log(fn -> - {:error, _} = Transmogrifier.handle_incoming(data) - end) =~ "Object containment failed" - end - - test "it rejects activities which reference objects that have an incorrect attribution (variant 2)" do - data = %{ - "@context" => "https://www.w3.org/ns/activitystreams", - "id" => "http://mastodon.example.org/users/admin/activities/1234", - "actor" => "http://mastodon.example.org/users/admin", - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "object" => "https://info.pleroma.site/activity3.json", - "type" => "Announce" - } - - assert capture_log(fn -> - {:error, _} = Transmogrifier.handle_incoming(data) - end) =~ "Object containment failed" - end - end - - describe "reserialization" do - test "successfully reserializes a message with inReplyTo == nil" do - user = insert(:user) - - message = %{ - "@context" => "https://www.w3.org/ns/activitystreams", - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "cc" => [], - "type" => "Create", - "object" => %{ - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "cc" => [], - "type" => "Note", - "content" => "Hi", - "inReplyTo" => nil, - "attributedTo" => user.ap_id - }, - "actor" => user.ap_id - } - - {:ok, activity} = Transmogrifier.handle_incoming(message) - - {:ok, _} = Transmogrifier.prepare_outgoing(activity.data) - end - - test "successfully reserializes a message with AS2 objects in IR" do - user = insert(:user) - - message = %{ - "@context" => "https://www.w3.org/ns/activitystreams", - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "cc" => [], - "type" => "Create", - "object" => %{ - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "cc" => [], - "type" => "Note", - "content" => "Hi", - "inReplyTo" => nil, - "attributedTo" => user.ap_id, - "tag" => [ - %{"name" => "#2hu", "href" => "http://example.com/2hu", "type" => "Hashtag"}, - %{"name" => "Bob", "href" => "http://example.com/bob", "type" => "Mention"} - ] - }, - "actor" => user.ap_id - } - - {:ok, activity} = Transmogrifier.handle_incoming(message) - - {:ok, _} = Transmogrifier.prepare_outgoing(activity.data) - end - end - - describe "fix_explicit_addressing" do - setup do - user = insert(:user) - [user: user] - end - - test "moves non-explicitly mentioned actors to cc", %{user: user} do - explicitly_mentioned_actors = [ - "https://pleroma.gold/users/user1", - "https://pleroma.gold/user2" - ] - - object = %{ - "actor" => user.ap_id, - "to" => explicitly_mentioned_actors ++ ["https://social.beepboop.ga/users/dirb"], - "cc" => [], - "tag" => - Enum.map(explicitly_mentioned_actors, fn href -> - %{"type" => "Mention", "href" => href} - end) - } - - fixed_object = Transmogrifier.fix_explicit_addressing(object) - assert Enum.all?(explicitly_mentioned_actors, &(&1 in fixed_object["to"])) - refute "https://social.beepboop.ga/users/dirb" in fixed_object["to"] - assert "https://social.beepboop.ga/users/dirb" in fixed_object["cc"] - end - - test "does not move actor's follower collection to cc", %{user: user} do - object = %{ - "actor" => user.ap_id, - "to" => [user.follower_address], - "cc" => [] - } - - fixed_object = Transmogrifier.fix_explicit_addressing(object) - assert user.follower_address in fixed_object["to"] - refute user.follower_address in fixed_object["cc"] - end - - test "removes recipient's follower collection from cc", %{user: user} do - recipient = insert(:user) - - object = %{ - "actor" => user.ap_id, - "to" => [recipient.ap_id, "https://www.w3.org/ns/activitystreams#Public"], - "cc" => [user.follower_address, recipient.follower_address] - } - - fixed_object = Transmogrifier.fix_explicit_addressing(object) - - assert user.follower_address in fixed_object["cc"] - refute recipient.follower_address in fixed_object["cc"] - refute recipient.follower_address in fixed_object["to"] - end - end - - describe "fix_summary/1" do - test "returns fixed object" do - assert Transmogrifier.fix_summary(%{"summary" => nil}) == %{"summary" => ""} - assert Transmogrifier.fix_summary(%{"summary" => "ok"}) == %{"summary" => "ok"} - assert Transmogrifier.fix_summary(%{}) == %{"summary" => ""} - end - end - - describe "fix_in_reply_to/2" do - setup do: clear_config([:instance, :federation_incoming_replies_max_depth]) - - setup do - data = Poison.decode!(File.read!("test/fixtures/mastodon-post-activity.json")) - [data: data] - end - - test "returns not modified object when hasn't containts inReplyTo field", %{data: data} do - assert Transmogrifier.fix_in_reply_to(data) == data - end - - test "returns object with inReplyToAtomUri when denied incoming reply", %{data: data} do - Pleroma.Config.put([:instance, :federation_incoming_replies_max_depth], 0) - - object_with_reply = - Map.put(data["object"], "inReplyTo", "https://shitposter.club/notice/2827873") - - modified_object = Transmogrifier.fix_in_reply_to(object_with_reply) - assert modified_object["inReplyTo"] == "https://shitposter.club/notice/2827873" - assert modified_object["inReplyToAtomUri"] == "https://shitposter.club/notice/2827873" - - object_with_reply = - Map.put(data["object"], "inReplyTo", %{"id" => "https://shitposter.club/notice/2827873"}) - - modified_object = Transmogrifier.fix_in_reply_to(object_with_reply) - assert modified_object["inReplyTo"] == %{"id" => "https://shitposter.club/notice/2827873"} - assert modified_object["inReplyToAtomUri"] == "https://shitposter.club/notice/2827873" - - object_with_reply = - Map.put(data["object"], "inReplyTo", ["https://shitposter.club/notice/2827873"]) - - modified_object = Transmogrifier.fix_in_reply_to(object_with_reply) - assert modified_object["inReplyTo"] == ["https://shitposter.club/notice/2827873"] - assert modified_object["inReplyToAtomUri"] == "https://shitposter.club/notice/2827873" - - object_with_reply = Map.put(data["object"], "inReplyTo", []) - modified_object = Transmogrifier.fix_in_reply_to(object_with_reply) - assert modified_object["inReplyTo"] == [] - assert modified_object["inReplyToAtomUri"] == "" - end - - @tag capture_log: true - test "returns modified object when allowed incoming reply", %{data: data} do - object_with_reply = - Map.put( - data["object"], - "inReplyTo", - "https://shitposter.club/notice/2827873" - ) - - Pleroma.Config.put([:instance, :federation_incoming_replies_max_depth], 5) - modified_object = Transmogrifier.fix_in_reply_to(object_with_reply) - - assert modified_object["inReplyTo"] == - "tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment" - - assert modified_object["inReplyToAtomUri"] == "https://shitposter.club/notice/2827873" - - assert modified_object["context"] == - "tag:shitposter.club,2017-05-05:objectType=thread:nonce=3c16e9c2681f6d26" - end - end - - describe "fix_url/1" do - test "fixes data for object when url is map" do - object = %{ - "url" => %{ - "type" => "Link", - "mimeType" => "video/mp4", - "href" => "https://peede8d-46fb-ad81-2d4c2d1630e3-480.mp4" - } - } - - assert Transmogrifier.fix_url(object) == %{ - "url" => "https://peede8d-46fb-ad81-2d4c2d1630e3-480.mp4" - } - end - - test "fixes data for video object" do - object = %{ - "type" => "Video", - "url" => [ - %{ - "type" => "Link", - "mimeType" => "video/mp4", - "href" => "https://peede8d-46fb-ad81-2d4c2d1630e3-480.mp4" - }, - %{ - "type" => "Link", - "mimeType" => "video/mp4", - "href" => "https://peertube46fb-ad81-2d4c2d1630e3-240.mp4" - }, - %{ - "type" => "Link", - "mimeType" => "text/html", - "href" => "https://peertube.-2d4c2d1630e3" - }, - %{ - "type" => "Link", - "mimeType" => "text/html", - "href" => "https://peertube.-2d4c2d16377-42" - } - ] - } - - assert Transmogrifier.fix_url(object) == %{ - "attachment" => [ - %{ - "href" => "https://peede8d-46fb-ad81-2d4c2d1630e3-480.mp4", - "mimeType" => "video/mp4", - "type" => "Link" - } - ], - "type" => "Video", - "url" => "https://peertube.-2d4c2d1630e3" - } - end - - test "fixes url for not Video object" do - object = %{ - "type" => "Text", - "url" => [ - %{ - "type" => "Link", - "mimeType" => "text/html", - "href" => "https://peertube.-2d4c2d1630e3" - }, - %{ - "type" => "Link", - "mimeType" => "text/html", - "href" => "https://peertube.-2d4c2d16377-42" - } - ] - } - - assert Transmogrifier.fix_url(object) == %{ - "type" => "Text", - "url" => "https://peertube.-2d4c2d1630e3" - } - - assert Transmogrifier.fix_url(%{"type" => "Text", "url" => []}) == %{ - "type" => "Text", - "url" => "" - } - end - - test "retunrs not modified object" do - assert Transmogrifier.fix_url(%{"type" => "Text"}) == %{"type" => "Text"} - end - end - - describe "get_obj_helper/2" do - test "returns nil when cannot normalize object" do - assert capture_log(fn -> - refute Transmogrifier.get_obj_helper("test-obj-id") - end) =~ "Unsupported URI scheme" - end - - @tag capture_log: true - test "returns {:ok, %Object{}} for success case" do - assert {:ok, %Object{}} = - Transmogrifier.get_obj_helper("https://shitposter.club/notice/2827873") - end - end - - describe "fix_attachments/1" do - test "returns not modified object" do - data = Poison.decode!(File.read!("test/fixtures/mastodon-post-activity.json")) - assert Transmogrifier.fix_attachments(data) == data - end - - test "returns modified object when attachment is map" do - assert Transmogrifier.fix_attachments(%{ - "attachment" => %{ - "mediaType" => "video/mp4", - "url" => "https://peertube.moe/stat-480.mp4" - } - }) == %{ - "attachment" => [ - %{ - "mediaType" => "video/mp4", - "type" => "Document", - "url" => [ - %{ - "href" => "https://peertube.moe/stat-480.mp4", - "mediaType" => "video/mp4", - "type" => "Link" - } - ] - } - ] - } - end - - test "returns modified object when attachment is list" do - assert Transmogrifier.fix_attachments(%{ - "attachment" => [ - %{"mediaType" => "video/mp4", "url" => "https://pe.er/stat-480.mp4"}, - %{"mimeType" => "video/mp4", "href" => "https://pe.er/stat-480.mp4"} - ] - }) == %{ - "attachment" => [ - %{ - "mediaType" => "video/mp4", - "type" => "Document", - "url" => [ - %{ - "href" => "https://pe.er/stat-480.mp4", - "mediaType" => "video/mp4", - "type" => "Link" - } - ] - }, - %{ - "mediaType" => "video/mp4", - "type" => "Document", - "url" => [ - %{ - "href" => "https://pe.er/stat-480.mp4", - "mediaType" => "video/mp4", - "type" => "Link" - } - ] - } - ] - } - end - end - - describe "fix_emoji/1" do - test "returns not modified object when object not contains tags" do - data = Poison.decode!(File.read!("test/fixtures/mastodon-post-activity.json")) - assert Transmogrifier.fix_emoji(data) == data - end - - test "returns object with emoji when object contains list tags" do - assert Transmogrifier.fix_emoji(%{ - "tag" => [ - %{"type" => "Emoji", "name" => ":bib:", "icon" => %{"url" => "/test"}}, - %{"type" => "Hashtag"} - ] - }) == %{ - "emoji" => %{"bib" => "/test"}, - "tag" => [ - %{"icon" => %{"url" => "/test"}, "name" => ":bib:", "type" => "Emoji"}, - %{"type" => "Hashtag"} - ] - } - end - - test "returns object with emoji when object contains map tag" do - assert Transmogrifier.fix_emoji(%{ - "tag" => %{"type" => "Emoji", "name" => ":bib:", "icon" => %{"url" => "/test"}} - }) == %{ - "emoji" => %{"bib" => "/test"}, - "tag" => %{"icon" => %{"url" => "/test"}, "name" => ":bib:", "type" => "Emoji"} - } - end - end - - describe "set_replies/1" do - setup do: clear_config([:activitypub, :note_replies_output_limit], 2) - - test "returns unmodified object if activity doesn't have self-replies" do - data = Poison.decode!(File.read!("test/fixtures/mastodon-post-activity.json")) - assert Transmogrifier.set_replies(data) == data - end - - test "sets `replies` collection with a limited number of self-replies" do - [user, another_user] = insert_list(2, :user) - - {:ok, %{id: id1} = activity} = CommonAPI.post(user, %{status: "1"}) - - {:ok, %{id: id2} = self_reply1} = - CommonAPI.post(user, %{status: "self-reply 1", in_reply_to_status_id: id1}) - - {:ok, self_reply2} = - CommonAPI.post(user, %{status: "self-reply 2", in_reply_to_status_id: id1}) - - # Assuming to _not_ be present in `replies` due to :note_replies_output_limit is set to 2 - {:ok, _} = CommonAPI.post(user, %{status: "self-reply 3", in_reply_to_status_id: id1}) - - {:ok, _} = - CommonAPI.post(user, %{ - status: "self-reply to self-reply", - in_reply_to_status_id: id2 - }) - - {:ok, _} = - CommonAPI.post(another_user, %{ - status: "another user's reply", - in_reply_to_status_id: id1 - }) - - object = Object.normalize(activity) - replies_uris = Enum.map([self_reply1, self_reply2], fn a -> a.object.data["id"] end) - - assert %{"type" => "Collection", "items" => ^replies_uris} = - Transmogrifier.set_replies(object.data)["replies"] - end - end - - test "take_emoji_tags/1" do - user = insert(:user, %{emoji: %{"firefox" => "https://example.org/firefox.png"}}) - - assert Transmogrifier.take_emoji_tags(user) == [ - %{ - "icon" => %{"type" => "Image", "url" => "https://example.org/firefox.png"}, - "id" => "https://example.org/firefox.png", - "name" => ":firefox:", - "type" => "Emoji", - "updated" => "1970-01-01T00:00:00Z" - } - ] - end -end diff --git a/test/web/admin_api/controllers/admin_api_controller_test.exs b/test/web/admin_api/controllers/admin_api_controller_test.exs deleted file mode 100644 index 3bc88c6a9..000000000 --- a/test/web/admin_api/controllers/admin_api_controller_test.exs +++ /dev/null @@ -1,1979 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do - use Pleroma.Web.ConnCase - use Oban.Testing, repo: Pleroma.Repo - - import ExUnit.CaptureLog - import Mock - import Pleroma.Factory - import Swoosh.TestAssertions - - alias Pleroma.Activity - alias Pleroma.Config - alias Pleroma.HTML - alias Pleroma.MFA - alias Pleroma.ModerationLog - alias Pleroma.Repo - alias Pleroma.Tests.ObanHelpers - alias Pleroma.User - alias Pleroma.Web - alias Pleroma.Web.ActivityPub.Relay - alias Pleroma.Web.CommonAPI - alias Pleroma.Web.MediaProxy - - setup_all do - Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) - - :ok - end - - setup do - admin = insert(:user, is_admin: true) - token = insert(:oauth_admin_token, user: admin) - - conn = - build_conn() - |> assign(:user, admin) - |> assign(:token, token) - - {:ok, %{admin: admin, token: token, conn: conn}} - end - - test "with valid `admin_token` query parameter, skips OAuth scopes check" do - clear_config([:admin_token], "password123") - - user = insert(:user) - - conn = get(build_conn(), "/api/pleroma/admin/users/#{user.nickname}?admin_token=password123") - - assert json_response(conn, 200) - end - - describe "with [:auth, :enforce_oauth_admin_scope_usage]," do - setup do: clear_config([:auth, :enforce_oauth_admin_scope_usage], true) - - test "GET /api/pleroma/admin/users/:nickname requires admin:read:accounts or broader scope", - %{admin: admin} do - user = insert(:user) - url = "/api/pleroma/admin/users/#{user.nickname}" - - good_token1 = insert(:oauth_token, user: admin, scopes: ["admin"]) - good_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read"]) - good_token3 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts"]) - - bad_token1 = insert(:oauth_token, user: admin, scopes: ["read:accounts"]) - bad_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts:partial"]) - bad_token3 = nil - - for good_token <- [good_token1, good_token2, good_token3] do - conn = - build_conn() - |> assign(:user, admin) - |> assign(:token, good_token) - |> get(url) - - assert json_response(conn, 200) - end - - for good_token <- [good_token1, good_token2, good_token3] do - conn = - build_conn() - |> assign(:user, nil) - |> assign(:token, good_token) - |> get(url) - - assert json_response(conn, :forbidden) - end - - for bad_token <- [bad_token1, bad_token2, bad_token3] do - conn = - build_conn() - |> assign(:user, admin) - |> assign(:token, bad_token) - |> get(url) - - assert json_response(conn, :forbidden) - end - end - end - - describe "unless [:auth, :enforce_oauth_admin_scope_usage]," do - setup do: clear_config([:auth, :enforce_oauth_admin_scope_usage], false) - - test "GET /api/pleroma/admin/users/:nickname requires " <> - "read:accounts or admin:read:accounts or broader scope", - %{admin: admin} do - user = insert(:user) - url = "/api/pleroma/admin/users/#{user.nickname}" - - good_token1 = insert(:oauth_token, user: admin, scopes: ["admin"]) - good_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read"]) - good_token3 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts"]) - good_token4 = insert(:oauth_token, user: admin, scopes: ["read:accounts"]) - good_token5 = insert(:oauth_token, user: admin, scopes: ["read"]) - - good_tokens = [good_token1, good_token2, good_token3, good_token4, good_token5] - - bad_token1 = insert(:oauth_token, user: admin, scopes: ["read:accounts:partial"]) - bad_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts:partial"]) - bad_token3 = nil - - for good_token <- good_tokens do - conn = - build_conn() - |> assign(:user, admin) - |> assign(:token, good_token) - |> get(url) - - assert json_response(conn, 200) - end - - for good_token <- good_tokens do - conn = - build_conn() - |> assign(:user, nil) - |> assign(:token, good_token) - |> get(url) - - assert json_response(conn, :forbidden) - end - - for bad_token <- [bad_token1, bad_token2, bad_token3] do - conn = - build_conn() - |> assign(:user, admin) - |> assign(:token, bad_token) - |> get(url) - - assert json_response(conn, :forbidden) - end - end - end - - describe "DELETE /api/pleroma/admin/users" do - test "single user", %{admin: admin, conn: conn} do - clear_config([:instance, :federating], true) - - user = - insert(:user, - avatar: %{"url" => [%{"href" => "https://someurl"}]}, - banner: %{"url" => [%{"href" => "https://somebanner"}]}, - bio: "Hello world!", - name: "A guy" - ) - - # Create some activities to check they got deleted later - follower = insert(:user) - {:ok, _} = CommonAPI.post(user, %{status: "test"}) - {:ok, _, _, _} = CommonAPI.follow(user, follower) - {:ok, _, _, _} = CommonAPI.follow(follower, user) - user = Repo.get(User, user.id) - assert user.note_count == 1 - assert user.follower_count == 1 - assert user.following_count == 1 - refute user.deactivated - - with_mock Pleroma.Web.Federator, - publish: fn _ -> nil end, - perform: fn _, _ -> nil end do - conn = - conn - |> put_req_header("accept", "application/json") - |> delete("/api/pleroma/admin/users?nickname=#{user.nickname}") - - ObanHelpers.perform_all() - - assert User.get_by_nickname(user.nickname).deactivated - - log_entry = Repo.one(ModerationLog) - - assert ModerationLog.get_log_entry_message(log_entry) == - "@#{admin.nickname} deleted users: @#{user.nickname}" - - assert json_response(conn, 200) == [user.nickname] - - user = Repo.get(User, user.id) - assert user.deactivated - - assert user.avatar == %{} - assert user.banner == %{} - assert user.note_count == 0 - assert user.follower_count == 0 - assert user.following_count == 0 - assert user.bio == "" - assert user.name == nil - - assert called(Pleroma.Web.Federator.publish(:_)) - end - end - - test "multiple users", %{admin: admin, conn: conn} do - user_one = insert(:user) - user_two = insert(:user) - - conn = - conn - |> put_req_header("accept", "application/json") - |> delete("/api/pleroma/admin/users", %{ - nicknames: [user_one.nickname, user_two.nickname] - }) - - log_entry = Repo.one(ModerationLog) - - assert ModerationLog.get_log_entry_message(log_entry) == - "@#{admin.nickname} deleted users: @#{user_one.nickname}, @#{user_two.nickname}" - - response = json_response(conn, 200) - assert response -- [user_one.nickname, user_two.nickname] == [] - end - end - - describe "/api/pleroma/admin/users" do - test "Create", %{conn: conn} do - conn = - conn - |> put_req_header("accept", "application/json") - |> post("/api/pleroma/admin/users", %{ - "users" => [ - %{ - "nickname" => "lain", - "email" => "lain@example.org", - "password" => "test" - }, - %{ - "nickname" => "lain2", - "email" => "lain2@example.org", - "password" => "test" - } - ] - }) - - response = json_response(conn, 200) |> Enum.map(&Map.get(&1, "type")) - assert response == ["success", "success"] - - log_entry = Repo.one(ModerationLog) - - assert ["lain", "lain2"] -- Enum.map(log_entry.data["subjects"], & &1["nickname"]) == [] - end - - test "Cannot create user with existing email", %{conn: conn} do - user = insert(:user) - - conn = - conn - |> put_req_header("accept", "application/json") - |> post("/api/pleroma/admin/users", %{ - "users" => [ - %{ - "nickname" => "lain", - "email" => user.email, - "password" => "test" - } - ] - }) - - assert json_response(conn, 409) == [ - %{ - "code" => 409, - "data" => %{ - "email" => user.email, - "nickname" => "lain" - }, - "error" => "email has already been taken", - "type" => "error" - } - ] - end - - test "Cannot create user with existing nickname", %{conn: conn} do - user = insert(:user) - - conn = - conn - |> put_req_header("accept", "application/json") - |> post("/api/pleroma/admin/users", %{ - "users" => [ - %{ - "nickname" => user.nickname, - "email" => "someuser@plerama.social", - "password" => "test" - } - ] - }) - - assert json_response(conn, 409) == [ - %{ - "code" => 409, - "data" => %{ - "email" => "someuser@plerama.social", - "nickname" => user.nickname - }, - "error" => "nickname has already been taken", - "type" => "error" - } - ] - end - - test "Multiple user creation works in transaction", %{conn: conn} do - user = insert(:user) - - conn = - conn - |> put_req_header("accept", "application/json") - |> post("/api/pleroma/admin/users", %{ - "users" => [ - %{ - "nickname" => "newuser", - "email" => "newuser@pleroma.social", - "password" => "test" - }, - %{ - "nickname" => "lain", - "email" => user.email, - "password" => "test" - } - ] - }) - - assert json_response(conn, 409) == [ - %{ - "code" => 409, - "data" => %{ - "email" => user.email, - "nickname" => "lain" - }, - "error" => "email has already been taken", - "type" => "error" - }, - %{ - "code" => 409, - "data" => %{ - "email" => "newuser@pleroma.social", - "nickname" => "newuser" - }, - "error" => "", - "type" => "error" - } - ] - - assert User.get_by_nickname("newuser") === nil - end - end - - describe "/api/pleroma/admin/users/:nickname" do - test "Show", %{conn: conn} do - user = insert(:user) - - conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}") - - expected = %{ - "deactivated" => false, - "id" => to_string(user.id), - "local" => true, - "nickname" => user.nickname, - "roles" => %{"admin" => false, "moderator" => false}, - "tags" => [], - "avatar" => User.avatar_url(user) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(user.name || user.nickname), - "confirmation_pending" => false, - "approval_pending" => false, - "url" => user.ap_id, - "registration_reason" => nil, - "actor_type" => "Person" - } - - assert expected == json_response(conn, 200) - end - - test "when the user doesn't exist", %{conn: conn} do - user = build(:user) - - conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}") - - assert %{"error" => "Not found"} == json_response(conn, 404) - end - end - - describe "/api/pleroma/admin/users/follow" do - test "allows to force-follow another user", %{admin: admin, conn: conn} do - user = insert(:user) - follower = insert(:user) - - conn - |> put_req_header("accept", "application/json") - |> post("/api/pleroma/admin/users/follow", %{ - "follower" => follower.nickname, - "followed" => user.nickname - }) - - user = User.get_cached_by_id(user.id) - follower = User.get_cached_by_id(follower.id) - - assert User.following?(follower, user) - - log_entry = Repo.one(ModerationLog) - - assert ModerationLog.get_log_entry_message(log_entry) == - "@#{admin.nickname} made @#{follower.nickname} follow @#{user.nickname}" - end - end - - describe "/api/pleroma/admin/users/unfollow" do - test "allows to force-unfollow another user", %{admin: admin, conn: conn} do - user = insert(:user) - follower = insert(:user) - - User.follow(follower, user) - - conn - |> put_req_header("accept", "application/json") - |> post("/api/pleroma/admin/users/unfollow", %{ - "follower" => follower.nickname, - "followed" => user.nickname - }) - - user = User.get_cached_by_id(user.id) - follower = User.get_cached_by_id(follower.id) - - refute User.following?(follower, user) - - log_entry = Repo.one(ModerationLog) - - assert ModerationLog.get_log_entry_message(log_entry) == - "@#{admin.nickname} made @#{follower.nickname} unfollow @#{user.nickname}" - end - end - - describe "PUT /api/pleroma/admin/users/tag" do - setup %{conn: conn} do - user1 = insert(:user, %{tags: ["x"]}) - user2 = insert(:user, %{tags: ["y"]}) - user3 = insert(:user, %{tags: ["unchanged"]}) - - conn = - conn - |> put_req_header("accept", "application/json") - |> put( - "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <> - "#{user2.nickname}&tags[]=foo&tags[]=bar" - ) - - %{conn: conn, user1: user1, user2: user2, user3: user3} - end - - test "it appends specified tags to users with specified nicknames", %{ - conn: conn, - admin: admin, - user1: user1, - user2: user2 - } do - assert empty_json_response(conn) - assert User.get_cached_by_id(user1.id).tags == ["x", "foo", "bar"] - assert User.get_cached_by_id(user2.id).tags == ["y", "foo", "bar"] - - log_entry = Repo.one(ModerationLog) - - users = - [user1.nickname, user2.nickname] - |> Enum.map(&"@#{&1}") - |> Enum.join(", ") - - tags = ["foo", "bar"] |> Enum.join(", ") - - assert ModerationLog.get_log_entry_message(log_entry) == - "@#{admin.nickname} added tags: #{tags} to users: #{users}" - end - - test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do - assert empty_json_response(conn) - assert User.get_cached_by_id(user3.id).tags == ["unchanged"] - end - end - - describe "DELETE /api/pleroma/admin/users/tag" do - setup %{conn: conn} do - user1 = insert(:user, %{tags: ["x"]}) - user2 = insert(:user, %{tags: ["y", "z"]}) - user3 = insert(:user, %{tags: ["unchanged"]}) - - conn = - conn - |> put_req_header("accept", "application/json") - |> delete( - "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <> - "#{user2.nickname}&tags[]=x&tags[]=z" - ) - - %{conn: conn, user1: user1, user2: user2, user3: user3} - end - - test "it removes specified tags from users with specified nicknames", %{ - conn: conn, - admin: admin, - user1: user1, - user2: user2 - } do - assert empty_json_response(conn) - assert User.get_cached_by_id(user1.id).tags == [] - assert User.get_cached_by_id(user2.id).tags == ["y"] - - log_entry = Repo.one(ModerationLog) - - users = - [user1.nickname, user2.nickname] - |> Enum.map(&"@#{&1}") - |> Enum.join(", ") - - tags = ["x", "z"] |> Enum.join(", ") - - assert ModerationLog.get_log_entry_message(log_entry) == - "@#{admin.nickname} removed tags: #{tags} from users: #{users}" - end - - test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do - assert empty_json_response(conn) - assert User.get_cached_by_id(user3.id).tags == ["unchanged"] - end - end - - describe "/api/pleroma/admin/users/:nickname/permission_group" do - test "GET is giving user_info", %{admin: admin, conn: conn} do - conn = - conn - |> put_req_header("accept", "application/json") - |> get("/api/pleroma/admin/users/#{admin.nickname}/permission_group/") - - assert json_response(conn, 200) == %{ - "is_admin" => true, - "is_moderator" => false - } - end - - test "/:right POST, can add to a permission group", %{admin: admin, conn: conn} do - user = insert(:user) - - conn = - conn - |> put_req_header("accept", "application/json") - |> post("/api/pleroma/admin/users/#{user.nickname}/permission_group/admin") - - assert json_response(conn, 200) == %{ - "is_admin" => true - } - - log_entry = Repo.one(ModerationLog) - - assert ModerationLog.get_log_entry_message(log_entry) == - "@#{admin.nickname} made @#{user.nickname} admin" - end - - test "/:right POST, can add to a permission group (multiple)", %{admin: admin, conn: conn} do - user_one = insert(:user) - user_two = insert(:user) - - conn = - conn - |> put_req_header("accept", "application/json") - |> post("/api/pleroma/admin/users/permission_group/admin", %{ - nicknames: [user_one.nickname, user_two.nickname] - }) - - assert json_response(conn, 200) == %{"is_admin" => true} - - log_entry = Repo.one(ModerationLog) - - assert ModerationLog.get_log_entry_message(log_entry) == - "@#{admin.nickname} made @#{user_one.nickname}, @#{user_two.nickname} admin" - end - - test "/:right DELETE, can remove from a permission group", %{admin: admin, conn: conn} do - user = insert(:user, is_admin: true) - - conn = - conn - |> put_req_header("accept", "application/json") - |> delete("/api/pleroma/admin/users/#{user.nickname}/permission_group/admin") - - assert json_response(conn, 200) == %{"is_admin" => false} - - log_entry = Repo.one(ModerationLog) - - assert ModerationLog.get_log_entry_message(log_entry) == - "@#{admin.nickname} revoked admin role from @#{user.nickname}" - end - - test "/:right DELETE, can remove from a permission group (multiple)", %{ - admin: admin, - conn: conn - } do - user_one = insert(:user, is_admin: true) - user_two = insert(:user, is_admin: true) - - conn = - conn - |> put_req_header("accept", "application/json") - |> delete("/api/pleroma/admin/users/permission_group/admin", %{ - nicknames: [user_one.nickname, user_two.nickname] - }) - - assert json_response(conn, 200) == %{"is_admin" => false} - - log_entry = Repo.one(ModerationLog) - - assert ModerationLog.get_log_entry_message(log_entry) == - "@#{admin.nickname} revoked admin role from @#{user_one.nickname}, @#{ - user_two.nickname - }" - end - end - - test "/api/pleroma/admin/users/:nickname/password_reset", %{conn: conn} do - user = insert(:user) - - conn = - conn - |> put_req_header("accept", "application/json") - |> get("/api/pleroma/admin/users/#{user.nickname}/password_reset") - - resp = json_response(conn, 200) - - assert Regex.match?(~r/(http:\/\/|https:\/\/)/, resp["link"]) - end - - describe "GET /api/pleroma/admin/users" do - test "renders users array for the first page", %{conn: conn, admin: admin} do - user = insert(:user, local: false, tags: ["foo", "bar"]) - user2 = insert(:user, approval_pending: true, registration_reason: "I'm a chill dude") - - conn = get(conn, "/api/pleroma/admin/users?page=1") - - users = - [ - %{ - "deactivated" => admin.deactivated, - "id" => admin.id, - "nickname" => admin.nickname, - "roles" => %{"admin" => true, "moderator" => false}, - "local" => true, - "tags" => [], - "avatar" => User.avatar_url(admin) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(admin.name || admin.nickname), - "confirmation_pending" => false, - "approval_pending" => false, - "url" => admin.ap_id, - "registration_reason" => nil, - "actor_type" => "Person" - }, - %{ - "deactivated" => user.deactivated, - "id" => user.id, - "nickname" => user.nickname, - "roles" => %{"admin" => false, "moderator" => false}, - "local" => false, - "tags" => ["foo", "bar"], - "avatar" => User.avatar_url(user) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(user.name || user.nickname), - "confirmation_pending" => false, - "approval_pending" => false, - "url" => user.ap_id, - "registration_reason" => nil, - "actor_type" => "Person" - }, - %{ - "deactivated" => user2.deactivated, - "id" => user2.id, - "nickname" => user2.nickname, - "roles" => %{"admin" => false, "moderator" => false}, - "local" => true, - "tags" => [], - "avatar" => User.avatar_url(user2) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(user2.name || user2.nickname), - "confirmation_pending" => false, - "approval_pending" => true, - "url" => user2.ap_id, - "registration_reason" => "I'm a chill dude", - "actor_type" => "Person" - } - ] - |> Enum.sort_by(& &1["nickname"]) - - assert json_response(conn, 200) == %{ - "count" => 3, - "page_size" => 50, - "users" => users - } - end - - test "pagination works correctly with service users", %{conn: conn} do - service1 = User.get_or_create_service_actor_by_ap_id(Web.base_url() <> "/meido", "meido") - - insert_list(25, :user) - - assert %{"count" => 26, "page_size" => 10, "users" => users1} = - conn - |> get("/api/pleroma/admin/users?page=1&filters=", %{page_size: "10"}) - |> json_response(200) - - assert Enum.count(users1) == 10 - assert service1 not in users1 - - assert %{"count" => 26, "page_size" => 10, "users" => users2} = - conn - |> get("/api/pleroma/admin/users?page=2&filters=", %{page_size: "10"}) - |> json_response(200) - - assert Enum.count(users2) == 10 - assert service1 not in users2 - - assert %{"count" => 26, "page_size" => 10, "users" => users3} = - conn - |> get("/api/pleroma/admin/users?page=3&filters=", %{page_size: "10"}) - |> json_response(200) - - assert Enum.count(users3) == 6 - assert service1 not in users3 - end - - test "renders empty array for the second page", %{conn: conn} do - insert(:user) - - conn = get(conn, "/api/pleroma/admin/users?page=2") - - assert json_response(conn, 200) == %{ - "count" => 2, - "page_size" => 50, - "users" => [] - } - end - - test "regular search", %{conn: conn} do - user = insert(:user, nickname: "bob") - - conn = get(conn, "/api/pleroma/admin/users?query=bo") - - assert json_response(conn, 200) == %{ - "count" => 1, - "page_size" => 50, - "users" => [ - %{ - "deactivated" => user.deactivated, - "id" => user.id, - "nickname" => user.nickname, - "roles" => %{"admin" => false, "moderator" => false}, - "local" => true, - "tags" => [], - "avatar" => User.avatar_url(user) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(user.name || user.nickname), - "confirmation_pending" => false, - "approval_pending" => false, - "url" => user.ap_id, - "registration_reason" => nil, - "actor_type" => "Person" - } - ] - } - end - - test "search by domain", %{conn: conn} do - user = insert(:user, nickname: "nickname@domain.com") - insert(:user) - - conn = get(conn, "/api/pleroma/admin/users?query=domain.com") - - assert json_response(conn, 200) == %{ - "count" => 1, - "page_size" => 50, - "users" => [ - %{ - "deactivated" => user.deactivated, - "id" => user.id, - "nickname" => user.nickname, - "roles" => %{"admin" => false, "moderator" => false}, - "local" => true, - "tags" => [], - "avatar" => User.avatar_url(user) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(user.name || user.nickname), - "confirmation_pending" => false, - "approval_pending" => false, - "url" => user.ap_id, - "registration_reason" => nil, - "actor_type" => "Person" - } - ] - } - end - - test "search by full nickname", %{conn: conn} do - user = insert(:user, nickname: "nickname@domain.com") - insert(:user) - - conn = get(conn, "/api/pleroma/admin/users?query=nickname@domain.com") - - assert json_response(conn, 200) == %{ - "count" => 1, - "page_size" => 50, - "users" => [ - %{ - "deactivated" => user.deactivated, - "id" => user.id, - "nickname" => user.nickname, - "roles" => %{"admin" => false, "moderator" => false}, - "local" => true, - "tags" => [], - "avatar" => User.avatar_url(user) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(user.name || user.nickname), - "confirmation_pending" => false, - "approval_pending" => false, - "url" => user.ap_id, - "registration_reason" => nil, - "actor_type" => "Person" - } - ] - } - end - - test "search by display name", %{conn: conn} do - user = insert(:user, name: "Display name") - insert(:user) - - conn = get(conn, "/api/pleroma/admin/users?name=display") - - assert json_response(conn, 200) == %{ - "count" => 1, - "page_size" => 50, - "users" => [ - %{ - "deactivated" => user.deactivated, - "id" => user.id, - "nickname" => user.nickname, - "roles" => %{"admin" => false, "moderator" => false}, - "local" => true, - "tags" => [], - "avatar" => User.avatar_url(user) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(user.name || user.nickname), - "confirmation_pending" => false, - "approval_pending" => false, - "url" => user.ap_id, - "registration_reason" => nil, - "actor_type" => "Person" - } - ] - } - end - - test "search by email", %{conn: conn} do - user = insert(:user, email: "email@example.com") - insert(:user) - - conn = get(conn, "/api/pleroma/admin/users?email=email@example.com") - - assert json_response(conn, 200) == %{ - "count" => 1, - "page_size" => 50, - "users" => [ - %{ - "deactivated" => user.deactivated, - "id" => user.id, - "nickname" => user.nickname, - "roles" => %{"admin" => false, "moderator" => false}, - "local" => true, - "tags" => [], - "avatar" => User.avatar_url(user) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(user.name || user.nickname), - "confirmation_pending" => false, - "approval_pending" => false, - "url" => user.ap_id, - "registration_reason" => nil, - "actor_type" => "Person" - } - ] - } - end - - test "regular search with page size", %{conn: conn} do - user = insert(:user, nickname: "aalice") - user2 = insert(:user, nickname: "alice") - - conn1 = get(conn, "/api/pleroma/admin/users?query=a&page_size=1&page=1") - - assert json_response(conn1, 200) == %{ - "count" => 2, - "page_size" => 1, - "users" => [ - %{ - "deactivated" => user.deactivated, - "id" => user.id, - "nickname" => user.nickname, - "roles" => %{"admin" => false, "moderator" => false}, - "local" => true, - "tags" => [], - "avatar" => User.avatar_url(user) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(user.name || user.nickname), - "confirmation_pending" => false, - "approval_pending" => false, - "url" => user.ap_id, - "registration_reason" => nil, - "actor_type" => "Person" - } - ] - } - - conn2 = get(conn, "/api/pleroma/admin/users?query=a&page_size=1&page=2") - - assert json_response(conn2, 200) == %{ - "count" => 2, - "page_size" => 1, - "users" => [ - %{ - "deactivated" => user2.deactivated, - "id" => user2.id, - "nickname" => user2.nickname, - "roles" => %{"admin" => false, "moderator" => false}, - "local" => true, - "tags" => [], - "avatar" => User.avatar_url(user2) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(user2.name || user2.nickname), - "confirmation_pending" => false, - "approval_pending" => false, - "url" => user2.ap_id, - "registration_reason" => nil, - "actor_type" => "Person" - } - ] - } - end - - test "only local users" do - admin = insert(:user, is_admin: true, nickname: "john") - token = insert(:oauth_admin_token, user: admin) - user = insert(:user, nickname: "bob") - - insert(:user, nickname: "bobb", local: false) - - conn = - build_conn() - |> assign(:user, admin) - |> assign(:token, token) - |> get("/api/pleroma/admin/users?query=bo&filters=local") - - assert json_response(conn, 200) == %{ - "count" => 1, - "page_size" => 50, - "users" => [ - %{ - "deactivated" => user.deactivated, - "id" => user.id, - "nickname" => user.nickname, - "roles" => %{"admin" => false, "moderator" => false}, - "local" => true, - "tags" => [], - "avatar" => User.avatar_url(user) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(user.name || user.nickname), - "confirmation_pending" => false, - "approval_pending" => false, - "url" => user.ap_id, - "registration_reason" => nil, - "actor_type" => "Person" - } - ] - } - end - - test "only local users with no query", %{conn: conn, admin: old_admin} do - admin = insert(:user, is_admin: true, nickname: "john") - user = insert(:user, nickname: "bob") - - insert(:user, nickname: "bobb", local: false) - - conn = get(conn, "/api/pleroma/admin/users?filters=local") - - users = - [ - %{ - "deactivated" => user.deactivated, - "id" => user.id, - "nickname" => user.nickname, - "roles" => %{"admin" => false, "moderator" => false}, - "local" => true, - "tags" => [], - "avatar" => User.avatar_url(user) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(user.name || user.nickname), - "confirmation_pending" => false, - "approval_pending" => false, - "url" => user.ap_id, - "registration_reason" => nil, - "actor_type" => "Person" - }, - %{ - "deactivated" => admin.deactivated, - "id" => admin.id, - "nickname" => admin.nickname, - "roles" => %{"admin" => true, "moderator" => false}, - "local" => true, - "tags" => [], - "avatar" => User.avatar_url(admin) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(admin.name || admin.nickname), - "confirmation_pending" => false, - "approval_pending" => false, - "url" => admin.ap_id, - "registration_reason" => nil, - "actor_type" => "Person" - }, - %{ - "deactivated" => false, - "id" => old_admin.id, - "local" => true, - "nickname" => old_admin.nickname, - "roles" => %{"admin" => true, "moderator" => false}, - "tags" => [], - "avatar" => User.avatar_url(old_admin) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(old_admin.name || old_admin.nickname), - "confirmation_pending" => false, - "approval_pending" => false, - "url" => old_admin.ap_id, - "registration_reason" => nil, - "actor_type" => "Person" - } - ] - |> Enum.sort_by(& &1["nickname"]) - - assert json_response(conn, 200) == %{ - "count" => 3, - "page_size" => 50, - "users" => users - } - end - - test "only unapproved users", %{conn: conn} do - user = - insert(:user, - nickname: "sadboy", - approval_pending: true, - registration_reason: "Plz let me in!" - ) - - insert(:user, nickname: "happyboy", approval_pending: false) - - conn = get(conn, "/api/pleroma/admin/users?filters=need_approval") - - users = - [ - %{ - "deactivated" => user.deactivated, - "id" => user.id, - "nickname" => user.nickname, - "roles" => %{"admin" => false, "moderator" => false}, - "local" => true, - "tags" => [], - "avatar" => User.avatar_url(user) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(user.name || user.nickname), - "confirmation_pending" => false, - "approval_pending" => true, - "url" => user.ap_id, - "registration_reason" => "Plz let me in!", - "actor_type" => "Person" - } - ] - |> Enum.sort_by(& &1["nickname"]) - - assert json_response(conn, 200) == %{ - "count" => 1, - "page_size" => 50, - "users" => users - } - end - - test "load only admins", %{conn: conn, admin: admin} do - second_admin = insert(:user, is_admin: true) - insert(:user) - insert(:user) - - conn = get(conn, "/api/pleroma/admin/users?filters=is_admin") - - users = - [ - %{ - "deactivated" => false, - "id" => admin.id, - "nickname" => admin.nickname, - "roles" => %{"admin" => true, "moderator" => false}, - "local" => admin.local, - "tags" => [], - "avatar" => User.avatar_url(admin) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(admin.name || admin.nickname), - "confirmation_pending" => false, - "approval_pending" => false, - "url" => admin.ap_id, - "registration_reason" => nil, - "actor_type" => "Person" - }, - %{ - "deactivated" => false, - "id" => second_admin.id, - "nickname" => second_admin.nickname, - "roles" => %{"admin" => true, "moderator" => false}, - "local" => second_admin.local, - "tags" => [], - "avatar" => User.avatar_url(second_admin) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(second_admin.name || second_admin.nickname), - "confirmation_pending" => false, - "approval_pending" => false, - "url" => second_admin.ap_id, - "registration_reason" => nil, - "actor_type" => "Person" - } - ] - |> Enum.sort_by(& &1["nickname"]) - - assert json_response(conn, 200) == %{ - "count" => 2, - "page_size" => 50, - "users" => users - } - end - - test "load only moderators", %{conn: conn} do - moderator = insert(:user, is_moderator: true) - insert(:user) - insert(:user) - - conn = get(conn, "/api/pleroma/admin/users?filters=is_moderator") - - assert json_response(conn, 200) == %{ - "count" => 1, - "page_size" => 50, - "users" => [ - %{ - "deactivated" => false, - "id" => moderator.id, - "nickname" => moderator.nickname, - "roles" => %{"admin" => false, "moderator" => true}, - "local" => moderator.local, - "tags" => [], - "avatar" => User.avatar_url(moderator) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(moderator.name || moderator.nickname), - "confirmation_pending" => false, - "approval_pending" => false, - "url" => moderator.ap_id, - "registration_reason" => nil, - "actor_type" => "Person" - } - ] - } - end - - test "load users with tags list", %{conn: conn} do - user1 = insert(:user, tags: ["first"]) - user2 = insert(:user, tags: ["second"]) - insert(:user) - insert(:user) - - conn = get(conn, "/api/pleroma/admin/users?tags[]=first&tags[]=second") - - users = - [ - %{ - "deactivated" => false, - "id" => user1.id, - "nickname" => user1.nickname, - "roles" => %{"admin" => false, "moderator" => false}, - "local" => user1.local, - "tags" => ["first"], - "avatar" => User.avatar_url(user1) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(user1.name || user1.nickname), - "confirmation_pending" => false, - "approval_pending" => false, - "url" => user1.ap_id, - "registration_reason" => nil, - "actor_type" => "Person" - }, - %{ - "deactivated" => false, - "id" => user2.id, - "nickname" => user2.nickname, - "roles" => %{"admin" => false, "moderator" => false}, - "local" => user2.local, - "tags" => ["second"], - "avatar" => User.avatar_url(user2) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(user2.name || user2.nickname), - "confirmation_pending" => false, - "approval_pending" => false, - "url" => user2.ap_id, - "registration_reason" => nil, - "actor_type" => "Person" - } - ] - |> Enum.sort_by(& &1["nickname"]) - - assert json_response(conn, 200) == %{ - "count" => 2, - "page_size" => 50, - "users" => users - } - end - - test "`active` filters out users pending approval", %{token: token} do - insert(:user, approval_pending: true) - %{id: user_id} = insert(:user, approval_pending: false) - %{id: admin_id} = token.user - - conn = - build_conn() - |> assign(:user, token.user) - |> assign(:token, token) - |> get("/api/pleroma/admin/users?filters=active") - - assert %{ - "count" => 2, - "page_size" => 50, - "users" => [ - %{"id" => ^admin_id}, - %{"id" => ^user_id} - ] - } = json_response(conn, 200) - end - - test "it works with multiple filters" do - admin = insert(:user, nickname: "john", is_admin: true) - token = insert(:oauth_admin_token, user: admin) - user = insert(:user, nickname: "bob", local: false, deactivated: true) - - insert(:user, nickname: "ken", local: true, deactivated: true) - insert(:user, nickname: "bobb", local: false, deactivated: false) - - conn = - build_conn() - |> assign(:user, admin) - |> assign(:token, token) - |> get("/api/pleroma/admin/users?filters=deactivated,external") - - assert json_response(conn, 200) == %{ - "count" => 1, - "page_size" => 50, - "users" => [ - %{ - "deactivated" => user.deactivated, - "id" => user.id, - "nickname" => user.nickname, - "roles" => %{"admin" => false, "moderator" => false}, - "local" => user.local, - "tags" => [], - "avatar" => User.avatar_url(user) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(user.name || user.nickname), - "confirmation_pending" => false, - "approval_pending" => false, - "url" => user.ap_id, - "registration_reason" => nil, - "actor_type" => "Person" - } - ] - } - end - - test "it omits relay user", %{admin: admin, conn: conn} do - assert %User{} = Relay.get_actor() - - conn = get(conn, "/api/pleroma/admin/users") - - assert json_response(conn, 200) == %{ - "count" => 1, - "page_size" => 50, - "users" => [ - %{ - "deactivated" => admin.deactivated, - "id" => admin.id, - "nickname" => admin.nickname, - "roles" => %{"admin" => true, "moderator" => false}, - "local" => true, - "tags" => [], - "avatar" => User.avatar_url(admin) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(admin.name || admin.nickname), - "confirmation_pending" => false, - "approval_pending" => false, - "url" => admin.ap_id, - "registration_reason" => nil, - "actor_type" => "Person" - } - ] - } - end - end - - test "PATCH /api/pleroma/admin/users/activate", %{admin: admin, conn: conn} do - user_one = insert(:user, deactivated: true) - user_two = insert(:user, deactivated: true) - - conn = - patch( - conn, - "/api/pleroma/admin/users/activate", - %{nicknames: [user_one.nickname, user_two.nickname]} - ) - - response = json_response(conn, 200) - assert Enum.map(response["users"], & &1["deactivated"]) == [false, false] - - log_entry = Repo.one(ModerationLog) - - assert ModerationLog.get_log_entry_message(log_entry) == - "@#{admin.nickname} activated users: @#{user_one.nickname}, @#{user_two.nickname}" - end - - test "PATCH /api/pleroma/admin/users/deactivate", %{admin: admin, conn: conn} do - user_one = insert(:user, deactivated: false) - user_two = insert(:user, deactivated: false) - - conn = - patch( - conn, - "/api/pleroma/admin/users/deactivate", - %{nicknames: [user_one.nickname, user_two.nickname]} - ) - - response = json_response(conn, 200) - assert Enum.map(response["users"], & &1["deactivated"]) == [true, true] - - log_entry = Repo.one(ModerationLog) - - assert ModerationLog.get_log_entry_message(log_entry) == - "@#{admin.nickname} deactivated users: @#{user_one.nickname}, @#{user_two.nickname}" - end - - test "PATCH /api/pleroma/admin/users/approve", %{admin: admin, conn: conn} do - user_one = insert(:user, approval_pending: true) - user_two = insert(:user, approval_pending: true) - - conn = - patch( - conn, - "/api/pleroma/admin/users/approve", - %{nicknames: [user_one.nickname, user_two.nickname]} - ) - - response = json_response(conn, 200) - assert Enum.map(response["users"], & &1["approval_pending"]) == [false, false] - - log_entry = Repo.one(ModerationLog) - - assert ModerationLog.get_log_entry_message(log_entry) == - "@#{admin.nickname} approved users: @#{user_one.nickname}, @#{user_two.nickname}" - end - - test "PATCH /api/pleroma/admin/users/:nickname/toggle_activation", %{admin: admin, conn: conn} do - user = insert(:user) - - conn = patch(conn, "/api/pleroma/admin/users/#{user.nickname}/toggle_activation") - - assert json_response(conn, 200) == - %{ - "deactivated" => !user.deactivated, - "id" => user.id, - "nickname" => user.nickname, - "roles" => %{"admin" => false, "moderator" => false}, - "local" => true, - "tags" => [], - "avatar" => User.avatar_url(user) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(user.name || user.nickname), - "confirmation_pending" => false, - "approval_pending" => false, - "url" => user.ap_id, - "registration_reason" => nil, - "actor_type" => "Person" - } - - log_entry = Repo.one(ModerationLog) - - assert ModerationLog.get_log_entry_message(log_entry) == - "@#{admin.nickname} deactivated users: @#{user.nickname}" - end - - describe "PUT disable_mfa" do - test "returns 200 and disable 2fa", %{conn: conn} do - user = - insert(:user, - multi_factor_authentication_settings: %MFA.Settings{ - enabled: true, - totp: %MFA.Settings.TOTP{secret: "otp_secret", confirmed: true} - } - ) - - response = - conn - |> put("/api/pleroma/admin/users/disable_mfa", %{nickname: user.nickname}) - |> json_response(200) - - assert response == user.nickname - mfa_settings = refresh_record(user).multi_factor_authentication_settings - - refute mfa_settings.enabled - refute mfa_settings.totp.confirmed - end - - test "returns 404 if user not found", %{conn: conn} do - response = - conn - |> put("/api/pleroma/admin/users/disable_mfa", %{nickname: "nickname"}) - |> json_response(404) - - assert response == %{"error" => "Not found"} - end - end - - describe "GET /api/pleroma/admin/restart" do - setup do: clear_config(:configurable_from_database, true) - - test "pleroma restarts", %{conn: conn} do - capture_log(fn -> - assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{} - end) =~ "pleroma restarted" - - refute Restarter.Pleroma.need_reboot?() - end - end - - test "need_reboot flag", %{conn: conn} do - assert conn - |> get("/api/pleroma/admin/need_reboot") - |> json_response(200) == %{"need_reboot" => false} - - Restarter.Pleroma.need_reboot() - - assert conn - |> get("/api/pleroma/admin/need_reboot") - |> json_response(200) == %{"need_reboot" => true} - - on_exit(fn -> Restarter.Pleroma.refresh() end) - end - - describe "GET /api/pleroma/admin/users/:nickname/statuses" do - setup do - user = insert(:user) - - date1 = (DateTime.to_unix(DateTime.utc_now()) + 2000) |> DateTime.from_unix!() - date2 = (DateTime.to_unix(DateTime.utc_now()) + 1000) |> DateTime.from_unix!() - date3 = (DateTime.to_unix(DateTime.utc_now()) + 3000) |> DateTime.from_unix!() - - insert(:note_activity, user: user, published: date1) - insert(:note_activity, user: user, published: date2) - insert(:note_activity, user: user, published: date3) - - %{user: user} - end - - test "renders user's statuses", %{conn: conn, user: user} do - conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses") - - assert json_response(conn, 200) |> length() == 3 - end - - test "renders user's statuses with a limit", %{conn: conn, user: user} do - conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?page_size=2") - - assert json_response(conn, 200) |> length() == 2 - end - - test "doesn't return private statuses by default", %{conn: conn, user: user} do - {:ok, _private_status} = CommonAPI.post(user, %{status: "private", visibility: "private"}) - - {:ok, _public_status} = CommonAPI.post(user, %{status: "public", visibility: "public"}) - - conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses") - - assert json_response(conn, 200) |> length() == 4 - end - - test "returns private statuses with godmode on", %{conn: conn, user: user} do - {:ok, _private_status} = CommonAPI.post(user, %{status: "private", visibility: "private"}) - - {:ok, _public_status} = CommonAPI.post(user, %{status: "public", visibility: "public"}) - - conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?godmode=true") - - assert json_response(conn, 200) |> length() == 5 - end - - test "excludes reblogs by default", %{conn: conn, user: user} do - other_user = insert(:user) - {:ok, activity} = CommonAPI.post(user, %{status: "."}) - {:ok, %Activity{}} = CommonAPI.repeat(activity.id, other_user) - - conn_res = get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses") - assert json_response(conn_res, 200) |> length() == 0 - - conn_res = - get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses?with_reblogs=true") - - assert json_response(conn_res, 200) |> length() == 1 - end - end - - describe "GET /api/pleroma/admin/moderation_log" do - setup do - moderator = insert(:user, is_moderator: true) - - %{moderator: moderator} - end - - test "returns the log", %{conn: conn, admin: admin} do - Repo.insert(%ModerationLog{ - data: %{ - actor: %{ - "id" => admin.id, - "nickname" => admin.nickname, - "type" => "user" - }, - action: "relay_follow", - target: "https://example.org/relay" - }, - inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second) - }) - - Repo.insert(%ModerationLog{ - data: %{ - actor: %{ - "id" => admin.id, - "nickname" => admin.nickname, - "type" => "user" - }, - action: "relay_unfollow", - target: "https://example.org/relay" - }, - inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second) - }) - - conn = get(conn, "/api/pleroma/admin/moderation_log") - - response = json_response(conn, 200) - [first_entry, second_entry] = response["items"] - - assert response["total"] == 2 - assert first_entry["data"]["action"] == "relay_unfollow" - - assert first_entry["message"] == - "@#{admin.nickname} unfollowed relay: https://example.org/relay" - - assert second_entry["data"]["action"] == "relay_follow" - - assert second_entry["message"] == - "@#{admin.nickname} followed relay: https://example.org/relay" - end - - test "returns the log with pagination", %{conn: conn, admin: admin} do - Repo.insert(%ModerationLog{ - data: %{ - actor: %{ - "id" => admin.id, - "nickname" => admin.nickname, - "type" => "user" - }, - action: "relay_follow", - target: "https://example.org/relay" - }, - inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second) - }) - - Repo.insert(%ModerationLog{ - data: %{ - actor: %{ - "id" => admin.id, - "nickname" => admin.nickname, - "type" => "user" - }, - action: "relay_unfollow", - target: "https://example.org/relay" - }, - inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second) - }) - - conn1 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=1") - - response1 = json_response(conn1, 200) - [first_entry] = response1["items"] - - assert response1["total"] == 2 - assert response1["items"] |> length() == 1 - assert first_entry["data"]["action"] == "relay_unfollow" - - assert first_entry["message"] == - "@#{admin.nickname} unfollowed relay: https://example.org/relay" - - conn2 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=2") - - response2 = json_response(conn2, 200) - [second_entry] = response2["items"] - - assert response2["total"] == 2 - assert response2["items"] |> length() == 1 - assert second_entry["data"]["action"] == "relay_follow" - - assert second_entry["message"] == - "@#{admin.nickname} followed relay: https://example.org/relay" - end - - test "filters log by date", %{conn: conn, admin: admin} do - first_date = "2017-08-15T15:47:06Z" - second_date = "2017-08-20T15:47:06Z" - - Repo.insert(%ModerationLog{ - data: %{ - actor: %{ - "id" => admin.id, - "nickname" => admin.nickname, - "type" => "user" - }, - action: "relay_follow", - target: "https://example.org/relay" - }, - inserted_at: NaiveDateTime.from_iso8601!(first_date) - }) - - Repo.insert(%ModerationLog{ - data: %{ - actor: %{ - "id" => admin.id, - "nickname" => admin.nickname, - "type" => "user" - }, - action: "relay_unfollow", - target: "https://example.org/relay" - }, - inserted_at: NaiveDateTime.from_iso8601!(second_date) - }) - - conn1 = - get( - conn, - "/api/pleroma/admin/moderation_log?start_date=#{second_date}" - ) - - response1 = json_response(conn1, 200) - [first_entry] = response1["items"] - - assert response1["total"] == 1 - assert first_entry["data"]["action"] == "relay_unfollow" - - assert first_entry["message"] == - "@#{admin.nickname} unfollowed relay: https://example.org/relay" - end - - test "returns log filtered by user", %{conn: conn, admin: admin, moderator: moderator} do - Repo.insert(%ModerationLog{ - data: %{ - actor: %{ - "id" => admin.id, - "nickname" => admin.nickname, - "type" => "user" - }, - action: "relay_follow", - target: "https://example.org/relay" - } - }) - - Repo.insert(%ModerationLog{ - data: %{ - actor: %{ - "id" => moderator.id, - "nickname" => moderator.nickname, - "type" => "user" - }, - action: "relay_unfollow", - target: "https://example.org/relay" - } - }) - - conn1 = get(conn, "/api/pleroma/admin/moderation_log?user_id=#{moderator.id}") - - response1 = json_response(conn1, 200) - [first_entry] = response1["items"] - - assert response1["total"] == 1 - assert get_in(first_entry, ["data", "actor", "id"]) == moderator.id - end - - test "returns log filtered by search", %{conn: conn, moderator: moderator} do - ModerationLog.insert_log(%{ - actor: moderator, - action: "relay_follow", - target: "https://example.org/relay" - }) - - ModerationLog.insert_log(%{ - actor: moderator, - action: "relay_unfollow", - target: "https://example.org/relay" - }) - - conn1 = get(conn, "/api/pleroma/admin/moderation_log?search=unfo") - - response1 = json_response(conn1, 200) - [first_entry] = response1["items"] - - assert response1["total"] == 1 - - assert get_in(first_entry, ["data", "message"]) == - "@#{moderator.nickname} unfollowed relay: https://example.org/relay" - end - end - - test "gets a remote users when [:instance, :limit_to_local_content] is set to :unauthenticated", - %{conn: conn} do - clear_config(Pleroma.Config.get([:instance, :limit_to_local_content]), :unauthenticated) - user = insert(:user, %{local: false, nickname: "u@peer1.com"}) - conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials") - - assert json_response(conn, 200) - end - - describe "GET /users/:nickname/credentials" do - test "gets the user credentials", %{conn: conn} do - user = insert(:user) - conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials") - - response = assert json_response(conn, 200) - assert response["email"] == user.email - end - - test "returns 403 if requested by a non-admin" do - user = insert(:user) - - conn = - build_conn() - |> assign(:user, user) - |> get("/api/pleroma/admin/users/#{user.nickname}/credentials") - - assert json_response(conn, :forbidden) - end - end - - describe "PATCH /users/:nickname/credentials" do - setup do - user = insert(:user) - [user: user] - end - - test "changes password and email", %{conn: conn, admin: admin, user: user} do - assert user.password_reset_pending == false - - conn = - patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{ - "password" => "new_password", - "email" => "new_email@example.com", - "name" => "new_name" - }) - - assert json_response(conn, 200) == %{"status" => "success"} - - ObanHelpers.perform_all() - - updated_user = User.get_by_id(user.id) - - assert updated_user.email == "new_email@example.com" - assert updated_user.name == "new_name" - assert updated_user.password_hash != user.password_hash - assert updated_user.password_reset_pending == true - - [log_entry2, log_entry1] = ModerationLog |> Repo.all() |> Enum.sort() - - assert ModerationLog.get_log_entry_message(log_entry1) == - "@#{admin.nickname} updated users: @#{user.nickname}" - - assert ModerationLog.get_log_entry_message(log_entry2) == - "@#{admin.nickname} forced password reset for users: @#{user.nickname}" - end - - test "returns 403 if requested by a non-admin", %{user: user} do - conn = - build_conn() - |> assign(:user, user) - |> patch("/api/pleroma/admin/users/#{user.nickname}/credentials", %{ - "password" => "new_password", - "email" => "new_email@example.com", - "name" => "new_name" - }) - - assert json_response(conn, :forbidden) - end - - test "changes actor type from permitted list", %{conn: conn, user: user} do - assert user.actor_type == "Person" - - assert patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{ - "actor_type" => "Service" - }) - |> json_response(200) == %{"status" => "success"} - - updated_user = User.get_by_id(user.id) - - assert updated_user.actor_type == "Service" - - assert patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{ - "actor_type" => "Application" - }) - |> json_response(400) == %{"errors" => %{"actor_type" => "is invalid"}} - end - - test "update non existing user", %{conn: conn} do - assert patch(conn, "/api/pleroma/admin/users/non-existing/credentials", %{ - "password" => "new_password" - }) - |> json_response(404) == %{"error" => "Not found"} - end - end - - describe "PATCH /users/:nickname/force_password_reset" do - test "sets password_reset_pending to true", %{conn: conn} do - user = insert(:user) - assert user.password_reset_pending == false - - conn = - patch(conn, "/api/pleroma/admin/users/force_password_reset", %{nicknames: [user.nickname]}) - - assert empty_json_response(conn) == "" - - ObanHelpers.perform_all() - - assert User.get_by_id(user.id).password_reset_pending == true - end - end - - describe "instances" do - test "GET /instances/:instance/statuses", %{conn: conn} do - user = insert(:user, local: false, nickname: "archaeme@archae.me") - user2 = insert(:user, local: false, nickname: "test@test.com") - insert_pair(:note_activity, user: user) - activity = insert(:note_activity, user: user2) - - ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses") - - response = json_response(ret_conn, 200) - - assert length(response) == 2 - - ret_conn = get(conn, "/api/pleroma/admin/instances/test.com/statuses") - - response = json_response(ret_conn, 200) - - assert length(response) == 1 - - ret_conn = get(conn, "/api/pleroma/admin/instances/nonexistent.com/statuses") - - response = json_response(ret_conn, 200) - - assert Enum.empty?(response) - - CommonAPI.repeat(activity.id, user) - - ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses") - response = json_response(ret_conn, 200) - assert length(response) == 2 - - ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses?with_reblogs=true") - response = json_response(ret_conn, 200) - assert length(response) == 3 - end - end - - describe "PATCH /confirm_email" do - test "it confirms emails of two users", %{conn: conn, admin: admin} do - [first_user, second_user] = insert_pair(:user, confirmation_pending: true) - - assert first_user.confirmation_pending == true - assert second_user.confirmation_pending == true - - ret_conn = - patch(conn, "/api/pleroma/admin/users/confirm_email", %{ - nicknames: [ - first_user.nickname, - second_user.nickname - ] - }) - - assert ret_conn.status == 200 - - assert first_user.confirmation_pending == true - assert second_user.confirmation_pending == true - - log_entry = Repo.one(ModerationLog) - - assert ModerationLog.get_log_entry_message(log_entry) == - "@#{admin.nickname} confirmed email for users: @#{first_user.nickname}, @#{ - second_user.nickname - }" - end - end - - describe "PATCH /resend_confirmation_email" do - test "it resend emails for two users", %{conn: conn, admin: admin} do - [first_user, second_user] = insert_pair(:user, confirmation_pending: true) - - ret_conn = - patch(conn, "/api/pleroma/admin/users/resend_confirmation_email", %{ - nicknames: [ - first_user.nickname, - second_user.nickname - ] - }) - - assert ret_conn.status == 200 - - log_entry = Repo.one(ModerationLog) - - assert ModerationLog.get_log_entry_message(log_entry) == - "@#{admin.nickname} re-sent confirmation email for users: @#{first_user.nickname}, @#{ - second_user.nickname - }" - - ObanHelpers.perform_all() - assert_email_sent(Pleroma.Emails.UserEmail.account_confirmation_email(first_user)) - end - end - - describe "/api/pleroma/admin/stats" do - test "status visibility count", %{conn: conn} do - admin = insert(:user, is_admin: true) - user = insert(:user) - CommonAPI.post(user, %{visibility: "public", status: "hey"}) - CommonAPI.post(user, %{visibility: "unlisted", status: "hey"}) - CommonAPI.post(user, %{visibility: "unlisted", status: "hey"}) - - response = - conn - |> assign(:user, admin) - |> get("/api/pleroma/admin/stats") - |> json_response(200) - - assert %{"direct" => 0, "private" => 0, "public" => 1, "unlisted" => 2} = - response["status_visibility"] - end - - test "by instance", %{conn: conn} do - admin = insert(:user, is_admin: true) - user1 = insert(:user) - instance2 = "instance2.tld" - user2 = insert(:user, %{ap_id: "https://#{instance2}/@actor"}) - - CommonAPI.post(user1, %{visibility: "public", status: "hey"}) - CommonAPI.post(user2, %{visibility: "unlisted", status: "hey"}) - CommonAPI.post(user2, %{visibility: "private", status: "hey"}) - - response = - conn - |> assign(:user, admin) - |> get("/api/pleroma/admin/stats", instance: instance2) - |> json_response(200) - - assert %{"direct" => 0, "private" => 1, "public" => 0, "unlisted" => 1} = - response["status_visibility"] - end - end -end - -# Needed for testing -defmodule Pleroma.Web.Endpoint.NotReal do -end - -defmodule Pleroma.Captcha.NotReal do -end diff --git a/test/web/masto_fe_controller_test.exs b/test/web/masto_fe_controller_test.exs deleted file mode 100644 index f3b54b5f2..000000000 --- a/test/web/masto_fe_controller_test.exs +++ /dev/null @@ -1,85 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.MastodonAPI.MastoFEController do - use Pleroma.Web.ConnCase - - alias Pleroma.Config - alias Pleroma.User - - import Pleroma.Factory - - setup do: clear_config([:instance, :public]) - - test "put settings", %{conn: conn} do - user = insert(:user) - - conn = - conn - |> assign(:user, user) - |> assign(:token, insert(:oauth_token, user: user, scopes: ["write:accounts"])) - |> put("/api/web/settings", %{"data" => %{"programming" => "socks"}}) - - assert _result = json_response(conn, 200) - - user = User.get_cached_by_ap_id(user.ap_id) - assert user.mastofe_settings == %{"programming" => "socks"} - end - - describe "index/2 redirections" do - setup %{conn: conn} do - session_opts = [ - store: :cookie, - key: "_test", - signing_salt: "cooldude" - ] - - conn = - conn - |> Plug.Session.call(Plug.Session.init(session_opts)) - |> fetch_session() - - test_path = "/web/statuses/test" - %{conn: conn, path: test_path} - end - - test "redirects not logged-in users to the login page", %{conn: conn, path: path} do - conn = get(conn, path) - - assert conn.status == 302 - assert redirected_to(conn) == "/web/login" - end - - test "redirects not logged-in users to the login page on private instances", %{ - conn: conn, - path: path - } do - Config.put([:instance, :public], false) - - conn = get(conn, path) - - assert conn.status == 302 - assert redirected_to(conn) == "/web/login" - end - - test "does not redirect logged in users to the login page", %{conn: conn, path: path} do - token = insert(:oauth_token, scopes: ["read"]) - - conn = - conn - |> assign(:user, token.user) - |> assign(:token, token) - |> get(path) - - assert conn.status == 200 - end - - test "saves referer path to session", %{conn: conn, path: path} do - conn = get(conn, path) - return_to = Plug.Conn.get_session(conn, :return_to) - - assert return_to == path - end - end -end diff --git a/test/web/mastodon_api/controllers/auth_controller_test.exs b/test/web/mastodon_api/controllers/auth_controller_test.exs deleted file mode 100644 index 4fa95fce1..000000000 --- a/test/web/mastodon_api/controllers/auth_controller_test.exs +++ /dev/null @@ -1,162 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.MastodonAPI.AuthControllerTest do - use Pleroma.Web.ConnCase - - alias Pleroma.Config - alias Pleroma.Repo - alias Pleroma.Tests.ObanHelpers - - import Pleroma.Factory - import Swoosh.TestAssertions - - describe "GET /web/login" do - setup %{conn: conn} do - session_opts = [ - store: :cookie, - key: "_test", - signing_salt: "cooldude" - ] - - conn = - conn - |> Plug.Session.call(Plug.Session.init(session_opts)) - |> fetch_session() - - test_path = "/web/statuses/test" - %{conn: conn, path: test_path} - end - - test "redirects to the saved path after log in", %{conn: conn, path: path} do - app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".") - auth = insert(:oauth_authorization, app: app) - - conn = - conn - |> put_session(:return_to, path) - |> get("/web/login", %{code: auth.token}) - - assert conn.status == 302 - assert redirected_to(conn) == path - end - - test "redirects to the getting-started page when referer is not present", %{conn: conn} do - app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".") - auth = insert(:oauth_authorization, app: app) - - conn = get(conn, "/web/login", %{code: auth.token}) - - assert conn.status == 302 - assert redirected_to(conn) == "/web/getting-started" - end - end - - describe "POST /auth/password, with valid parameters" do - setup %{conn: conn} do - user = insert(:user) - conn = post(conn, "/auth/password?email=#{user.email}") - %{conn: conn, user: user} - end - - test "it returns 204", %{conn: conn} do - assert json_response(conn, :no_content) - end - - test "it creates a PasswordResetToken record for user", %{user: user} do - token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id) - assert token_record - end - - test "it sends an email to user", %{user: user} do - ObanHelpers.perform_all() - token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id) - - email = Pleroma.Emails.UserEmail.password_reset_email(user, token_record.token) - notify_email = Config.get([:instance, :notify_email]) - instance_name = Config.get([:instance, :name]) - - assert_email_sent( - from: {instance_name, notify_email}, - to: {user.name, user.email}, - html_body: email.html_body - ) - end - end - - describe "POST /auth/password, with nickname" do - test "it returns 204", %{conn: conn} do - user = insert(:user) - - assert conn - |> post("/auth/password?nickname=#{user.nickname}") - |> json_response(:no_content) - - ObanHelpers.perform_all() - token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id) - - email = Pleroma.Emails.UserEmail.password_reset_email(user, token_record.token) - notify_email = Config.get([:instance, :notify_email]) - instance_name = Config.get([:instance, :name]) - - assert_email_sent( - from: {instance_name, notify_email}, - to: {user.name, user.email}, - html_body: email.html_body - ) - end - - test "it doesn't fail when a user has no email", %{conn: conn} do - user = insert(:user, %{email: nil}) - - assert conn - |> post("/auth/password?nickname=#{user.nickname}") - |> json_response(:no_content) - end - end - - describe "POST /auth/password, with invalid parameters" do - setup do - user = insert(:user) - {:ok, user: user} - end - - test "it returns 204 when user is not found", %{conn: conn, user: user} do - conn = post(conn, "/auth/password?email=nonexisting_#{user.email}") - - assert conn - |> json_response(:no_content) - end - - test "it returns 204 when user is not local", %{conn: conn, user: user} do - {:ok, user} = Repo.update(Ecto.Changeset.change(user, local: false)) - conn = post(conn, "/auth/password?email=#{user.email}") - - assert conn - |> json_response(:no_content) - end - - test "it returns 204 when user is deactivated", %{conn: conn, user: user} do - {:ok, user} = Repo.update(Ecto.Changeset.change(user, deactivated: true, local: true)) - conn = post(conn, "/auth/password?email=#{user.email}") - - assert conn - |> json_response(:no_content) - end - end - - describe "DELETE /auth/sign_out" do - test "redirect to root page", %{conn: conn} do - user = insert(:user) - - conn = - conn - |> assign(:user, user) - |> delete("/auth/sign_out") - - assert conn.status == 302 - assert redirected_to(conn) == "/" - end - end -end diff --git a/test/web/mastodon_api/controllers/filter_controller_test.exs b/test/web/mastodon_api/controllers/filter_controller_test.exs deleted file mode 100644 index 0d426ec34..000000000 --- a/test/web/mastodon_api/controllers/filter_controller_test.exs +++ /dev/null @@ -1,152 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.MastodonAPI.FilterControllerTest do - use Pleroma.Web.ConnCase - - alias Pleroma.Web.MastodonAPI.FilterView - - test "creating a filter" do - %{conn: conn} = oauth_access(["write:filters"]) - - filter = %Pleroma.Filter{ - phrase: "knights", - context: ["home"] - } - - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/filters", %{"phrase" => filter.phrase, context: filter.context}) - - assert response = json_response_and_validate_schema(conn, 200) - assert response["phrase"] == filter.phrase - assert response["context"] == filter.context - assert response["irreversible"] == false - assert response["id"] != nil - assert response["id"] != "" - end - - test "fetching a list of filters" do - %{user: user, conn: conn} = oauth_access(["read:filters"]) - - query_one = %Pleroma.Filter{ - user_id: user.id, - filter_id: 1, - phrase: "knights", - context: ["home"] - } - - query_two = %Pleroma.Filter{ - user_id: user.id, - filter_id: 2, - phrase: "who", - context: ["home"] - } - - {:ok, filter_one} = Pleroma.Filter.create(query_one) - {:ok, filter_two} = Pleroma.Filter.create(query_two) - - response = - conn - |> get("/api/v1/filters") - |> json_response_and_validate_schema(200) - - assert response == - render_json( - FilterView, - "index.json", - filters: [filter_two, filter_one] - ) - end - - test "get a filter" do - %{user: user, conn: conn} = oauth_access(["read:filters"]) - - # check whole_word false - query = %Pleroma.Filter{ - user_id: user.id, - filter_id: 2, - phrase: "knight", - context: ["home"], - whole_word: false - } - - {:ok, filter} = Pleroma.Filter.create(query) - - conn = get(conn, "/api/v1/filters/#{filter.filter_id}") - - assert response = json_response_and_validate_schema(conn, 200) - assert response["whole_word"] == false - - # check whole_word true - %{user: user, conn: conn} = oauth_access(["read:filters"]) - - query = %Pleroma.Filter{ - user_id: user.id, - filter_id: 3, - phrase: "knight", - context: ["home"], - whole_word: true - } - - {:ok, filter} = Pleroma.Filter.create(query) - - conn = get(conn, "/api/v1/filters/#{filter.filter_id}") - - assert response = json_response_and_validate_schema(conn, 200) - assert response["whole_word"] == true - end - - test "update a filter" do - %{user: user, conn: conn} = oauth_access(["write:filters"]) - - query = %Pleroma.Filter{ - user_id: user.id, - filter_id: 2, - phrase: "knight", - context: ["home"], - hide: true, - whole_word: true - } - - {:ok, _filter} = Pleroma.Filter.create(query) - - new = %Pleroma.Filter{ - phrase: "nii", - context: ["home"] - } - - conn = - conn - |> put_req_header("content-type", "application/json") - |> put("/api/v1/filters/#{query.filter_id}", %{ - phrase: new.phrase, - context: new.context - }) - - assert response = json_response_and_validate_schema(conn, 200) - assert response["phrase"] == new.phrase - assert response["context"] == new.context - assert response["irreversible"] == true - assert response["whole_word"] == true - end - - test "delete a filter" do - %{user: user, conn: conn} = oauth_access(["write:filters"]) - - query = %Pleroma.Filter{ - user_id: user.id, - filter_id: 2, - phrase: "knight", - context: ["home"] - } - - {:ok, filter} = Pleroma.Filter.create(query) - - conn = delete(conn, "/api/v1/filters/#{filter.filter_id}") - - assert json_response_and_validate_schema(conn, 200) == %{} - end -end diff --git a/test/web/mastodon_api/controllers/suggestion_controller_test.exs b/test/web/mastodon_api/controllers/suggestion_controller_test.exs deleted file mode 100644 index 7f08e187c..000000000 --- a/test/web/mastodon_api/controllers/suggestion_controller_test.exs +++ /dev/null @@ -1,18 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.MastodonAPI.SuggestionControllerTest do - use Pleroma.Web.ConnCase - - setup do: oauth_access(["read"]) - - test "returns empty result", %{conn: conn} do - res = - conn - |> get("/api/v1/suggestions") - |> json_response_and_validate_schema(200) - - assert res == [] - end -end diff --git a/test/web/media_proxy/invalidations/script_test.exs b/test/web/media_proxy/invalidations/script_test.exs deleted file mode 100644 index 51833ab18..000000000 --- a/test/web/media_proxy/invalidations/script_test.exs +++ /dev/null @@ -1,26 +0,0 @@ -defmodule Pleroma.Web.MediaProxy.Invalidation.ScriptTest do - use ExUnit.Case - alias Pleroma.Web.MediaProxy.Invalidation - - import ExUnit.CaptureLog - - setup do - on_exit(fn -> Cachex.clear(:banned_urls_cache) end) - end - - test "it logger error when script not found" do - assert capture_log(fn -> - assert Invalidation.Script.purge( - ["http://example.com/media/example.jpg"], - script_path: "./example" - ) == {:error, "%ErlangError{original: :enoent}"} - end) =~ "Error while cache purge: %ErlangError{original: :enoent}" - - capture_log(fn -> - assert Invalidation.Script.purge( - ["http://example.com/media/example.jpg"], - [] - ) == {:error, "\"not found script path\""} - end) - end -end diff --git a/test/web/media_proxy/media_proxy_controller_test.exs b/test/web/media_proxy/media_proxy_controller_test.exs deleted file mode 100644 index d4db44c63..000000000 --- a/test/web/media_proxy/media_proxy_controller_test.exs +++ /dev/null @@ -1,121 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.MediaProxy.MediaProxyControllerTest do - use Pleroma.Web.ConnCase - - import Mock - - alias Pleroma.Web.MediaProxy - alias Pleroma.Web.MediaProxy.MediaProxyController - alias Plug.Conn - - setup do - on_exit(fn -> Cachex.clear(:banned_urls_cache) end) - end - - test "it returns 404 when MediaProxy disabled", %{conn: conn} do - clear_config([:media_proxy, :enabled], false) - - assert %Conn{ - status: 404, - resp_body: "Not Found" - } = get(conn, "/proxy/hhgfh/eeeee") - - assert %Conn{ - status: 404, - resp_body: "Not Found" - } = get(conn, "/proxy/hhgfh/eeee/fff") - end - - describe "" do - setup do - clear_config([:media_proxy, :enabled], true) - clear_config([Pleroma.Web.Endpoint, :secret_key_base], "00000000000") - [url: MediaProxy.encode_url("https://google.fn/test.png")] - end - - test "it returns 403 for invalid signature", %{conn: conn, url: url} do - Pleroma.Config.put([Pleroma.Web.Endpoint, :secret_key_base], "000") - %{path: path} = URI.parse(url) - - assert %Conn{ - status: 403, - resp_body: "Forbidden" - } = get(conn, path) - - assert %Conn{ - status: 403, - resp_body: "Forbidden" - } = get(conn, "/proxy/hhgfh/eeee") - - assert %Conn{ - status: 403, - resp_body: "Forbidden" - } = get(conn, "/proxy/hhgfh/eeee/fff") - end - - test "redirects on valid url when filename is invalidated", %{conn: conn, url: url} do - invalid_url = String.replace(url, "test.png", "test-file.png") - response = get(conn, invalid_url) - assert response.status == 302 - assert redirected_to(response) == url - end - - test "it performs ReverseProxy.call with valid signature", %{conn: conn, url: url} do - with_mock Pleroma.ReverseProxy, - call: fn _conn, _url, _opts -> %Conn{status: :success} end do - assert %Conn{status: :success} = get(conn, url) - end - end - - test "it returns 404 when url is in banned_urls cache", %{conn: conn, url: url} do - MediaProxy.put_in_banned_urls("https://google.fn/test.png") - - with_mock Pleroma.ReverseProxy, - call: fn _conn, _url, _opts -> %Conn{status: :success} end do - assert %Conn{status: 404, resp_body: "Not Found"} = get(conn, url) - end - end - end - - describe "filename_matches/3" do - test "preserves the encoded or decoded path" do - assert MediaProxyController.filename_matches( - %{"filename" => "/Hello world.jpg"}, - "/Hello world.jpg", - "http://pleroma.social/Hello world.jpg" - ) == :ok - - assert MediaProxyController.filename_matches( - %{"filename" => "/Hello%20world.jpg"}, - "/Hello%20world.jpg", - "http://pleroma.social/Hello%20world.jpg" - ) == :ok - - assert MediaProxyController.filename_matches( - %{"filename" => "/my%2Flong%2Furl%2F2019%2F07%2FS.jpg"}, - "/my%2Flong%2Furl%2F2019%2F07%2FS.jpg", - "http://pleroma.social/my%2Flong%2Furl%2F2019%2F07%2FS.jpg" - ) == :ok - - assert MediaProxyController.filename_matches( - %{"filename" => "/my%2Flong%2Furl%2F2019%2F07%2FS.jp"}, - "/my%2Flong%2Furl%2F2019%2F07%2FS.jp", - "http://pleroma.social/my%2Flong%2Furl%2F2019%2F07%2FS.jpg" - ) == {:wrong_filename, "my%2Flong%2Furl%2F2019%2F07%2FS.jpg"} - end - - test "encoded url are tried to match for proxy as `conn.request_path` encodes the url" do - # conn.request_path will return encoded url - request_path = "/ANALYSE-DAI-_-LE-STABLECOIN-100-D%C3%89CENTRALIS%C3%89-BQ.jpg" - - assert MediaProxyController.filename_matches( - true, - request_path, - "https://mydomain.com/uploads/2019/07/ANALYSE-DAI-_-LE-STABLECOIN-100-DÉCENTRALISÉ-BQ.jpg" - ) == :ok - end - end -end diff --git a/test/web/metadata/metadata_test.exs b/test/web/metadata/metadata_test.exs deleted file mode 100644 index 3f8b29e58..000000000 --- a/test/web/metadata/metadata_test.exs +++ /dev/null @@ -1,25 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.MetadataTest do - use Pleroma.DataCase, async: true - - import Pleroma.Factory - - describe "restrict indexing remote users" do - test "for remote user" do - user = insert(:user, local: false) - - assert Pleroma.Web.Metadata.build_tags(%{user: user}) =~ - "<meta content=\"noindex, noarchive\" name=\"robots\">" - end - - test "for local user" do - user = insert(:user) - - refute Pleroma.Web.Metadata.build_tags(%{user: user}) =~ - "<meta content=\"noindex, noarchive\" name=\"robots\">" - end - end -end diff --git a/test/web/metadata/opengraph_test.exs b/test/web/metadata/opengraph_test.exs deleted file mode 100644 index 218540e6c..000000000 --- a/test/web/metadata/opengraph_test.exs +++ /dev/null @@ -1,96 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.Metadata.Providers.OpenGraphTest do - use Pleroma.DataCase - import Pleroma.Factory - alias Pleroma.Web.Metadata.Providers.OpenGraph - - setup do: clear_config([Pleroma.Web.Metadata, :unfurl_nsfw]) - - test "it renders all supported types of attachments and skips unknown types" do - user = insert(:user) - - note = - insert(:note, %{ - data: %{ - "actor" => user.ap_id, - "tag" => [], - "id" => "https://pleroma.gov/objects/whatever", - "content" => "pleroma in a nutshell", - "attachment" => [ - %{ - "url" => [ - %{"mediaType" => "image/png", "href" => "https://pleroma.gov/tenshi.png"} - ] - }, - %{ - "url" => [ - %{ - "mediaType" => "application/octet-stream", - "href" => "https://pleroma.gov/fqa/badapple.sfc" - } - ] - }, - %{ - "url" => [ - %{"mediaType" => "video/webm", "href" => "https://pleroma.gov/about/juche.webm"} - ] - }, - %{ - "url" => [ - %{ - "mediaType" => "audio/basic", - "href" => "http://www.gnu.org/music/free-software-song.au" - } - ] - } - ] - } - }) - - result = OpenGraph.build_tags(%{object: note, url: note.data["id"], user: user}) - - assert Enum.all?( - [ - {:meta, [property: "og:image", content: "https://pleroma.gov/tenshi.png"], []}, - {:meta, - [property: "og:audio", content: "http://www.gnu.org/music/free-software-song.au"], - []}, - {:meta, [property: "og:video", content: "https://pleroma.gov/about/juche.webm"], - []} - ], - fn element -> element in result end - ) - end - - test "it does not render attachments if post is nsfw" do - Pleroma.Config.put([Pleroma.Web.Metadata, :unfurl_nsfw], false) - user = insert(:user, avatar: %{"url" => [%{"href" => "https://pleroma.gov/tenshi.png"}]}) - - note = - insert(:note, %{ - data: %{ - "actor" => user.ap_id, - "id" => "https://pleroma.gov/objects/whatever", - "content" => "#cuteposting #nsfw #hambaga", - "tag" => ["cuteposting", "nsfw", "hambaga"], - "sensitive" => true, - "attachment" => [ - %{ - "url" => [ - %{"mediaType" => "image/png", "href" => "https://misskey.microsoft/corndog.png"} - ] - } - ] - } - }) - - result = OpenGraph.build_tags(%{object: note, url: note.data["id"], user: user}) - - assert {:meta, [property: "og:image", content: "https://pleroma.gov/tenshi.png"], []} in result - - refute {:meta, [property: "og:image", content: "https://misskey.microsoft/corndog.png"], []} in result - end -end diff --git a/test/web/twitter_api/password_controller_test.exs b/test/web/twitter_api/password_controller_test.exs deleted file mode 100644 index 231a46c67..000000000 --- a/test/web/twitter_api/password_controller_test.exs +++ /dev/null @@ -1,81 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.TwitterAPI.PasswordControllerTest do - use Pleroma.Web.ConnCase - - alias Pleroma.PasswordResetToken - alias Pleroma.User - alias Pleroma.Web.OAuth.Token - import Pleroma.Factory - - describe "GET /api/pleroma/password_reset/token" do - test "it returns error when token invalid", %{conn: conn} do - response = - conn - |> get("/api/pleroma/password_reset/token") - |> html_response(:ok) - - assert response =~ "<h2>Invalid Token</h2>" - end - - test "it shows password reset form", %{conn: conn} do - user = insert(:user) - {:ok, token} = PasswordResetToken.create_token(user) - - response = - conn - |> get("/api/pleroma/password_reset/#{token.token}") - |> html_response(:ok) - - assert response =~ "<h2>Password Reset for #{user.nickname}</h2>" - end - end - - describe "POST /api/pleroma/password_reset" do - test "it returns HTTP 200", %{conn: conn} do - user = insert(:user) - {:ok, token} = PasswordResetToken.create_token(user) - {:ok, _access_token} = Token.create_token(insert(:oauth_app), user, %{}) - - params = %{ - "password" => "test", - password_confirmation: "test", - token: token.token - } - - response = - conn - |> assign(:user, user) - |> post("/api/pleroma/password_reset", %{data: params}) - |> html_response(:ok) - - assert response =~ "<h2>Password changed!</h2>" - - user = refresh_record(user) - assert Pbkdf2.verify_pass("test", user.password_hash) - assert Enum.empty?(Token.get_user_tokens(user)) - end - - test "it sets password_reset_pending to false", %{conn: conn} do - user = insert(:user, password_reset_pending: true) - - {:ok, token} = PasswordResetToken.create_token(user) - {:ok, _access_token} = Token.create_token(insert(:oauth_app), user, %{}) - - params = %{ - "password" => "test", - password_confirmation: "test", - token: token.token - } - - conn - |> assign(:user, user) - |> post("/api/pleroma/password_reset", %{data: params}) - |> html_response(:ok) - - assert User.get_by_id(user.id).password_reset_pending == false - end - end -end diff --git a/test/workers/cron/clear_oauth_token_worker_test.exs b/test/workers/cron/clear_oauth_token_worker_test.exs deleted file mode 100644 index 67836f34f..000000000 --- a/test/workers/cron/clear_oauth_token_worker_test.exs +++ /dev/null @@ -1,22 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Workers.Cron.ClearOauthTokenWorkerTest do - use Pleroma.DataCase - - import Pleroma.Factory - alias Pleroma.Workers.Cron.ClearOauthTokenWorker - - setup do: clear_config([:oauth2, :clean_expired_tokens]) - - test "deletes expired tokens" do - insert(:oauth_token, - valid_until: NaiveDateTime.add(NaiveDateTime.utc_now(), -60 * 10) - ) - - Pleroma.Config.put([:oauth2, :clean_expired_tokens], true) - ClearOauthTokenWorker.perform(%Oban.Job{}) - assert Pleroma.Repo.all(Pleroma.Web.OAuth.Token) == [] - end -end diff --git a/test/workers/cron/purge_expired_activities_worker_test.exs b/test/workers/cron/purge_expired_activities_worker_test.exs deleted file mode 100644 index d1acd9ae6..000000000 --- a/test/workers/cron/purge_expired_activities_worker_test.exs +++ /dev/null @@ -1,84 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Workers.Cron.PurgeExpiredActivitiesWorkerTest do - use Pleroma.DataCase - - alias Pleroma.ActivityExpiration - alias Pleroma.Workers.Cron.PurgeExpiredActivitiesWorker - - import Pleroma.Factory - import ExUnit.CaptureLog - - setup do - clear_config([ActivityExpiration, :enabled]) - end - - test "deletes an expiration activity" do - Pleroma.Config.put([ActivityExpiration, :enabled], true) - activity = insert(:note_activity) - - naive_datetime = - NaiveDateTime.add( - NaiveDateTime.utc_now(), - -:timer.minutes(2), - :millisecond - ) - - expiration = - insert( - :expiration_in_the_past, - %{activity_id: activity.id, scheduled_at: naive_datetime} - ) - - Pleroma.Workers.Cron.PurgeExpiredActivitiesWorker.perform(%Oban.Job{}) - - refute Pleroma.Repo.get(Pleroma.Activity, activity.id) - refute Pleroma.Repo.get(Pleroma.ActivityExpiration, expiration.id) - end - - test "works with ActivityExpirationPolicy" do - Pleroma.Config.put([ActivityExpiration, :enabled], true) - - clear_config([:mrf, :policies], Pleroma.Web.ActivityPub.MRF.ActivityExpirationPolicy) - - user = insert(:user) - - days = Pleroma.Config.get([:mrf_activity_expiration, :days], 365) - - {:ok, %{id: id} = activity} = Pleroma.Web.CommonAPI.post(user, %{status: "cofe"}) - - past_date = - NaiveDateTime.utc_now() |> Timex.shift(days: -days) |> NaiveDateTime.truncate(:second) - - activity - |> Repo.preload(:expiration) - |> Map.get(:expiration) - |> Ecto.Changeset.change(%{scheduled_at: past_date}) - |> Repo.update!() - - Pleroma.Workers.Cron.PurgeExpiredActivitiesWorker.perform(%Oban.Job{}) - - assert [%{data: %{"type" => "Delete", "deleted_activity_id" => ^id}}] = - Pleroma.Repo.all(Pleroma.Activity) - end - - describe "delete_activity/1" do - test "adds log message if activity isn't find" do - assert capture_log([level: :error], fn -> - PurgeExpiredActivitiesWorker.delete_activity(%ActivityExpiration{ - activity_id: "test-activity" - }) - end) =~ "Couldn't delete expired activity: not found activity" - end - - test "adds log message if actor isn't find" do - assert capture_log([level: :error], fn -> - PurgeExpiredActivitiesWorker.delete_activity(%ActivityExpiration{ - activity_id: "test-activity" - }) - end) =~ "Couldn't delete expired activity: not found activity" - end - end -end |