diff options
| author | Alex S <alex.strizhakov@gmail.com> | 2019-05-01 12:29:33 +0700 | 
|---|---|---|
| committer | Alex S <alex.strizhakov@gmail.com> | 2019-05-01 12:29:33 +0700 | 
| commit | bdfa3a6fa87f95e93aa853ec4961645215f31221 (patch) | |
| tree | 467b9dd762c9878541e34f2b38a1c58e387c8f2c /test | |
| parent | 97b35e00b049c8f908484163b5ffdbcb55db7867 (diff) | |
| parent | 77690b9d03facf74483e3379f72b5b51c9f1bd4e (diff) | |
| download | pleroma-bdfa3a6fa87f95e93aa853ec4961645215f31221.tar.gz pleroma-bdfa3a6fa87f95e93aa853ec4961645215f31221.zip  | |
Merging with develop
Conflicts:
lib/pleroma/web/activity_pub/transmogrifier.ex
lib/pleroma/user.ex
Diffstat (limited to 'test')
61 files changed, 5556 insertions, 1108 deletions
diff --git a/test/bookmark_test.exs b/test/bookmark_test.exs new file mode 100644 index 000000000..b81c102ef --- /dev/null +++ b/test/bookmark_test.exs @@ -0,0 +1,52 @@ +defmodule Pleroma.BookmarkTest do +  use Pleroma.DataCase +  import Pleroma.Factory +  alias Pleroma.Bookmark +  alias Pleroma.Web.CommonAPI + +  describe "create/2" do +    test "with valid params" do +      user = insert(:user) +      {:ok, activity} = CommonAPI.post(user, %{"status" => "Some cool information"}) +      {:ok, bookmark} = Bookmark.create(user.id, activity.id) +      assert bookmark.user_id == user.id +      assert bookmark.activity_id == activity.id +    end + +    test "with invalid params" do +      {:error, changeset} = Bookmark.create(nil, "") +      refute changeset.valid? + +      assert changeset.errors == [ +               user_id: {"can't be blank", [validation: :required]}, +               activity_id: {"can't be blank", [validation: :required]} +             ] +    end +  end + +  describe "destroy/2" do +    test "with valid params" do +      user = insert(:user) + +      {:ok, activity} = CommonAPI.post(user, %{"status" => "Some cool information"}) +      {:ok, _bookmark} = Bookmark.create(user.id, activity.id) + +      {:ok, _deleted_bookmark} = Bookmark.destroy(user.id, activity.id) +    end +  end + +  describe "get/2" do +    test "gets a bookmark" do +      user = insert(:user) + +      {:ok, activity} = +        CommonAPI.post(user, %{ +          "status" => +            "Scientists Discover The Secret Behind Tenshi Eating A Corndog Being So Cute – Science Daily" +        }) + +      {:ok, bookmark} = Bookmark.create(user.id, activity.id) +      assert bookmark == Bookmark.get(user.id, activity.id) +    end +  end +end diff --git a/test/emoji_test.exs b/test/emoji_test.exs new file mode 100644 index 000000000..2eaa26be6 --- /dev/null +++ b/test/emoji_test.exs @@ -0,0 +1,106 @@ +defmodule Pleroma.EmojiTest do +  use ExUnit.Case, async: true +  alias Pleroma.Emoji + +  describe "get_all/0" do +    setup do +      emoji_list = Emoji.get_all() +      {:ok, emoji_list: emoji_list} +    end + +    test "first emoji", %{emoji_list: emoji_list} do +      [emoji | _others] = emoji_list +      {code, path, tags} = emoji + +      assert tuple_size(emoji) == 3 +      assert is_binary(code) +      assert is_binary(path) +      assert is_list(tags) +    end + +    test "random emoji", %{emoji_list: emoji_list} do +      emoji = Enum.random(emoji_list) +      {code, path, tags} = emoji + +      assert tuple_size(emoji) == 3 +      assert is_binary(code) +      assert is_binary(path) +      assert is_list(tags) +    end +  end + +  describe "match_extra/2" do +    setup do +      groups = [ +        "list of files": ["/emoji/custom/first_file.png", "/emoji/custom/second_file.png"], +        "wildcard folder": "/emoji/custom/*/file.png", +        "wildcard files": "/emoji/custom/folder/*.png", +        "special file": "/emoji/custom/special.png" +      ] + +      {:ok, groups: groups} +    end + +    test "config for list of files", %{groups: groups} do +      group = +        groups +        |> Emoji.match_extra("/emoji/custom/first_file.png") +        |> to_string() + +      assert group == "list of files" +    end + +    test "config with wildcard folder", %{groups: groups} do +      group = +        groups +        |> Emoji.match_extra("/emoji/custom/some_folder/file.png") +        |> to_string() + +      assert group == "wildcard folder" +    end + +    test "config with wildcard folder and subfolders", %{groups: groups} do +      group = +        groups +        |> Emoji.match_extra("/emoji/custom/some_folder/another_folder/file.png") +        |> to_string() + +      assert group == "wildcard folder" +    end + +    test "config with wildcard files", %{groups: groups} do +      group = +        groups +        |> Emoji.match_extra("/emoji/custom/folder/some_file.png") +        |> to_string() + +      assert group == "wildcard files" +    end + +    test "config with wildcard files and subfolders", %{groups: groups} do +      group = +        groups +        |> Emoji.match_extra("/emoji/custom/folder/another_folder/some_file.png") +        |> to_string() + +      assert group == "wildcard files" +    end + +    test "config for special file", %{groups: groups} do +      group = +        groups +        |> Emoji.match_extra("/emoji/custom/special.png") +        |> to_string() + +      assert group == "special file" +    end + +    test "no mathing returns nil", %{groups: groups} do +      group = +        groups +        |> Emoji.match_extra("/emoji/some_undefined.png") + +      refute group +    end +  end +end diff --git a/test/fixtures/httpoison_mock/emelie.atom b/test/fixtures/httpoison_mock/emelie.atom new file mode 100644 index 000000000..ddaa1c6ca --- /dev/null +++ b/test/fixtures/httpoison_mock/emelie.atom @@ -0,0 +1,306 @@ +<?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/httpoison_mock/status.emelie.json b/test/fixtures/httpoison_mock/status.emelie.json new file mode 100644 index 000000000..4aada0377 --- /dev/null +++ b/test/fixtures/httpoison_mock/status.emelie.json @@ -0,0 +1,64 @@ +{ +    "@context": [ +        "https://www.w3.org/ns/activitystreams", +        { +            "ostatus": "http://ostatus.org#", +            "atomUri": "ostatus:atomUri", +            "inReplyToAtomUri": "ostatus:inReplyToAtomUri", +            "conversation": "ostatus:conversation", +            "sensitive": "as:sensitive", +            "Hashtag": "as:Hashtag", +            "toot": "http://joinmastodon.org/ns#", +            "Emoji": "toot:Emoji", +            "focalPoint": { +                "@container": "@list", +                "@id": "toot:focalPoint" +            } +        } +    ], +    "id": "https://mastodon.social/users/emelie/statuses/101849165031453009", +    "type": "Note", +    "summary": null, +    "inReplyTo": null, +    "published": "2019-04-01T05:02:05Z", +    "url": "https://mastodon.social/@emelie/101849165031453009", +    "attributedTo": "https://mastodon.social/users/emelie", +    "to": [ +        "https://www.w3.org/ns/activitystreams#Public" +    ], +    "cc": [ +        "https://mastodon.social/users/emelie/followers" +    ], +    "sensitive": false, +    "atomUri": "https://mastodon.social/users/emelie/statuses/101849165031453009", +    "inReplyToAtomUri": null, +    "conversation": "tag:mastodon.social,2019-04-01:objectId=94350309:objectType=Conversation", +    "content": "<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>", +    "contentMap": { +        "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>" +    }, +    "attachment": [ +        { +            "type": "Document", +            "mediaType": "video/mp4", +            "url": "https://files.mastodon.social/media_attachments/files/013/049/816/original/e7831178a5e0d6d4.mp4", +            "name": null +        } +    ], +    "tag": [ +        { +            "type": "Hashtag", +            "href": "https://mastodon.social/tags/mastocats", +            "name": "#mastocats" +        } +    ], +    "replies": { +        "id": "https://mastodon.social/users/emelie/statuses/101849165031453009/replies", +        "type": "Collection", +        "first": { +            "type": "CollectionPage", +            "partOf": "https://mastodon.social/users/emelie/statuses/101849165031453009/replies", +            "items": [] +        } +    } +} diff --git a/test/fixtures/httpoison_mock/webfinger_emelie.json b/test/fixtures/httpoison_mock/webfinger_emelie.json new file mode 100644 index 000000000..0b61cb618 --- /dev/null +++ b/test/fixtures/httpoison_mock/webfinger_emelie.json @@ -0,0 +1,36 @@ +{ +    "aliases": [ +        "https://mastodon.social/@emelie", +        "https://mastodon.social/users/emelie" +    ], +    "links": [ +        { +            "href": "https://mastodon.social/@emelie", +            "rel": "http://webfinger.net/rel/profile-page", +            "type": "text/html" +        }, +        { +            "href": "https://mastodon.social/users/emelie.atom", +            "rel": "http://schemas.google.com/g/2010#updates-from", +            "type": "application/atom+xml" +        }, +        { +            "href": "https://mastodon.social/users/emelie", +            "rel": "self", +            "type": "application/activity+json" +        }, +        { +            "href": "https://mastodon.social/api/salmon/15657", +            "rel": "salmon" +        }, +        { +            "href": "data:application/magic-public-key,RSA.u3CWs1oAJPE3ZJ9sj6Ut_Mu-mTE7MOijsQc8_6c73XVVuhIEomiozJIH7l8a7S1n5SYL4UuiwcubSOi7u1bbGpYnp5TYhN-Cxvq_P80V4_ncNIPSQzS49it7nSLeG5pA21lGPDA44huquES1un6p9gSmbTwngVX9oe4MYuUeh0Z7vijjU13Llz1cRq_ZgPQPgfz-2NJf-VeXnvyDZDYxZPVBBlrMl3VoGbu0M5L8SjY35559KCZ3woIvqRolcoHXfgvJMdPcJgSZVYxlCw3dA95q9jQcn6s87CPSUs7bmYEQCrDVn5m5NER5TzwBmP4cgJl9AaDVWQtRd4jFZNTxlQ==.AQAB", +            "rel": "magic-public-key" +        }, +        { +            "rel": "http://ostatus.org/schema/1.0/subscribe", +            "template": "https://mastodon.social/authorize_interaction?uri={uri}" +        } +    ], +    "subject": "acct:emelie@mastodon.social" +} diff --git a/test/fixtures/image.jpg b/test/fixtures/image.jpg Binary files differindex 09834bb5c..edff6246b 100644 --- a/test/fixtures/image.jpg +++ b/test/fixtures/image.jpg diff --git a/test/fixtures/lambadalambda.json b/test/fixtures/lambadalambda.json new file mode 100644 index 000000000..1f09fb591 --- /dev/null +++ b/test/fixtures/lambadalambda.json @@ -0,0 +1,64 @@ +{ +  "@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", +      "Hashtag": "as:Hashtag", +      "Emoji": "toot:Emoji", +      "IdentityProof": "toot:IdentityProof", +      "focalPoint": { +        "@container": "@list", +        "@id": "toot:focalPoint" +      } +    } +  ], +  "id": "https://mastodon.social/users/lambadalambda", +  "type": "Person", +  "following": "https://mastodon.social/users/lambadalambda/following", +  "followers": "https://mastodon.social/users/lambadalambda/followers", +  "inbox": "https://mastodon.social/users/lambadalambda/inbox", +  "outbox": "https://mastodon.social/users/lambadalambda/outbox", +  "featured": "https://mastodon.social/users/lambadalambda/collections/featured", +  "preferredUsername": "lambadalambda", +  "name": "Critical Value", +  "summary": "\u003cp\u003e\u003c/p\u003e", +  "url": "https://mastodon.social/@lambadalambda", +  "manuallyApprovesFollowers": false, +  "publicKey": { +    "id": "https://mastodon.social/users/lambadalambda#main-key", +    "owner": "https://mastodon.social/users/lambadalambda", +    "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw0P/Tq4gb4G/QVuMGbJo\nC/AfMNcv+m7NfrlOwkVzcU47jgESuYI4UtJayissCdBycHUnfVUd9qol+eznSODz\nCJhfJloqEIC+aSnuEPGA0POtWad6DU0E6/Ho5zQn5WAWUwbRQqowbrsm/GHo2+3v\neR5jGenwA6sYhINg/c3QQbksyV0uJ20Umyx88w8+TJuv53twOfmyDWuYNoQ3y5cc\nHKOZcLHxYOhvwg3PFaGfFHMFiNmF40dTXt9K96r7sbzc44iLD+VphbMPJEjkMuf8\nPGEFOBzy8pm3wJZw2v32RNW2VESwMYyqDzwHXGSq1a73cS7hEnc79gXlELsK04L9\nQQIDAQAB\n-----END PUBLIC KEY-----\n" +  }, +  "tag": [], +  "attachment": [], +  "endpoints": { +    "sharedInbox": "https://mastodon.social/inbox" +  }, +  "icon": { +    "type": "Image", +    "mediaType": "image/gif", +    "url": "https://files.mastodon.social/accounts/avatars/000/000/264/original/1429214160519.gif" +  }, +  "image": { +    "type": "Image", +    "mediaType": "image/gif", +    "url": "https://files.mastodon.social/accounts/headers/000/000/264/original/28b26104f83747d2.gif" +  } +} diff --git a/test/formatter_test.exs b/test/formatter_test.exs index 7d8864bf4..97eb2f583 100644 --- a/test/formatter_test.exs +++ b/test/formatter_test.exs @@ -181,6 +181,31 @@ defmodule Pleroma.FormatterTest do        expected_text = "@a hi"        assert {^expected_text, [] = _mentions, [] = _tags} = Formatter.linkify(text)      end + +    test "given the 'safe_mention' option, it will only mention people in the beginning" do +      user = insert(:user) +      _other_user = insert(:user) +      third_user = insert(:user) +      text = " @#{user.nickname} hey dude i hate @#{third_user.nickname}" +      {expected_text, mentions, [] = _tags} = Formatter.linkify(text, safe_mention: true) + +      assert mentions == [{"@#{user.nickname}", user}] + +      assert expected_text == +               "<span class='h-card'><a data-user='#{user.id}' class='u-url mention' href='#{ +                 user.ap_id +               }'>@<span>#{user.nickname}</span></a></span> hey dude i hate <span class='h-card'><a data-user='#{ +                 third_user.id +               }' class='u-url mention' href='#{third_user.ap_id}'>@<span>#{third_user.nickname}</span></a></span>" +    end + +    test "given the 'safe_mention' option, it will still work without any mention" do +      text = "A post without any mention" +      {expected_text, mentions, [] = _tags} = Formatter.linkify(text, safe_mention: true) + +      assert mentions == [] +      assert expected_text == text +    end    end    describe ".parse_tags" do @@ -220,10 +245,10 @@ defmodule Pleroma.FormatterTest do    end    test "it adds cool emoji" do -    text = "I love :moominmamma:" +    text = "I love :firefox:"      expected_result = -      "I love <img height=\"32px\" width=\"32px\" alt=\"moominmamma\" title=\"moominmamma\" src=\"/finmoji/128px/moominmamma-128.png\" />" +      "I love <img height=\"32px\" width=\"32px\" alt=\"firefox\" title=\"firefox\" src=\"/emoji/Firefox.gif\" />"      assert Formatter.emojify(text) == expected_result    end @@ -244,9 +269,11 @@ defmodule Pleroma.FormatterTest do    end    test "it returns the emoji used in the text" do -    text = "I love :moominmamma:" +    text = "I love :firefox:" -    assert Formatter.get_emoji(text) == [{"moominmamma", "/finmoji/128px/moominmamma-128.png"}] +    assert Formatter.get_emoji(text) == [ +             {"firefox", "/emoji/Firefox.gif", ["Gif", "Fun"]} +           ]    end    test "it returns a nice empty result when no emojis are present" do diff --git a/test/healthcheck_test.exs b/test/healthcheck_test.exs new file mode 100644 index 000000000..e05061220 --- /dev/null +++ b/test/healthcheck_test.exs @@ -0,0 +1,22 @@ +defmodule Pleroma.HealthcheckTest do +  use Pleroma.DataCase +  alias Pleroma.Healthcheck + +  test "system_info/0" do +    result = Healthcheck.system_info() |> Map.from_struct() + +    assert Map.keys(result) == [:active, :healthy, :idle, :memory_used, :pool_size] +  end + +  describe "check_health/1" do +    test "pool size equals active connections" do +      result = Healthcheck.check_health(%Healthcheck{pool_size: 10, active: 10}) +      refute result.healthy +    end + +    test "chech_health/1" do +      result = Healthcheck.check_health(%Healthcheck{pool_size: 10, active: 9}) +      assert result.healthy +    end +  end +end diff --git a/test/html_test.exs b/test/html_test.exs index 29cab17f3..08738276e 100644 --- a/test/html_test.exs +++ b/test/html_test.exs @@ -10,6 +10,8 @@ defmodule Pleroma.HTMLTest do      <b>this is in bold</b>      <p>this is a paragraph</p>      this is a linebreak<br /> +    this is a link with allowed "rel" attribute: <a href="http://example.com/" rel="tag">example.com</a> +    this is a link with not allowed "rel" attribute: <a href="http://example.com/" rel="tag noallowed">example.com</a>      this is an image: <img src="http://example.com/image.jpg"><br />      <script>alert('hacked')</script>    """ @@ -18,12 +20,26 @@ defmodule Pleroma.HTMLTest do      <img src="http://example.com/image.jpg" onerror="alert('hacked')">    """ +  @html_span_class_sample """ +    <span class="animate-spin">hi</span> +  """ + +  @html_span_microformats_sample """ +    <span class="h-card"><a class="u-url mention">@<span>foo</span></a></span> +  """ + +  @html_span_invalid_microformats_sample """ +    <span class="h-card"><a class="u-url mention animate-spin">@<span>foo</span></a></span> +  """ +    describe "StripTags scrubber" do      test "works as expected" do        expected = """        this is in bold          this is a paragraph          this is a linebreak +        this is a link with allowed "rel" attribute: example.com +        this is a link with not allowed "rel" attribute: example.com          this is an image:           alert('hacked')        """ @@ -44,6 +60,8 @@ defmodule Pleroma.HTMLTest do        this is in bold          <p>this is a paragraph</p>          this is a linebreak<br /> +        this is a link with allowed "rel" attribute: <a href="http://example.com/" rel="tag">example.com</a> +        this is a link with not allowed "rel" attribute: <a href="http://example.com/">example.com</a>          this is an image: <img src="http://example.com/image.jpg" /><br />          alert('hacked')        """ @@ -58,6 +76,36 @@ defmodule Pleroma.HTMLTest do        assert expected == HTML.filter_tags(@html_onerror_sample, Pleroma.HTML.Scrubber.TwitterText)      end + +    test "does not allow spans with invalid classes" do +      expected = """ +      <span>hi</span> +      """ + +      assert expected == +               HTML.filter_tags(@html_span_class_sample, Pleroma.HTML.Scrubber.TwitterText) +    end + +    test "does allow microformats" do +      expected = """ +      <span class="h-card"><a class="u-url mention">@<span>foo</span></a></span> +      """ + +      assert expected == +               HTML.filter_tags(@html_span_microformats_sample, Pleroma.HTML.Scrubber.TwitterText) +    end + +    test "filters invalid microformats markup" do +      expected = """ +      <span class="h-card"><a>@<span>foo</span></a></span> +      """ + +      assert expected == +               HTML.filter_tags( +                 @html_span_invalid_microformats_sample, +                 Pleroma.HTML.Scrubber.TwitterText +               ) +    end    end    describe "default scrubber" do @@ -66,6 +114,8 @@ defmodule Pleroma.HTMLTest do        <b>this is in bold</b>          <p>this is a paragraph</p>          this is a linebreak<br /> +        this is a link with allowed "rel" attribute: <a href="http://example.com/" rel="tag">example.com</a> +        this is a link with not allowed "rel" attribute: <a href="http://example.com/">example.com</a>          this is an image: <img src="http://example.com/image.jpg" /><br />          alert('hacked')        """ @@ -80,5 +130,34 @@ defmodule Pleroma.HTMLTest do        assert expected == HTML.filter_tags(@html_onerror_sample, Pleroma.HTML.Scrubber.Default)      end + +    test "does not allow spans with invalid classes" do +      expected = """ +      <span>hi</span> +      """ + +      assert expected == HTML.filter_tags(@html_span_class_sample, Pleroma.HTML.Scrubber.Default) +    end + +    test "does allow microformats" do +      expected = """ +      <span class="h-card"><a class="u-url mention">@<span>foo</span></a></span> +      """ + +      assert expected == +               HTML.filter_tags(@html_span_microformats_sample, Pleroma.HTML.Scrubber.Default) +    end + +    test "filters invalid microformats markup" do +      expected = """ +      <span class="h-card"><a>@<span>foo</span></a></span> +      """ + +      assert expected == +               HTML.filter_tags( +                 @html_span_invalid_microformats_sample, +                 Pleroma.HTML.Scrubber.Default +               ) +    end    end  end diff --git a/test/jobs_test.exs b/test/jobs_test.exs deleted file mode 100644 index d55c86ccc..000000000 --- a/test/jobs_test.exs +++ /dev/null @@ -1,83 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.JobsTest do -  use ExUnit.Case, async: true - -  alias Jobs.WorkerMock -  alias Pleroma.Jobs - -  setup do -    state = %{ -      queues: Enum.into([Jobs.create_queue(:testing)], %{}), -      refs: %{} -    } - -    [state: state] -  end - -  test "creates queue" do -    queue = Jobs.create_queue(:foobar) - -    assert {:foobar, set} = queue -    assert :set == elem(set, 0) |> elem(0) -  end - -  test "enqueues an element according to priority" do -    queue = [%{item: 1, priority: 2}] - -    new_queue = Jobs.enqueue_sorted(queue, 2, 1) -    assert new_queue == [%{item: 2, priority: 1}, %{item: 1, priority: 2}] - -    new_queue = Jobs.enqueue_sorted(queue, 2, 3) -    assert new_queue == [%{item: 1, priority: 2}, %{item: 2, priority: 3}] -  end - -  test "pop first item" do -    queue = [%{item: 2, priority: 1}, %{item: 1, priority: 2}] - -    assert {2, [%{item: 1, priority: 2}]} = Jobs.queue_pop(queue) -  end - -  test "enqueue a job", %{state: state} do -    assert {:noreply, new_state} = -             Jobs.handle_cast({:enqueue, :testing, WorkerMock, [:test_job, :foo, :bar], 3}, state) - -    assert %{queues: %{testing: {running_jobs, []}}, refs: _} = new_state -    assert :sets.size(running_jobs) == 1 -    assert [ref] = :sets.to_list(running_jobs) -    assert %{refs: %{^ref => :testing}} = new_state -  end - -  test "max jobs setting", %{state: state} do -    max_jobs = Pleroma.Config.get([Jobs, :testing, :max_jobs]) - -    {:noreply, state} = -      Enum.reduce(1..(max_jobs + 1), {:noreply, state}, fn _, {:noreply, state} -> -        Jobs.handle_cast({:enqueue, :testing, WorkerMock, [:test_job, :foo, :bar], 3}, state) -      end) - -    assert %{ -             queues: %{ -               testing: -                 {running_jobs, [%{item: {WorkerMock, [:test_job, :foo, :bar]}, priority: 3}]} -             } -           } = state - -    assert :sets.size(running_jobs) == max_jobs -  end - -  test "remove job after it finished", %{state: state} do -    {:noreply, new_state} = -      Jobs.handle_cast({:enqueue, :testing, WorkerMock, [:test_job, :foo, :bar], 3}, state) - -    %{queues: %{testing: {running_jobs, []}}} = new_state -    [ref] = :sets.to_list(running_jobs) - -    assert {:noreply, %{queues: %{testing: {running_jobs, []}}, refs: %{}}} = -             Jobs.handle_info({:DOWN, ref, :process, nil, nil}, new_state) - -    assert :sets.size(running_jobs) == 0 -  end -end diff --git a/test/media_proxy_test.exs b/test/media_proxy_test.exs index ddbadfbf5..a4331478e 100644 --- a/test/media_proxy_test.exs +++ b/test/media_proxy_test.exs @@ -177,4 +177,13 @@ defmodule Pleroma.MediaProxyTest do      {:ok, decoded} = decode_url(sig, base64)      decoded    end + +  test "mediaproxy whitelist" do +    Pleroma.Config.put([:media_proxy, :enabled], true) +    Pleroma.Config.put([:media_proxy, :whitelist], ["google.com", "feld.me"]) +    url = "https://feld.me/foo.png" + +    unencoded = url(url) +    assert unencoded == url +  end  end diff --git a/test/notification_test.exs b/test/notification_test.exs index 12b4292aa..581db58a8 100644 --- a/test/notification_test.exs +++ b/test/notification_test.exs @@ -29,21 +29,102 @@ defmodule Pleroma.NotificationTest do        assert notification.activity_id == activity.id        assert other_notification.activity_id == activity.id      end + +    test "it creates a notification for subscribed users" do +      user = insert(:user) +      subscriber = insert(:user) + +      User.subscribe(subscriber, user) + +      {:ok, status} = TwitterAPI.create_status(user, %{"status" => "Akariiiin"}) +      {:ok, [notification]} = Notification.create_notifications(status) + +      assert notification.user_id == subscriber.id +    end    end    describe "create_notification" do      test "it doesn't create a notification for user if the user blocks the activity author" do        activity = insert(:note_activity) -      author = User.get_by_ap_id(activity.data["actor"]) +      author = User.get_cached_by_ap_id(activity.data["actor"])        user = insert(:user)        {:ok, user} = User.block(user, author)        assert nil == Notification.create_notification(activity, user)      end +    test "it doesn't create a notificatin for the user if the user mutes the activity author" do +      muter = insert(:user) +      muted = insert(:user) +      {:ok, _} = User.mute(muter, muted) +      muter = Repo.get(User, muter.id) +      {:ok, activity} = CommonAPI.post(muted, %{"status" => "Hi @#{muter.nickname}"}) + +      assert nil == Notification.create_notification(activity, muter) +    end + +    test "it doesn't create a notification for an activity from a muted thread" do +      muter = insert(:user) +      other_user = insert(:user) +      {:ok, activity} = CommonAPI.post(muter, %{"status" => "hey"}) +      CommonAPI.add_mute(muter, activity) + +      {:ok, activity} = +        CommonAPI.post(other_user, %{ +          "status" => "Hi @#{muter.nickname}", +          "in_reply_to_status_id" => activity.id +        }) + +      assert nil == Notification.create_notification(activity, muter) +    end + +    test "it disables notifications from people on remote instances" do +      user = insert(:user, info: %{notification_settings: %{"remote" => false}}) +      other_user = insert(:user) + +      create_activity = %{ +        "@context" => "https://www.w3.org/ns/activitystreams", +        "type" => "Create", +        "to" => ["https://www.w3.org/ns/activitystreams#Public"], +        "actor" => other_user.ap_id, +        "object" => %{ +          "type" => "Note", +          "content" => "Hi @#{user.nickname}", +          "attributedTo" => other_user.ap_id +        } +      } + +      {:ok, %{local: false} = activity} = Transmogrifier.handle_incoming(create_activity) +      assert nil == Notification.create_notification(activity, user) +    end + +    test "it disables notifications from people on the local instance" do +      user = insert(:user, info: %{notification_settings: %{"local" => false}}) +      other_user = insert(:user) +      {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hey @#{user.nickname}"}) +      assert nil == Notification.create_notification(activity, user) +    end + +    test "it disables notifications from followers" do +      follower = insert(:user) +      followed = insert(:user, info: %{notification_settings: %{"followers" => false}}) +      User.follow(follower, followed) +      {:ok, activity} = CommonAPI.post(follower, %{"status" => "hey @#{followed.nickname}"}) +      assert nil == Notification.create_notification(activity, followed) +    end + +    test "it disables notifications from people the user follows" do +      follower = insert(:user, info: %{notification_settings: %{"follows" => false}}) +      followed = insert(:user) +      User.follow(follower, followed) +      follower = Repo.get(User, follower.id) +      {:ok, activity} = CommonAPI.post(followed, %{"status" => "hey @#{follower.nickname}"}) +      assert nil == Notification.create_notification(activity, follower) +    end +      test "it doesn't create a notification for user if he is the activity author" do        activity = insert(:note_activity) -      author = User.get_by_ap_id(activity.data["actor"]) +      author = User.get_cached_by_ap_id(activity.data["actor"])        assert nil == Notification.create_notification(activity, author)      end @@ -84,6 +165,28 @@ defmodule Pleroma.NotificationTest do        {:ok, dupe} = TwitterAPI.repeat(user, status.id)        assert nil == Notification.create_notification(dupe, retweeted_user)      end + +    test "it doesn't create duplicate notifications for follow+subscribed users" do +      user = insert(:user) +      subscriber = insert(:user) + +      {:ok, _, _, _} = TwitterAPI.follow(subscriber, %{"user_id" => user.id}) +      User.subscribe(subscriber, user) +      {:ok, status} = TwitterAPI.create_status(user, %{"status" => "Akariiiin"}) +      {:ok, [_notif]} = Notification.create_notifications(status) +    end + +    test "it doesn't create subscription notifications if the recipient cannot see the status" do +      user = insert(:user) +      subscriber = insert(:user) + +      User.subscribe(subscriber, user) + +      {:ok, status} = +        TwitterAPI.create_status(user, %{"status" => "inwisible", "visibility" => "direct"}) + +      assert {:ok, []} == Notification.create_notifications(status) +    end    end    describe "get notification" do diff --git a/test/object/containment_test.exs b/test/object/containment_test.exs new file mode 100644 index 000000000..452064093 --- /dev/null +++ b/test/object/containment_test.exs @@ -0,0 +1,58 @@ +defmodule Pleroma.Object.ContainmentTest do +  use Pleroma.DataCase + +  alias Pleroma.Object.Containment +  alias Pleroma.User + +  import Pleroma.Factory + +  describe "general origin containment" do +    test "contain_origin_from_id() catches obvious spoofing attempts" do +      data = %{ +        "id" => "http://example.com/~alyssa/activities/1234.json" +      } + +      :error = +        Containment.contain_origin_from_id( +          "http://example.org/~alyssa/activities/1234.json", +          data +        ) +    end + +    test "contain_origin_from_id() allows alternate IDs within the same origin domain" do +      data = %{ +        "id" => "http://example.com/~alyssa/activities/1234.json" +      } + +      :ok = +        Containment.contain_origin_from_id( +          "http://example.com/~alyssa/activities/1234", +          data +        ) +    end + +    test "contain_origin_from_id() allows matching IDs" do +      data = %{ +        "id" => "http://example.com/~alyssa/activities/1234.json" +      } + +      :ok = +        Containment.contain_origin_from_id( +          "http://example.com/~alyssa/activities/1234.json", +          data +        ) +    end + +    test "users cannot be collided through fake direction spoofing attempts" 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"}) +        }) + +      {:error, _} = User.get_or_fetch_by_ap_id("https://n1u.moe/users/rye") +    end +  end +end diff --git a/test/object/fetcher_test.exs b/test/object/fetcher_test.exs new file mode 100644 index 000000000..72f616782 --- /dev/null +++ b/test/object/fetcher_test.exs @@ -0,0 +1,90 @@ +defmodule Pleroma.Object.FetcherTest do +  use Pleroma.DataCase + +  alias Pleroma.Activity +  alias Pleroma.Object +  alias Pleroma.Object.Fetcher +  import Tesla.Mock + +  setup do +    mock(fn env -> apply(HttpRequestMock, :request, [env]) end) +    :ok +  end + +  describe "actor origin containment" do +    test "it rejects objects with a bogus origin" do +      {:error, _} = Fetcher.fetch_object_from_id("https://info.pleroma.site/activity.json") +    end + +    test "it rejects objects when attributedTo is wrong (variant 1)" do +      {:error, _} = Fetcher.fetch_object_from_id("https://info.pleroma.site/activity2.json") +    end + +    test "it rejects objects when attributedTo is wrong (variant 2)" do +      {:error, _} = Fetcher.fetch_object_from_id("https://info.pleroma.site/activity3.json") +    end +  end + +  describe "fetching an object" do +    test "it fetches an object" 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"] + +      {:ok, object_again} = +        Fetcher.fetch_object_from_id("http://mastodon.example.org/@admin/99541947525187367") + +      assert [attachment] = object.data["attachment"] +      assert is_list(attachment["url"]) + +      assert object == object_again +    end + +    test "it works with objects only available via Ostatus" do +      {:ok, object} = Fetcher.fetch_object_from_id("https://shitposter.club/notice/2827873") +      assert activity = Activity.get_create_by_object_ap_id(object.data["id"]) +      assert activity.data["id"] + +      {:ok, object_again} = Fetcher.fetch_object_from_id("https://shitposter.club/notice/2827873") + +      assert object == object_again +    end + +    test "it correctly stitches up conversations between ostatus and ap" do +      last = "https://mstdn.io/users/mayuutann/statuses/99568293732299394" +      {:ok, object} = Fetcher.fetch_object_from_id(last) + +      object = Object.get_by_ap_id(object.data["inReplyTo"]) +      assert object +    end +  end + +  describe "implementation quirks" do +    test "it can fetch plume articles" do +      {:ok, object} = +        Fetcher.fetch_object_from_id( +          "https://baptiste.gelez.xyz/~/PlumeDevelopment/this-month-in-plume-june-2018/" +        ) + +      assert object +    end + +    test "it can fetch peertube videos" do +      {:ok, object} = +        Fetcher.fetch_object_from_id( +          "https://peertube.moe/videos/watch/df5f464b-be8d-46fb-ad81-2d4c2d1630e3" +        ) + +      assert object +    end + +    test "all objects with fake directions are rejected by the object fetcher" do +      {:error, _} = +        Fetcher.fetch_and_contain_remote_object_from_id( +          "https://info.pleroma.site/activity4.json" +        ) +    end +  end +end diff --git a/test/object_test.exs b/test/object_test.exs index 911757d57..d138ee091 100644 --- a/test/object_test.exs +++ b/test/object_test.exs @@ -5,9 +5,15 @@  defmodule Pleroma.ObjectTest do    use Pleroma.DataCase    import Pleroma.Factory +  import Tesla.Mock    alias Pleroma.Object    alias Pleroma.Repo +  setup do +    mock(fn env -> apply(HttpRequestMock, :request, [env]) end) +    :ok +  end +    test "returns an object by it's AP id" do      object = insert(:note)      found_object = Object.get_by_ap_id(object.data["id"]) @@ -58,4 +64,26 @@ defmodule Pleroma.ObjectTest do        assert cached_object.data["type"] == "Tombstone"      end    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" +    end + +    test "fetches unknown objects when fetch_remote is explicitly true" do +      %Object{} = +        object = Object.normalize("http://mastodon.example.org/@admin/99541947525187367", true) + +      assert object.data["url"] == "http://mastodon.example.org/@admin/99541947525187367" +    end + +    test "does not fetch unknown objects when fetch_remote is false" do +      assert is_nil( +               Object.normalize("http://mastodon.example.org/@admin/99541947525187367", false) +             ) +    end +  end  end diff --git a/test/plugs/legacy_authentication_plug_test.exs b/test/plugs/legacy_authentication_plug_test.exs index 302662797..8b0b06772 100644 --- a/test/plugs/legacy_authentication_plug_test.exs +++ b/test/plugs/legacy_authentication_plug_test.exs @@ -47,16 +47,18 @@ defmodule Pleroma.Plugs.LegacyAuthenticationPlugTest do        |> assign(:auth_user, user)      conn = -      with_mock User, -        reset_password: fn user, %{password: password, password_confirmation: password} -> -          send(self(), :reset_password) -          {:ok, user} -        end do -        conn -        |> LegacyAuthenticationPlug.call(%{}) +      with_mocks([ +        {:crypt, [], [crypt: fn _password, password_hash -> password_hash end]}, +        {User, [], +         [ +           reset_password: fn user, %{password: password, password_confirmation: password} -> +             {:ok, user} +           end +         ]} +      ]) do +        LegacyAuthenticationPlug.call(conn, %{})        end -    assert_received :reset_password      assert conn.assigns.user == user    end diff --git a/test/plugs/uploaded_media_plug_test.exs b/test/plugs/uploaded_media_plug_test.exs new file mode 100644 index 000000000..49cf5396a --- /dev/null +++ b/test/plugs/uploaded_media_plug_test.exs @@ -0,0 +1,43 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.UploadedMediaPlugTest do +  use Pleroma.Web.ConnCase +  alias Pleroma.Upload + +  defp upload_file(context) do +    Pleroma.DataCase.ensure_local_uploader(context) +    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: "nice_tf.jpg" +    } + +    {:ok, data} = Upload.store(file) +    [%{"href" => attachment_url} | _] = data["url"] +    [attachment_url: attachment_url] +  end + +  setup_all :upload_file + +  test "does not send Content-Disposition header when name param is not set", %{ +    attachment_url: attachment_url +  } do +    conn = get(build_conn(), attachment_url) +    refute Enum.any?(conn.resp_headers, &(elem(&1, 0) == "content-disposition")) +  end + +  test "sends Content-Disposition header when name param is set", %{ +    attachment_url: attachment_url +  } do +    conn = get(build_conn(), attachment_url <> "?name=\"cofe\".gif") + +    assert Enum.any?( +             conn.resp_headers, +             &(&1 == {"content-disposition", "filename=\"\\\"cofe\\\".gif\""}) +           ) +  end +end diff --git a/test/registration_test.exs b/test/registration_test.exs new file mode 100644 index 000000000..6143b82c7 --- /dev/null +++ b/test/registration_test.exs @@ -0,0 +1,59 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.RegistrationTest do +  use Pleroma.DataCase + +  import Pleroma.Factory + +  alias Pleroma.Registration +  alias Pleroma.Repo + +  describe "generic changeset" do +    test "requires :provider, :uid" do +      registration = build(:registration, provider: nil, uid: nil) + +      cs = Registration.changeset(registration, %{}) +      refute cs.valid? + +      assert [ +               provider: {"can't be blank", [validation: :required]}, +               uid: {"can't be blank", [validation: :required]} +             ] == cs.errors +    end + +    test "ensures uniqueness of [:provider, :uid]" do +      registration = insert(:registration) +      registration2 = build(:registration, provider: registration.provider, uid: registration.uid) + +      cs = Registration.changeset(registration2, %{}) +      assert cs.valid? + +      assert {:error, +              %Ecto.Changeset{ +                errors: [ +                  uid: +                    {"has already been taken", +                     [constraint: :unique, constraint_name: "registrations_provider_uid_index"]} +                ] +              }} = Repo.insert(cs) + +      # Note: multiple :uid values per [:user_id, :provider] are intentionally allowed +      cs2 = Registration.changeset(registration2, %{uid: "available.uid"}) +      assert cs2.valid? +      assert {:ok, _} = Repo.insert(cs2) + +      cs3 = Registration.changeset(registration2, %{provider: "provider2"}) +      assert cs3.valid? +      assert {:ok, _} = Repo.insert(cs3) +    end + +    test "allows `nil` :user_id (user-unbound registration)" do +      registration = build(:registration, user_id: nil) +      cs = Registration.changeset(registration, %{}) +      assert cs.valid? +      assert {:ok, _} = Repo.insert(cs) +    end +  end +end diff --git a/test/scheduled_activity_test.exs b/test/scheduled_activity_test.exs new file mode 100644 index 000000000..edc7cc3f9 --- /dev/null +++ b/test/scheduled_activity_test.exs @@ -0,0 +1,64 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2018 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 context do +    DataCase.ensure_local_uploader(context) +  end + +  describe "creation" do +    test "when daily user limit is exceeded" do +      user = insert(:user) + +      today = +        NaiveDateTime.utc_now() +        |> NaiveDateTime.add(:timer.minutes(6), :millisecond) +        |> NaiveDateTime.to_iso8601() + +      attrs = %{params: %{}, scheduled_at: today} +      {:ok, _} = ScheduledActivity.create(user, attrs) +      {:ok, _} = ScheduledActivity.create(user, attrs) +      {:error, changeset} = ScheduledActivity.create(user, attrs) +      assert changeset.errors == [scheduled_at: {"daily limit exceeded", []}] +    end + +    test "when total user limit is exceeded" do +      user = insert(:user) + +      today = +        NaiveDateTime.utc_now() +        |> NaiveDateTime.add(:timer.minutes(6), :millisecond) +        |> NaiveDateTime.to_iso8601() + +      tomorrow = +        NaiveDateTime.utc_now() +        |> NaiveDateTime.add(:timer.hours(36), :millisecond) +        |> NaiveDateTime.to_iso8601() + +      {:ok, _} = ScheduledActivity.create(user, %{params: %{}, scheduled_at: today}) +      {:ok, _} = ScheduledActivity.create(user, %{params: %{}, scheduled_at: today}) +      {:ok, _} = ScheduledActivity.create(user, %{params: %{}, scheduled_at: tomorrow}) +      {:error, changeset} = ScheduledActivity.create(user, %{params: %{}, scheduled_at: tomorrow}) +      assert changeset.errors == [scheduled_at: {"total limit exceeded", []}] +    end + +    test "when scheduled_at is earlier than 5 minute from now" do +      user = insert(:user) + +      scheduled_at = +        NaiveDateTime.utc_now() +        |> NaiveDateTime.add(:timer.minutes(4), :millisecond) +        |> NaiveDateTime.to_iso8601() + +      attrs = %{params: %{}, scheduled_at: scheduled_at} +      {:error, changeset} = ScheduledActivity.create(user, attrs) +      assert changeset.errors == [scheduled_at: {"must be at least 5 minutes from now", []}] +    end +  end +end diff --git a/test/scheduled_activity_worker_test.exs b/test/scheduled_activity_worker_test.exs new file mode 100644 index 000000000..e3ad1244e --- /dev/null +++ b/test/scheduled_activity_worker_test.exs @@ -0,0 +1,19 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.ScheduledActivityWorkerTest do +  use Pleroma.DataCase +  alias Pleroma.ScheduledActivity +  import Pleroma.Factory + +  test "creates a status from the scheduled activity" do +    user = insert(:user) +    scheduled_activity = insert(:scheduled_activity, user: user, params: %{status: "hi"}) +    Pleroma.ScheduledActivityWorker.perform(:execute, 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 +end diff --git a/test/support/factory.ex b/test/support/factory.ex index 18f77f01a..ea59912cf 100644 --- a/test/support/factory.ex +++ b/test/support/factory.ex @@ -216,7 +216,7 @@ defmodule Pleroma.Factory do        redirect_uris: "https://example.com/callback",        scopes: ["read", "write", "follow", "push"],        website: "https://example.com", -      client_id: "aaabbb==", +      client_id: Ecto.UUID.generate(),        client_secret: "aaa;/&bbb"      }    end @@ -240,6 +240,16 @@ defmodule Pleroma.Factory do      }    end +  def oauth_authorization_factory do +    %Pleroma.Web.OAuth.Authorization{ +      token: :crypto.strong_rand_bytes(32) |> Base.url_encode64(padding: false), +      scopes: ["read", "write", "follow", "push"], +      valid_until: NaiveDateTime.add(NaiveDateTime.utc_now(), 60 * 10), +      user: build(:user), +      app: build(:oauth_app) +    } +  end +    def push_subscription_factory do      %Pleroma.Web.Push.Subscription{        user: build(:user), @@ -257,4 +267,28 @@ defmodule Pleroma.Factory do        user: build(:user)      }    end + +  def scheduled_activity_factory do +    %Pleroma.ScheduledActivity{ +      user: build(:user), +      scheduled_at: NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(60), :millisecond), +      params: build(:note) |> Map.from_struct() |> Map.get(:data) +    } +  end + +  def registration_factory do +    user = insert(:user) + +    %Pleroma.Registration{ +      user: user, +      provider: "twitter", +      uid: "171799000", +      info: %{ +        "name" => "John Doe", +        "email" => "john@doe.com", +        "nickname" => "johndoe", +        "description" => "My bio" +      } +    } +  end  end diff --git a/test/support/http_request_mock.ex b/test/support/http_request_mock.ex index 78e8efc9d..5b355bfe6 100644 --- a/test/support/http_request_mock.ex +++ b/test/support/http_request_mock.ex @@ -36,6 +36,43 @@ defmodule HttpRequestMock do       }}    end +  def get("https://mastodon.social/users/emelie/statuses/101849165031453009", _, _, _) do +    {:ok, +     %Tesla.Env{ +       status: 200, +       body: File.read!("test/fixtures/httpoison_mock/status.emelie.json") +     }} +  end + +  def get("https://mastodon.social/users/emelie", _, _, _) do +    {:ok, +     %Tesla.Env{ +       status: 200, +       body: File.read!("test/fixtures/httpoison_mock/emelie.json") +     }} +  end + +  def get( +        "https://mastodon.social/.well-known/webfinger?resource=https://mastodon.social/users/emelie", +        _, +        _, +        _ +      ) do +    {:ok, +     %Tesla.Env{ +       status: 200, +       body: File.read!("test/fixtures/httpoison_mock/webfinger_emelie.json") +     }} +  end + +  def get("https://mastodon.social/users/emelie.atom", _, _, _) do +    {:ok, +     %Tesla.Env{ +       status: 200, +       body: File.read!("test/fixtures/httpoison_mock/emelie.atom") +     }} +  end +    def get(          "https://osada.macgirvin.com/.well-known/webfinger?resource=acct:mike@osada.macgirvin.com",          _, @@ -679,6 +716,10 @@ defmodule HttpRequestMock do      {:ok, %Tesla.Env{status: 200, body: File.read!("test/fixtures/lambadalambda.atom")}}    end +  def get("https://mastodon.social/users/lambadalambda", _, _, _) do +    {:ok, %Tesla.Env{status: 200, body: File.read!("test/fixtures/lambadalambda.json")}} +  end +    def get("https://social.heldscal.la/user/23211", _, _, Accept: "application/activity+json") do      {:ok, Tesla.Mock.json(%{"id" => "https://social.heldscal.la/user/23211"}, status: 200)}    end diff --git a/test/support/jobs_worker_mock.ex b/test/support/jobs_worker_mock.ex deleted file mode 100644 index 0fb976d05..000000000 --- a/test/support/jobs_worker_mock.ex +++ /dev/null @@ -1,19 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Jobs.WorkerMock do -  require Logger - -  def perform(:test_job, arg, arg2) do -    Logger.debug({:perform, :test_job, arg, arg2}) -  end - -  def perform(:test_job, payload) do -    Logger.debug({:perform, :test_job, payload}) -  end - -  def test_job(payload) do -    Pleroma.Jobs.enqueue(:testing, __MODULE__, [:test_job, payload]) -  end -end diff --git a/test/tasks/instance.exs b/test/tasks/instance.exs new file mode 100644 index 000000000..6917a2376 --- /dev/null +++ b/test/tasks/instance.exs @@ -0,0 +1,62 @@ +defmodule Pleroma.InstanceTest do +  use ExUnit.Case, async: true + +  setup do +    File.mkdir_p!(tmp_path()) +    on_exit(fn -> File.rm_rf(tmp_path()) end) +    :ok +  end + +  defp tmp_path do +    "/tmp/generated_files/" +  end + +  test "running gen" do +    mix_task = fn -> +      Mix.Tasks.Pleroma.Instance.run([ +        "gen", +        "--output", +        tmp_path() <> "generated_config.exs", +        "--output-psql", +        tmp_path() <> "setup.psql", +        "--domain", +        "test.pleroma.social", +        "--instance-name", +        "Pleroma", +        "--admin-email", +        "admin@example.com", +        "--notify-email", +        "notify@example.com", +        "--dbhost", +        "dbhost", +        "--dbname", +        "dbname", +        "--dbuser", +        "dbuser", +        "--dbpass", +        "dbpass", +        "--indexable", +        "y" +      ]) +    end + +    ExUnit.CaptureIO.capture_io(fn -> +      mix_task.() +    end) + +    generated_config = File.read!(tmp_path() <> "generated_config.exs") +    assert generated_config =~ "host: \"test.pleroma.social\"" +    assert generated_config =~ "name: \"Pleroma\"" +    assert generated_config =~ "email: \"admin@example.com\"" +    assert generated_config =~ "notify_email: \"notify@example.com\"" +    assert generated_config =~ "hostname: \"dbhost\"" +    assert generated_config =~ "database: \"dbname\"" +    assert generated_config =~ "username: \"dbuser\"" +    assert generated_config =~ "password: \"dbpass\"" +    assert File.read!(tmp_path() <> "setup.psql") == generated_setup_psql() +  end + +  defp generated_setup_psql do +    ~s(CREATE USER dbuser WITH ENCRYPTED PASSWORD 'dbpass';\nCREATE DATABASE dbname OWNER dbuser;\n\\c dbname;\n--Extensions made by ecto.migrate that need superuser access\nCREATE EXTENSION IF NOT EXISTS citext;\nCREATE EXTENSION IF NOT EXISTS pg_trgm;\nCREATE EXTENSION IF NOT EXISTS \"uuid-ossp\";\n) +  end +end diff --git a/test/tasks/relay_test.exs b/test/tasks/relay_test.exs index c9d90fa2e..9d260da3e 100644 --- a/test/tasks/relay_test.exs +++ b/test/tasks/relay_test.exs @@ -31,7 +31,7 @@ defmodule Mix.Tasks.Pleroma.RelayTest do        local_user = Relay.get_actor()        assert local_user.ap_id =~ "/relay" -      target_user = User.get_by_ap_id(target_instance) +      target_user = User.get_cached_by_ap_id(target_instance)        refute target_user.local        activity = Utils.fetch_latest_follow(local_user, target_user) @@ -48,7 +48,7 @@ defmodule Mix.Tasks.Pleroma.RelayTest do        Mix.Tasks.Pleroma.Relay.run(["follow", target_instance])        %User{ap_id: follower_id} = local_user = Relay.get_actor() -      target_user = User.get_by_ap_id(target_instance) +      target_user = User.get_cached_by_ap_id(target_instance)        follow_activity = Utils.fetch_latest_follow(local_user, target_user)        Mix.Tasks.Pleroma.Relay.run(["unfollow", target_instance]) @@ -60,7 +60,8 @@ defmodule Mix.Tasks.Pleroma.RelayTest do          ActivityPub.fetch_activities([], %{            "type" => "Undo",            "actor_id" => follower_id, -          "limit" => 1 +          "limit" => 1, +          "skip_preload" => true          })        assert undo_activity.data["type"] == "Undo" diff --git a/test/tasks/user_test.exs b/test/tasks/user_test.exs index 7b814d171..eaf4ecf84 100644 --- a/test/tasks/user_test.exs +++ b/test/tasks/user_test.exs @@ -50,7 +50,7 @@ defmodule Mix.Tasks.Pleroma.UserTest do        assert_received {:mix_shell, :info, [message]}        assert message =~ "created" -      user = User.get_by_nickname(unsaved.nickname) +      user = User.get_cached_by_nickname(unsaved.nickname)        assert user.name == unsaved.name        assert user.email == unsaved.email        assert user.bio == unsaved.bio @@ -75,7 +75,7 @@ defmodule Mix.Tasks.Pleroma.UserTest do        assert_received {:mix_shell, :info, [message]}        assert message =~ "will not be created" -      refute User.get_by_nickname(unsaved.nickname) +      refute User.get_cached_by_nickname(unsaved.nickname)      end    end @@ -88,7 +88,7 @@ defmodule Mix.Tasks.Pleroma.UserTest do        assert_received {:mix_shell, :info, [message]}        assert message =~ " deleted" -      user = User.get_by_nickname(user.nickname) +      user = User.get_cached_by_nickname(user.nickname)        assert user.info.deactivated      end @@ -109,7 +109,7 @@ defmodule Mix.Tasks.Pleroma.UserTest do        assert_received {:mix_shell, :info, [message]}        assert message =~ " deactivated" -      user = User.get_by_nickname(user.nickname) +      user = User.get_cached_by_nickname(user.nickname)        assert user.info.deactivated      end @@ -121,7 +121,7 @@ defmodule Mix.Tasks.Pleroma.UserTest do        assert_received {:mix_shell, :info, [message]}        assert message =~ " activated" -      user = User.get_by_nickname(user.nickname) +      user = User.get_cached_by_nickname(user.nickname)        refute user.info.deactivated      end @@ -150,7 +150,7 @@ defmodule Mix.Tasks.Pleroma.UserTest do        assert_received {:mix_shell, :info, [message]}        assert message =~ "Successfully unsubscribed" -      user = User.get_by_nickname(user.nickname) +      user = User.get_cached_by_nickname(user.nickname)        assert Enum.empty?(user.following)        assert user.info.deactivated      end @@ -178,7 +178,7 @@ defmodule Mix.Tasks.Pleroma.UserTest do        assert_received {:mix_shell, :info, [message]}        assert message =~ ~r/Admin status .* true/ -      user = User.get_by_nickname(user.nickname) +      user = User.get_cached_by_nickname(user.nickname)        assert user.info.is_moderator        assert user.info.locked        assert user.info.is_admin @@ -204,7 +204,7 @@ defmodule Mix.Tasks.Pleroma.UserTest do        assert_received {:mix_shell, :info, [message]}        assert message =~ ~r/Admin status .* false/ -      user = User.get_by_nickname(user.nickname) +      user = User.get_cached_by_nickname(user.nickname)        refute user.info.is_moderator        refute user.info.locked        refute user.info.is_admin @@ -245,7 +245,97 @@ defmodule Mix.Tasks.Pleroma.UserTest do               end) =~ "http"        assert_received {:mix_shell, :info, [message]} -      assert message =~ "Generated" +      assert message =~ "Generated user invite token one time" +    end + +    test "token is generated with expires_at" do +      assert capture_io(fn -> +               Mix.Tasks.Pleroma.User.run([ +                 "invite", +                 "--expires-at", +                 Date.to_string(Date.utc_today()) +               ]) +             end) + +      assert_received {:mix_shell, :info, [message]} +      assert message =~ "Generated user invite token date limited" +    end + +    test "token is generated with max use" do +      assert capture_io(fn -> +               Mix.Tasks.Pleroma.User.run([ +                 "invite", +                 "--max-use", +                 "5" +               ]) +             end) + +      assert_received {:mix_shell, :info, [message]} +      assert message =~ "Generated user invite token reusable" +    end + +    test "token is generated with max use and expires date" do +      assert capture_io(fn -> +               Mix.Tasks.Pleroma.User.run([ +                 "invite", +                 "--max-use", +                 "5", +                 "--expires-at", +                 Date.to_string(Date.utc_today()) +               ]) +             end) + +      assert_received {:mix_shell, :info, [message]} +      assert message =~ "Generated user invite token reusable date limited" +    end +  end + +  describe "running invites" do +    test "invites are listed" do +      {:ok, invite} = Pleroma.UserInviteToken.create_invite() + +      {:ok, invite2} = +        Pleroma.UserInviteToken.create_invite(%{expires_at: Date.utc_today(), max_use: 15}) + +      # assert capture_io(fn -> +      Mix.Tasks.Pleroma.User.run([ +        "invites" +      ]) + +      #  end) + +      assert_received {:mix_shell, :info, [message]} +      assert_received {:mix_shell, :info, [message2]} +      assert_received {:mix_shell, :info, [message3]} +      assert message =~ "Invites list:" +      assert message2 =~ invite.invite_type +      assert message3 =~ invite2.invite_type +    end +  end + +  describe "running revoke_invite" do +    test "invite is revoked" do +      {:ok, invite} = Pleroma.UserInviteToken.create_invite(%{expires_at: Date.utc_today()}) + +      assert capture_io(fn -> +               Mix.Tasks.Pleroma.User.run([ +                 "revoke_invite", +                 invite.token +               ]) +             end) + +      assert_received {:mix_shell, :info, [message]} +      assert message =~ "Invite for token #{invite.token} was revoked." +    end +  end + +  describe "running delete_activities" do +    test "activities are deleted" do +      %{nickname: nickname} = insert(:user) + +      assert :ok == Mix.Tasks.Pleroma.User.run(["delete_activities", nickname]) +      assert_received {:mix_shell, :info, [message]} +      assert message == "User #{nickname} statuses deleted."      end    end  end diff --git a/test/upload_test.exs b/test/upload_test.exs index bdda01b3f..946ebcb5a 100644 --- a/test/upload_test.exs +++ b/test/upload_test.exs @@ -56,7 +56,7 @@ defmodule Pleroma.UploadTest do        assert List.first(data["url"])["href"] ==                 Pleroma.Web.base_url() <> -                 "/media/e7a6d0cf595bff76f14c9a98b6c199539559e8b844e02e51e5efcfd1f614a2df.jpg" +                 "/media/e30397b58d226d6583ab5b8b3c5defb0c682bda5c31ef07a9f57c1c4986e3781.jpg"      end      test "copies the file to the configured folder without deduping" do diff --git a/test/user_invite_token_test.exs b/test/user_invite_token_test.exs new file mode 100644 index 000000000..276788254 --- /dev/null +++ b/test/user_invite_token_test.exs @@ -0,0 +1,96 @@ +defmodule Pleroma.UserInviteTokenTest do +  use ExUnit.Case, async: true +  use Pleroma.DataCase +  alias Pleroma.UserInviteToken + +  describe "valid_invite?/1 one time invites" do +    setup do +      invite = %UserInviteToken{invite_type: "one_time"} + +      {:ok, invite: invite} +    end + +    test "not used returns true", %{invite: invite} do +      invite = %{invite | used: false} +      assert UserInviteToken.valid_invite?(invite) +    end + +    test "used  returns false", %{invite: invite} do +      invite = %{invite | used: true} +      refute UserInviteToken.valid_invite?(invite) +    end +  end + +  describe "valid_invite?/1 reusable invites" do +    setup do +      invite = %UserInviteToken{ +        invite_type: "reusable", +        max_use: 5 +      } + +      {:ok, invite: invite} +    end + +    test "with less uses then max use returns true", %{invite: invite} do +      invite = %{invite | uses: 4} +      assert UserInviteToken.valid_invite?(invite) +    end + +    test "with equal or more uses then max use returns false", %{invite: invite} do +      invite = %{invite | uses: 5} + +      refute UserInviteToken.valid_invite?(invite) + +      invite = %{invite | uses: 6} + +      refute UserInviteToken.valid_invite?(invite) +    end +  end + +  describe "valid_token?/1 date limited invites" do +    setup do +      invite = %UserInviteToken{invite_type: "date_limited"} +      {:ok, invite: invite} +    end + +    test "expires today returns true", %{invite: invite} do +      invite = %{invite | expires_at: Date.utc_today()} +      assert UserInviteToken.valid_invite?(invite) +    end + +    test "expires yesterday returns false", %{invite: invite} do +      invite = %{invite | expires_at: Date.add(Date.utc_today(), -1)} +      invite = Repo.insert!(invite) +      refute UserInviteToken.valid_invite?(invite) +    end +  end + +  describe "valid_token?/1 reusable date limited invites" do +    setup do +      invite = %UserInviteToken{invite_type: "reusable_date_limited", max_use: 5} +      {:ok, invite: invite} +    end + +    test "not overdue date and less uses returns true", %{invite: invite} do +      invite = %{invite | expires_at: Date.utc_today(), uses: 4} +      assert UserInviteToken.valid_invite?(invite) +    end + +    test "overdue date and less uses returns false", %{invite: invite} do +      invite = %{invite | expires_at: Date.add(Date.utc_today(), -1)} +      invite = Repo.insert!(invite) +      refute UserInviteToken.valid_invite?(invite) +    end + +    test "not overdue date with more uses returns false", %{invite: invite} do +      invite = %{invite | expires_at: Date.utc_today(), uses: 5} +      refute UserInviteToken.valid_invite?(invite) +    end + +    test "overdue date with more uses returns false", %{invite: invite} do +      invite = %{invite | expires_at: Date.add(Date.utc_today(), -1), uses: 5} +      invite = Repo.insert!(invite) +      refute UserInviteToken.valid_invite?(invite) +    end +  end +end diff --git a/test/user_test.exs b/test/user_test.exs index c57eb2c06..7be47e5fb 100644 --- a/test/user_test.exs +++ b/test/user_test.exs @@ -5,9 +5,11 @@  defmodule Pleroma.UserTest do    alias Pleroma.Activity    alias Pleroma.Builders.UserBuilder +  alias Pleroma.Object    alias Pleroma.Repo    alias Pleroma.User    alias Pleroma.Web.CommonAPI +    use Pleroma.DataCase    import Pleroma.Factory @@ -121,9 +123,9 @@ defmodule Pleroma.UserTest do      {:ok, user} = User.follow(user, followed) -    user = Repo.get(User, user.id) +    user = User.get_cached_by_id(user.id) -    followed = User.get_by_ap_id(followed.ap_id) +    followed = User.get_cached_by_ap_id(followed.ap_id)      assert followed.info.follower_count == 1      assert User.ap_followers(followed) in user.following @@ -145,6 +147,15 @@ defmodule Pleroma.UserTest do      {:error, _} = User.follow(blockee, blocker)    end +  test "can't subscribe to a user who blocked us" do +    blocker = insert(:user) +    blocked = insert(:user) + +    {:ok, blocker} = User.block(blocker, blocked) + +    {:error, _} = User.subscribe(blocked, blocker) +  end +    test "local users do not automatically follow local locked accounts" do      follower = insert(:user, info: %{locked: true})      followed = insert(:user, info: %{locked: true}) @@ -177,7 +188,7 @@ defmodule Pleroma.UserTest do      {:ok, user, _activity} = User.unfollow(user, followed) -    user = Repo.get(User, user.id) +    user = User.get_cached_by_id(user.id)      assert user.following == []    end @@ -187,7 +198,7 @@ defmodule Pleroma.UserTest do      {:error, _} = User.unfollow(user, user) -    user = Repo.get(User, user.id) +    user = User.get_cached_by_id(user.id)      assert user.following == [user.ap_id]    end @@ -199,6 +210,13 @@ defmodule Pleroma.UserTest do      refute User.following?(followed, user)    end +  test "fetches correct profile for nickname beginning with number" do +    # Use old-style integer ID to try to reproduce the problem +    user = insert(:user, %{id: 1080}) +    userwithnumbers = insert(:user, %{nickname: "#{user.id}garbage"}) +    assert userwithnumbers == User.get_cached_by_nickname_or_id(userwithnumbers.nickname) +  end +    describe "user registration" do      @full_user_data %{        bio: "A guy", @@ -239,7 +257,7 @@ defmodule Pleroma.UserTest do        activity = Repo.one(Pleroma.Activity)        assert registered_user.ap_id in activity.recipients -      assert activity.data["object"]["content"] =~ "cool site" +      assert Object.normalize(activity).data["content"] =~ "cool site"        assert activity.actor == welcome_user.ap_id        Pleroma.Config.put([:instance, :welcome_user_nickname], nil) @@ -538,8 +556,8 @@ defmodule Pleroma.UserTest do        {:ok, res} = User.get_friends(user) -      followed_one = User.get_by_ap_id(followed_one.ap_id) -      followed_two = User.get_by_ap_id(followed_two.ap_id) +      followed_one = User.get_cached_by_ap_id(followed_one.ap_id) +      followed_two = User.get_cached_by_ap_id(followed_two.ap_id)        assert Enum.member?(res, followed_one)        assert Enum.member?(res, followed_two)        refute Enum.member?(res, not_followed) @@ -550,7 +568,7 @@ defmodule Pleroma.UserTest do      test "it sets the info->note_count property" do        note = insert(:note) -      user = User.get_by_ap_id(note.data["actor"]) +      user = User.get_cached_by_ap_id(note.data["actor"])        assert user.info.note_count == 0 @@ -561,7 +579,7 @@ defmodule Pleroma.UserTest do      test "it increases the info->note_count property" do        note = insert(:note) -      user = User.get_by_ap_id(note.data["actor"]) +      user = User.get_cached_by_ap_id(note.data["actor"])        assert user.info.note_count == 0 @@ -576,7 +594,7 @@ defmodule Pleroma.UserTest do      test "it decreases the info->note_count property" do        note = insert(:note) -      user = User.get_by_ap_id(note.data["actor"]) +      user = User.get_cached_by_ap_id(note.data["actor"])        assert user.info.note_count == 0 @@ -678,7 +696,7 @@ defmodule Pleroma.UserTest do        assert User.following?(blocked, blocker)        {:ok, blocker} = User.block(blocker, blocked) -      blocked = Repo.get(User, blocked.id) +      blocked = User.get_cached_by_id(blocked.id)        assert User.blocks?(blocker, blocked) @@ -696,7 +714,7 @@ defmodule Pleroma.UserTest do        refute User.following?(blocked, blocker)        {:ok, blocker} = User.block(blocker, blocked) -      blocked = Repo.get(User, blocked.id) +      blocked = User.get_cached_by_id(blocked.id)        assert User.blocks?(blocker, blocked) @@ -714,13 +732,29 @@ defmodule Pleroma.UserTest do        assert User.following?(blocked, blocker)        {:ok, blocker} = User.block(blocker, blocked) -      blocked = Repo.get(User, blocked.id) +      blocked = User.get_cached_by_id(blocked.id)        assert User.blocks?(blocker, blocked)        refute User.following?(blocker, blocked)        refute User.following?(blocked, blocker)      end + +    test "blocks tear down blocked->blocker subscription relationships" do +      blocker = insert(:user) +      blocked = insert(:user) + +      {:ok, blocker} = User.subscribe(blocked, blocker) + +      assert User.subscribed_to?(blocked, blocker) +      refute User.subscribed_to?(blocker, blocked) + +      {:ok, blocker} = User.block(blocker, blocked) + +      assert User.blocks?(blocker, blocked) +      refute User.subscribed_to?(blocker, blocked) +      refute User.subscribed_to?(blocked, blocker) +    end    end    describe "domain blocking" do @@ -791,6 +825,16 @@ defmodule Pleroma.UserTest do      assert false == user.info.deactivated    end +  test ".delete_user_activities deletes all create activities" do +    user = insert(:user) + +    {:ok, activity} = CommonAPI.post(user, %{"status" => "2hu"}) +    {:ok, _} = User.delete_user_activities(user) + +    # TODO: Remove favorites, repeats, delete activities. +    refute Activity.get_by_id(activity.id) +  end +    test ".delete deactivates a user, all follow relationships and all create activities" do      user = insert(:user)      followed = insert(:user) @@ -808,9 +852,9 @@ defmodule Pleroma.UserTest do      {:ok, _} = User.delete(user) -    followed = Repo.get(User, followed.id) -    follower = Repo.get(User, follower.id) -    user = Repo.get(User, user.id) +    followed = User.get_cached_by_id(followed.id) +    follower = User.get_cached_by_id(follower.id) +    user = User.get_cached_by_id(user.id)      assert user.info.deactivated @@ -819,7 +863,7 @@ defmodule Pleroma.UserTest do      # TODO: Remove favorites, repeats, delete activities. -    refute Repo.get(Activity, activity.id) +    refute Activity.get_by_id(activity.id)    end    test "get_public_key_for_ap_id fetches a user that's not in the db" do @@ -879,7 +923,11 @@ defmodule Pleroma.UserTest do        user = insert(:user, %{nickname: "john"})        Enum.each(["john", "jo", "j"], fn query -> -        assert user == User.search(query) |> List.first() |> Map.put(:search_rank, nil) +        assert user == +                 User.search(query) +                 |> List.first() +                 |> Map.put(:search_rank, nil) +                 |> Map.put(:search_type, nil)        end)      end @@ -887,7 +935,11 @@ defmodule Pleroma.UserTest do        user = insert(:user, %{name: "John Doe"})        Enum.each(["John Doe", "JOHN", "doe", "j d", "j", "d"], fn query -> -        assert user == User.search(query) |> List.first() |> Map.put(:search_rank, nil) +        assert user == +                 User.search(query) +                 |> List.first() +                 |> Map.put(:search_rank, nil) +                 |> Map.put(:search_type, nil)        end)      end @@ -941,6 +993,7 @@ defmodule Pleroma.UserTest do                 User.search("lain@pleroma.soykaf.com")                 |> List.first()                 |> Map.put(:search_rank, nil) +               |> Map.put(:search_type, nil)      end      test "does not yield false-positive matches" do @@ -955,10 +1008,10 @@ defmodule Pleroma.UserTest do        results = User.search("http://mastodon.example.org/users/admin", resolve: true)        result = results |> List.first() -      user = User.get_by_ap_id("http://mastodon.example.org/users/admin") +      user = User.get_cached_by_ap_id("http://mastodon.example.org/users/admin")        assert length(results) == 1 -      assert user == result |> Map.put(:search_rank, nil) +      assert user == result |> Map.put(:search_rank, nil) |> Map.put(:search_type, nil)      end    end @@ -1072,30 +1125,20 @@ defmodule Pleroma.UserTest do      end    end -  test "bookmarks" do +  test "follower count is updated when a follower is blocked" do      user = insert(:user) +    follower = insert(:user) +    follower2 = insert(:user) +    follower3 = insert(:user) -    {:ok, activity1} = -      CommonAPI.post(user, %{ -        "status" => "heweoo!" -      }) - -    id1 = activity1.data["object"]["id"] - -    {:ok, activity2} = -      CommonAPI.post(user, %{ -        "status" => "heweoo!" -      }) - -    id2 = activity2.data["object"]["id"] +    {:ok, follower} = Pleroma.User.follow(follower, user) +    {:ok, _follower2} = Pleroma.User.follow(follower2, user) +    {:ok, _follower3} = Pleroma.User.follow(follower3, user) -    assert {:ok, user_state1} = User.bookmark(user, id1) -    assert user_state1.bookmarks == [id1] +    {:ok, _} = Pleroma.User.block(user, follower) -    assert {:ok, user_state2} = User.unbookmark(user, id1) -    assert user_state2.bookmarks == [] +    user_show = Pleroma.Web.TwitterAPI.UserView.render("show.json", %{user: user}) -    assert {:ok, user_state3} = User.bookmark(user, id2) -    assert user_state3.bookmarks == [id2] +    assert Map.get(user_show, "followers_count") == 2    end  end diff --git a/test/web/activity_pub/activity_pub_controller_test.exs b/test/web/activity_pub/activity_pub_controller_test.exs index a1e83b380..30adfda36 100644 --- a/test/web/activity_pub/activity_pub_controller_test.exs +++ b/test/web/activity_pub/activity_pub_controller_test.exs @@ -8,7 +8,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do    alias Pleroma.Activity    alias Pleroma.Instances    alias Pleroma.Object -  alias Pleroma.Repo    alias Pleroma.User    alias Pleroma.Web.ActivityPub.ObjectView    alias Pleroma.Web.ActivityPub.UserView @@ -51,7 +50,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do          |> put_req_header("accept", "application/json")          |> get("/users/#{user.nickname}") -      user = Repo.get(User, user.id) +      user = User.get_cached_by_id(user.id)        assert json_response(conn, 200) == UserView.render("user.json", %{user: user})      end @@ -66,7 +65,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do          |> put_req_header("accept", "application/activity+json")          |> get("/users/#{user.nickname}") -      user = Repo.get(User, user.id) +      user = User.get_cached_by_id(user.id)        assert json_response(conn, 200) == UserView.render("user.json", %{user: user})      end @@ -84,7 +83,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do          )          |> get("/users/#{user.nickname}") -      user = Repo.get(User, user.id) +      user = User.get_cached_by_id(user.id)        assert json_response(conn, 200) == UserView.render("user.json", %{user: user})      end @@ -254,6 +253,36 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do        assert Activity.get_by_ap_id(data["id"])      end +    test "it accepts messages from actors that are followed by the user", %{conn: conn} do +      recipient = insert(:user) +      actor = insert(:user, %{ap_id: "http://mastodon.example.org/users/actor"}) + +      {:ok, recipient} = User.follow(recipient, actor) + +      data = +        File.read!("test/fixtures/mastodon-post-activity.json") +        |> Poison.decode!() + +      object = +        data["object"] +        |> Map.put("attributedTo", actor.ap_id) + +      data = +        data +        |> Map.put("actor", actor.ap_id) +        |> Map.put("object", object) + +      conn = +        conn +        |> assign(:valid_signature, true) +        |> put_req_header("content-type", "application/activity+json") +        |> post("/users/#{recipient.nickname}/inbox", data) + +      assert "ok" == json_response(conn, 200) +      :timer.sleep(500) +      assert Activity.get_by_ap_id(data["id"]) +    end +      test "it rejects reads from other users", %{conn: conn} do        user = insert(:user)        otheruser = insert(:user) @@ -543,7 +572,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do        user = insert(:user)        Enum.each(1..15, fn _ -> -        user = Repo.get(User, user.id) +        user = User.get_cached_by_id(user.id)          other_user = insert(:user)          User.follow(user, other_user)        end) diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs index 2b83bfb1d..f8e987e58 100644 --- a/test/web/activity_pub/activity_pub_test.exs +++ b/test/web/activity_pub/activity_pub_test.exs @@ -84,17 +84,21 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do        {:ok, status_two} = CommonAPI.post(user, %{"status" => ". #essais"})        {:ok, status_three} = CommonAPI.post(user, %{"status" => ". #test #reject"}) -      fetch_one = ActivityPub.fetch_activities([], %{"tag" => "test"}) -      fetch_two = ActivityPub.fetch_activities([], %{"tag" => ["test", "essais"]}) +      fetch_one = ActivityPub.fetch_activities([], %{"type" => "Create", "tag" => "test"}) + +      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"]          }) @@ -140,7 +144,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do        activity = insert(:note_activity)        {:ok, new_activity} = ActivityPub.insert(activity.data) -      assert activity == new_activity +      assert activity.id == new_activity.id      end      test "inserts a given map into the activity database, giving it an id if it has none." do @@ -192,8 +196,10 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do        }        {:ok, %Activity{} = activity} = ActivityPub.insert(data) -      assert is_binary(activity.data["object"]["id"]) -      assert %Object{} = Object.get_by_ap_id(activity.data["object"]["id"]) +      object = Object.normalize(activity.data["object"]) + +      assert is_binary(object.data["id"]) +      assert %Object{} = Object.get_by_ap_id(activity.data["object"])      end    end @@ -206,7 +212,11 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do            to: ["user1", "user1", "user2"],            actor: user,            context: "", -          object: %{} +          object: %{ +            "to" => ["user1", "user1", "user2"], +            "type" => "Note", +            "content" => "testing" +          }          })        assert activity.data["to"] == ["user1", "user2"] @@ -218,20 +228,61 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do        user = insert(:user)        {:ok, _} = -        CommonAPI.post(Repo.get(User, user.id), %{"status" => "1", "visibility" => "public"}) +        CommonAPI.post(User.get_cached_by_id(user.id), %{ +          "status" => "1", +          "visibility" => "public" +        })        {:ok, _} = -        CommonAPI.post(Repo.get(User, user.id), %{"status" => "2", "visibility" => "unlisted"}) +        CommonAPI.post(User.get_cached_by_id(user.id), %{ +          "status" => "2", +          "visibility" => "unlisted" +        })        {:ok, _} = -        CommonAPI.post(Repo.get(User, user.id), %{"status" => "2", "visibility" => "private"}) +        CommonAPI.post(User.get_cached_by_id(user.id), %{ +          "status" => "2", +          "visibility" => "private" +        })        {:ok, _} = -        CommonAPI.post(Repo.get(User, user.id), %{"status" => "3", "visibility" => "direct"}) +        CommonAPI.post(User.get_cached_by_id(user.id), %{ +          "status" => "3", +          "visibility" => "direct" +        }) -      user = Repo.get(User, user.id) +      user = User.get_cached_by_id(user.id)        assert user.info.note_count == 2      end + +    test "increases replies count" do +      user = insert(:user) +      user2 = insert(:user) + +      {:ok, activity} = CommonAPI.post(user, %{"status" => "1", "visibility" => "public"}) +      ap_id = activity.data["id"] +      reply_data = %{"status" => "1", "in_reply_to_status_id" => activity.id} + +      # 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 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 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 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 object.data["repliesCount"] == 2 +    end    end    describe "fetch activities for recipients" do @@ -270,7 +321,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      booster = insert(:user)      {:ok, user} = User.block(user, %{ap_id: activity_one.data["actor"]}) -    activities = ActivityPub.fetch_activities([], %{"blocking_user" => user}) +    activities = +      ActivityPub.fetch_activities([], %{"blocking_user" => user, "skip_preload" => true})      assert Enum.member?(activities, activity_two)      assert Enum.member?(activities, activity_three) @@ -278,7 +330,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      {:ok, user} = User.unblock(user, %{ap_id: activity_one.data["actor"]}) -    activities = ActivityPub.fetch_activities([], %{"blocking_user" => user}) +    activities = +      ActivityPub.fetch_activities([], %{"blocking_user" => user, "skip_preload" => true})      assert Enum.member?(activities, activity_two)      assert Enum.member?(activities, activity_three) @@ -287,16 +340,18 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      {:ok, user} = User.block(user, %{ap_id: activity_three.data["actor"]})      {:ok, _announce, %{data: %{"id" => id}}} = CommonAPI.repeat(activity_three.id, booster)      %Activity{} = boost_activity = Activity.get_create_by_object_ap_id(id) -    activity_three = Repo.get(Activity, activity_three.id) +    activity_three = Activity.get_by_id(activity_three.id) -    activities = ActivityPub.fetch_activities([], %{"blocking_user" => user}) +    activities = +      ActivityPub.fetch_activities([], %{"blocking_user" => user, "skip_preload" => true})      assert Enum.member?(activities, activity_two)      refute Enum.member?(activities, activity_three)      refute Enum.member?(activities, boost_activity)      assert Enum.member?(activities, activity_one) -    activities = ActivityPub.fetch_activities([], %{"blocking_user" => nil}) +    activities = +      ActivityPub.fetch_activities([], %{"blocking_user" => nil, "skip_preload" => true})      assert Enum.member?(activities, activity_two)      assert Enum.member?(activities, activity_three) @@ -304,6 +359,51 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      assert Enum.member?(activities, activity_one)    end +  test "doesn't return transitive interactions concerning blocked users" do +    blocker = insert(:user) +    blockee = insert(:user) +    friend = insert(:user) + +    {:ok, blocker} = User.block(blocker, blockee) + +    {:ok, activity_one} = CommonAPI.post(friend, %{"status" => "hey!"}) + +    {:ok, activity_two} = CommonAPI.post(friend, %{"status" => "hey! @#{blockee.nickname}"}) + +    {:ok, activity_three} = CommonAPI.post(blockee, %{"status" => "hey! @#{friend.nickname}"}) + +    {:ok, activity_four} = CommonAPI.post(blockee, %{"status" => "hey! @#{blocker.nickname}"}) + +    activities = ActivityPub.fetch_activities([], %{"blocking_user" => blocker}) + +    assert Enum.member?(activities, activity_one) +    refute Enum.member?(activities, activity_two) +    refute Enum.member?(activities, activity_three) +    refute Enum.member?(activities, activity_four) +  end + +  test "doesn't return announce activities concerning blocked users" do +    blocker = insert(:user) +    blockee = insert(:user) +    friend = insert(:user) + +    {:ok, blocker} = User.block(blocker, blockee) + +    {:ok, activity_one} = CommonAPI.post(friend, %{"status" => "hey!"}) + +    {:ok, activity_two} = CommonAPI.post(blockee, %{"status" => "hey! @#{friend.nickname}"}) + +    {:ok, activity_three, _} = CommonAPI.repeat(activity_two.id, friend) + +    activities = +      ActivityPub.fetch_activities([], %{"blocking_user" => blocker}) +      |> Enum.map(fn act -> act.id end) + +    assert Enum.member?(activities, activity_one.id) +    refute Enum.member?(activities, activity_two.id) +    refute Enum.member?(activities, activity_three.id) +  end +    test "doesn't return muted activities" do      activity_one = insert(:note_activity)      activity_two = insert(:note_activity) @@ -312,14 +412,20 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      booster = insert(:user)      {:ok, user} = User.mute(user, %User{ap_id: activity_one.data["actor"]}) -    activities = ActivityPub.fetch_activities([], %{"muting_user" => user}) +    activities = +      ActivityPub.fetch_activities([], %{"muting_user" => user, "skip_preload" => true})      assert Enum.member?(activities, activity_two)      assert Enum.member?(activities, activity_three)      refute Enum.member?(activities, activity_one)      # Calling with 'with_muted' will deliver muted activities, too. -    activities = ActivityPub.fetch_activities([], %{"muting_user" => user, "with_muted" => true}) +    activities = +      ActivityPub.fetch_activities([], %{ +        "muting_user" => user, +        "with_muted" => true, +        "skip_preload" => true +      })      assert Enum.member?(activities, activity_two)      assert Enum.member?(activities, activity_three) @@ -327,7 +433,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      {:ok, user} = User.unmute(user, %User{ap_id: activity_one.data["actor"]}) -    activities = ActivityPub.fetch_activities([], %{"muting_user" => user}) +    activities = +      ActivityPub.fetch_activities([], %{"muting_user" => user, "skip_preload" => true})      assert Enum.member?(activities, activity_two)      assert Enum.member?(activities, activity_three) @@ -336,16 +443,17 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      {:ok, user} = User.mute(user, %User{ap_id: activity_three.data["actor"]})      {:ok, _announce, %{data: %{"id" => id}}} = CommonAPI.repeat(activity_three.id, booster)      %Activity{} = boost_activity = Activity.get_create_by_object_ap_id(id) -    activity_three = Repo.get(Activity, activity_three.id) +    activity_three = Activity.get_by_id(activity_three.id) -    activities = ActivityPub.fetch_activities([], %{"muting_user" => user}) +    activities = +      ActivityPub.fetch_activities([], %{"muting_user" => user, "skip_preload" => true})      assert Enum.member?(activities, activity_two)      refute Enum.member?(activities, activity_three)      refute Enum.member?(activities, boost_activity)      assert Enum.member?(activities, activity_one) -    activities = ActivityPub.fetch_activities([], %{"muting_user" => nil}) +    activities = ActivityPub.fetch_activities([], %{"muting_user" => nil, "skip_preload" => true})      assert Enum.member?(activities, activity_two)      assert Enum.member?(activities, activity_three) @@ -353,6 +461,20 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      assert Enum.member?(activities, activity_one)    end +  test "does include announces on request" do +    activity_three = insert(:note_activity) +    user = insert(:user) +    booster = insert(:user) + +    {:ok, user} = User.follow(user, booster) + +    {:ok, announce, _object} = CommonAPI.repeat(activity_three.id, booster) + +    [announce_activity] = ActivityPub.fetch_activities([user.ap_id | user.following]) + +    assert announce_activity.id == announce.id +  end +    test "excludes reblogs on request" do      user = insert(:user)      {:ok, expected_activity} = ActivityBuilder.insert(%{"type" => "Create"}, %{:user => user}) @@ -424,6 +546,33 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do        assert length(activities) == 20        assert last == last_expected      end + +    test "doesn't return reblogs for users for whom reblogs have been muted" do +      activity = insert(:note_activity) +      user = insert(:user) +      booster = insert(:user) +      {:ok, user} = CommonAPI.hide_reblogs(user, booster) + +      {:ok, activity, _} = CommonAPI.repeat(activity.id, booster) + +      activities = ActivityPub.fetch_activities([], %{"muting_user" => user}) + +      refute Enum.any?(activities, fn %{id: id} -> id == activity.id end) +    end + +    test "returns reblogs for users for whom reblogs have not been muted" do +      activity = insert(:note_activity) +      user = insert(:user) +      booster = insert(:user) +      {:ok, user} = CommonAPI.hide_reblogs(user, booster) +      {:ok, user} = CommonAPI.show_reblogs(user, booster) + +      {:ok, activity, _} = CommonAPI.repeat(activity.id, booster) + +      activities = ActivityPub.fetch_activities([], %{"muting_user" => user}) + +      assert Enum.any?(activities, fn %{id: id} -> id == activity.id end) +    end    end    describe "like an object" do @@ -473,7 +622,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do        {:ok, _, _, object} = ActivityPub.unlike(user, object)        assert object.data["like_count"] == 0 -      assert Repo.get(Activity, like_activity.id) == nil +      assert Activity.get_by_id(like_activity.id) == nil      end    end @@ -524,7 +673,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do        assert unannounce_activity.data["actor"] == user.ap_id        assert unannounce_activity.data["context"] == announce_activity.data["context"] -      assert Repo.get(Activity, announce_activity.id) == nil +      assert Activity.get_by_id(announce_activity.id) == nil      end    end @@ -559,43 +708,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      end    end -  describe "fetching an object" do -    test "it fetches an object" do -      {:ok, object} = -        ActivityPub.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"] - -      {:ok, object_again} = -        ActivityPub.fetch_object_from_id("http://mastodon.example.org/@admin/99541947525187367") - -      assert [attachment] = object.data["attachment"] -      assert is_list(attachment["url"]) - -      assert object == object_again -    end - -    test "it works with objects only available via Ostatus" do -      {:ok, object} = ActivityPub.fetch_object_from_id("https://shitposter.club/notice/2827873") -      assert activity = Activity.get_create_by_object_ap_id(object.data["id"]) -      assert activity.data["id"] - -      {:ok, object_again} = -        ActivityPub.fetch_object_from_id("https://shitposter.club/notice/2827873") - -      assert object == object_again -    end - -    test "it correctly stitches up conversations between ostatus and ap" do -      last = "https://mstdn.io/users/mayuutann/statuses/99568293732299394" -      {:ok, object} = ActivityPub.fetch_object_from_id(last) - -      object = Object.get_by_ap_id(object.data["inReplyTo"]) -      assert object -    end -  end -    describe "following / unfollowing" do      test "creates a follow activity" do        follower = insert(:user) @@ -663,7 +775,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do        assert delete.data["actor"] == note.data["actor"]        assert delete.data["object"] == note.data["object"]["id"] -      assert Repo.get(Activity, delete.id) != nil +      assert Activity.get_by_id(delete.id) != nil        assert Repo.get(Object, object.id).data["type"] == "Tombstone"      end @@ -672,23 +784,35 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do        user = insert(:user, info: %{note_count: 10})        {:ok, a1} = -        CommonAPI.post(Repo.get(User, user.id), %{"status" => "yeah", "visibility" => "public"}) +        CommonAPI.post(User.get_cached_by_id(user.id), %{ +          "status" => "yeah", +          "visibility" => "public" +        })        {:ok, a2} = -        CommonAPI.post(Repo.get(User, user.id), %{"status" => "yeah", "visibility" => "unlisted"}) +        CommonAPI.post(User.get_cached_by_id(user.id), %{ +          "status" => "yeah", +          "visibility" => "unlisted" +        })        {:ok, a3} = -        CommonAPI.post(Repo.get(User, user.id), %{"status" => "yeah", "visibility" => "private"}) +        CommonAPI.post(User.get_cached_by_id(user.id), %{ +          "status" => "yeah", +          "visibility" => "private" +        })        {:ok, a4} = -        CommonAPI.post(Repo.get(User, user.id), %{"status" => "yeah", "visibility" => "direct"}) +        CommonAPI.post(User.get_cached_by_id(user.id), %{ +          "status" => "yeah", +          "visibility" => "direct" +        }) -      {:ok, _} = a1.data["object"]["id"] |> Object.get_by_ap_id() |> ActivityPub.delete() -      {:ok, _} = a2.data["object"]["id"] |> Object.get_by_ap_id() |> ActivityPub.delete() -      {:ok, _} = a3.data["object"]["id"] |> Object.get_by_ap_id() |> ActivityPub.delete() -      {:ok, _} = a4.data["object"]["id"] |> Object.get_by_ap_id() |> ActivityPub.delete() +      {:ok, _} = Object.normalize(a1) |> ActivityPub.delete() +      {:ok, _} = Object.normalize(a2) |> ActivityPub.delete() +      {:ok, _} = Object.normalize(a3) |> ActivityPub.delete() +      {:ok, _} = Object.normalize(a4) |> ActivityPub.delete() -      user = Repo.get(User, user.id) +      user = User.get_cached_by_id(user.id)        assert user.info.note_count == 10      end @@ -712,6 +836,36 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do        assert user.ap_id in delete.data["to"]      end + +    test "decreases reply count" do +      user = insert(:user) +      user2 = insert(:user) + +      {:ok, activity} = CommonAPI.post(user, %{"status" => "1", "visibility" => "public"}) +      reply_data = %{"status" => "1", "in_reply_to_status_id" => activity.id} +      ap_id = activity.data["id"] + +      {:ok, public_reply} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "public")) +      {:ok, unlisted_reply} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "unlisted")) +      {:ok, private_reply} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "private")) +      {:ok, direct_reply} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "direct")) + +      _ = CommonAPI.delete(direct_reply.id, user2) +      assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id) +      assert object.data["repliesCount"] == 2 + +      _ = CommonAPI.delete(private_reply.id, user2) +      assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id) +      assert object.data["repliesCount"] == 2 + +      _ = CommonAPI.delete(public_reply.id, user2) +      assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id) +      assert object.data["repliesCount"] == 1 + +      _ = CommonAPI.delete(unlisted_reply.id, user2) +      assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id) +      assert object.data["repliesCount"] == 0 +    end    end    describe "timeline post-processing" do @@ -750,7 +904,11 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do        activities = ActivityPub.fetch_activities([user1.ap_id | user1.following]) -      assert [public_activity, private_activity_1, private_activity_3] == activities +      private_activity_1 = Activity.get_by_ap_id_with_object(private_activity_1.data["id"]) + +      assert [public_activity, private_activity_1, private_activity_3] == +               activities +        assert length(activities) == 3        activities = ActivityPub.contain_timeline(activities, user1) @@ -760,15 +918,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      end    end -  test "it can fetch plume articles" do -    {:ok, object} = -      ActivityPub.fetch_object_from_id( -        "https://baptiste.gelez.xyz/~/PlumeDevelopment/this-month-in-plume-june-2018/" -      ) - -    assert object -  end -    describe "update" do      test "it creates an update activity with the new user data" do        user = insert(:user) @@ -790,15 +939,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      end    end -  test "it can fetch peertube videos" do -    {:ok, object} = -      ActivityPub.fetch_object_from_id( -        "https://peertube.moe/videos/watch/df5f464b-be8d-46fb-ad81-2d4c2d1630e3" -      ) - -    assert object -  end -    test "returned pinned statuses" do      Pleroma.Config.put([:instance, :max_pinned_statuses], 3)      user = insert(:user) diff --git a/test/web/activity_pub/transmogrifier_test.exs b/test/web/activity_pub/transmogrifier_test.exs index 8184dbbae..78429c7c6 100644 --- a/test/web/activity_pub/transmogrifier_test.exs +++ b/test/web/activity_pub/transmogrifier_test.exs @@ -5,6 +5,8 @@  defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do    use Pleroma.DataCase    alias Pleroma.Activity +  alias Pleroma.Object +  alias Pleroma.Object.Fetcher    alias Pleroma.Repo    alias Pleroma.User    alias Pleroma.Web.ActivityPub.ActivityPub @@ -49,16 +51,14 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do          |> Map.put("object", object)        {:ok, returned_activity} = Transmogrifier.handle_incoming(data) +      returned_object = Object.normalize(returned_activity.data["object"])        assert activity =                 Activity.get_create_by_object_ap_id(                   "tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment"                 ) -      assert returned_activity.data["object"]["inReplyToAtomUri"] == -               "https://shitposter.club/notice/2827873" - -      assert returned_activity.data["object"]["inReplyToStatusId"] == activity.id +      assert returned_object.data["inReplyToAtomUri"] == "https://shitposter.club/notice/2827873"      end      test "it works for incoming notices" do @@ -81,7 +81,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        assert data["actor"] == "http://mastodon.example.org/users/admin" -      object = data["object"] +      object = Object.normalize(data["object"]).data        assert object["id"] == "http://mastodon.example.org/users/admin/statuses/99512778738411822"        assert object["to"] == ["https://www.w3.org/ns/activitystreams#Public"] @@ -99,7 +99,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        assert object["sensitive"] == true -      user = User.get_by_ap_id(object["actor"]) +      user = User.get_cached_by_ap_id(object["actor"])        assert user.info.note_count == 1      end @@ -108,7 +108,9 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        data = File.read!("test/fixtures/mastodon-post-activity-hashtag.json") |> Poison.decode!()        {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) -      assert Enum.at(data["object"]["tag"], 2) == "moo" +      object = Object.normalize(data["object"]) + +      assert Enum.at(object.data["tag"], 2) == "moo"      end      test "it works for incoming notices with contentMap" do @@ -116,8 +118,9 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do          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 data["object"]["content"] == +      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 @@ -125,8 +128,9 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest 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 data["object"]["content"] == +      assert object.data["content"] ==                 "<p>henlo from my Psion netBook</p><p>message sent from my Psion netBook</p>"      end @@ -142,24 +146,27 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest 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 data["object"]["emoji"] == %{ +      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 data["object"]["tag"] +      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 data["object"]["url"] == "https://prismo.news/posts/83" +      assert object.data["url"] == "https://prismo.news/posts/83"      end      test "it cleans up incoming notices which are not really DMs" do @@ -181,15 +188,15 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        data = Map.put(data, "object", object) -      {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) +      {:ok, %Activity{data: data, local: false} = activity} = Transmogrifier.handle_incoming(data)        assert data["to"] == []        assert data["cc"] == to -      object = data["object"] +      object_data = Object.normalize(activity).data -      assert object["to"] == [] -      assert object["cc"] == to +      assert object_data["to"] == [] +      assert object_data["cc"] == to      end      test "it works for incoming follow requests" do @@ -205,7 +212,27 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        assert data["actor"] == "http://mastodon.example.org/users/admin"        assert data["type"] == "Follow"        assert data["id"] == "http://mastodon.example.org/users/admin#follows/2" -      assert User.following?(User.get_by_ap_id(data["actor"]), user) +      assert User.following?(User.get_cached_by_ap_id(data["actor"]), user) +    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) + +      user = insert(:user) +      target = User.get_or_fetch("http://mastodon.example.org/users/admin") + +      {:ok, user} = User.block(user, target) + +      data = +        File.read!("test/fixtures/mastodon-follow-activity.json") +        |> Poison.decode!() +        |> Map.put("object", user.ap_id) + +      {:ok, %Activity{data: %{"id" => id}}} = Transmogrifier.handle_incoming(data) + +      %Activity{} = activity = Activity.get_by_ap_id(id) + +      assert activity.data["state"] == "reject"      end      test "it works for incoming follow requests from hubzilla" do @@ -222,7 +249,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        assert data["actor"] == "https://hubzilla.example.org/channel/kaniini"        assert data["type"] == "Follow"        assert data["id"] == "https://hubzilla.example.org/channel/kaniini#follows/2" -      assert User.following?(User.get_by_ap_id(data["actor"]), user) +      assert User.following?(User.get_cached_by_ap_id(data["actor"]), user)      end      test "it works for incoming likes" do @@ -232,14 +259,14 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        data =          File.read!("test/fixtures/mastodon-like.json")          |> Poison.decode!() -        |> Map.put("object", activity.data["object"]["id"]) +        |> Map.put("object", activity.data["object"])        {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)        assert data["actor"] == "http://mastodon.example.org/users/admin"        assert data["type"] == "Like"        assert data["id"] == "http://mastodon.example.org/users/admin#likes/2" -      assert data["object"] == activity.data["object"]["id"] +      assert data["object"] == activity.data["object"]      end      test "it returns an error for incoming unlikes wihout a like activity" do @@ -249,7 +276,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        data =          File.read!("test/fixtures/mastodon-undo-like.json")          |> Poison.decode!() -        |> Map.put("object", activity.data["object"]["id"]) +        |> Map.put("object", activity.data["object"])        assert Transmogrifier.handle_incoming(data) == :error      end @@ -261,7 +288,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        like_data =          File.read!("test/fixtures/mastodon-like.json")          |> Poison.decode!() -        |> Map.put("object", activity.data["object"]["id"]) +        |> Map.put("object", activity.data["object"])        {:ok, %Activity{data: like_data, local: false}} = Transmogrifier.handle_incoming(like_data) @@ -303,7 +330,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        data =          File.read!("test/fixtures/mastodon-announce.json")          |> Poison.decode!() -        |> Map.put("object", activity.data["object"]["id"]) +        |> Map.put("object", activity.data["object"])        {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) @@ -313,7 +340,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        assert data["id"] ==                 "http://mastodon.example.org/users/admin/statuses/99542391527669785/activity" -      assert data["object"] == activity.data["object"]["id"] +      assert data["object"] == activity.data["object"]        assert Activity.get_create_by_object_ap_id(data["object"]).id == activity.id      end @@ -325,7 +352,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        data =          File.read!("test/fixtures/mastodon-announce.json")          |> Poison.decode!() -        |> Map.put("object", activity.data["object"]["id"]) +        |> Map.put("object", Object.normalize(activity).data["id"])          |> Map.put("to", ["http://mastodon.example.org/users/admin/followers"])          |> Map.put("cc", []) @@ -334,6 +361,53 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        assert data["to"] == ["http://mastodon.example.org/users/admin/followers"]      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", []) + +      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) + +      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 works for incoming update activities" do        data = File.read!("test/fixtures/mastodon-post-activity.json") |> Poison.decode!() @@ -404,7 +478,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        object =          data["object"] -        |> Map.put("id", activity.data["object"]["id"]) +        |> Map.put("id", activity.data["object"])        data =          data @@ -413,7 +487,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        {:ok, %Activity{local: false}} = Transmogrifier.handle_incoming(data) -      refute Repo.get(Activity, activity.id) +      refute Activity.get_by_id(activity.id)      end      test "it fails for incoming deletes with spoofed origin" do @@ -425,7 +499,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        object =          data["object"] -        |> Map.put("id", activity.data["object"]["id"]) +        |> Map.put("id", activity.data["object"])        data =          data @@ -433,7 +507,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        :error = Transmogrifier.handle_incoming(data) -      assert Repo.get(Activity, activity.id) +      assert Activity.get_by_id(activity.id)      end      test "it works for incoming unannounces with an existing notice" do @@ -443,7 +517,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        announce_data =          File.read!("test/fixtures/mastodon-announce.json")          |> Poison.decode!() -        |> Map.put("object", activity.data["object"]["id"]) +        |> Map.put("object", activity.data["object"])        {:ok, %Activity{data: announce_data, local: false}} =          Transmogrifier.handle_incoming(announce_data) @@ -458,7 +532,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        assert data["type"] == "Undo"        assert data["object"]["type"] == "Announce" -      assert data["object"]["object"] == activity.data["object"]["id"] +      assert data["object"]["object"] == activity.data["object"]        assert data["object"]["id"] ==                 "http://mastodon.example.org/users/admin/statuses/99542391527669785/activity" @@ -486,7 +560,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        assert data["object"]["object"] == user.ap_id        assert data["actor"] == "http://mastodon.example.org/users/admin" -      refute User.following?(User.get_by_ap_id(data["actor"]), user) +      refute User.following?(User.get_cached_by_ap_id(data["actor"]), user)      end      test "it works for incoming blocks" do @@ -503,7 +577,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        assert data["object"] == user.ap_id        assert data["actor"] == "http://mastodon.example.org/users/admin" -      blocker = User.get_by_ap_id(data["actor"]) +      blocker = User.get_cached_by_ap_id(data["actor"])        assert User.blocks?(blocker, user)      end @@ -530,8 +604,8 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        assert data["object"] == blocked.ap_id        assert data["actor"] == blocker.ap_id -      blocker = User.get_by_ap_id(data["actor"]) -      blocked = User.get_by_ap_id(data["object"]) +      blocker = User.get_cached_by_ap_id(data["actor"]) +      blocked = User.get_cached_by_ap_id(data["object"])        assert User.blocks?(blocker, blocked) @@ -560,7 +634,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        assert data["object"]["object"] == user.ap_id        assert data["actor"] == "http://mastodon.example.org/users/admin" -      blocker = User.get_by_ap_id(data["actor"]) +      blocker = User.get_cached_by_ap_id(data["actor"])        refute User.blocks?(blocker, user)      end @@ -591,7 +665,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        assert activity.data["object"] == follow_activity.data["id"] -      follower = Repo.get(User, follower.id) +      follower = User.get_cached_by_id(follower.id)        assert User.following?(follower, followed) == true      end @@ -613,7 +687,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        {:ok, activity} = Transmogrifier.handle_incoming(accept_data)        assert activity.data["object"] == follow_activity.data["id"] -      follower = Repo.get(User, follower.id) +      follower = User.get_cached_by_id(follower.id)        assert User.following?(follower, followed) == true      end @@ -633,7 +707,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        {:ok, activity} = Transmogrifier.handle_incoming(accept_data)        assert activity.data["object"] == follow_activity.data["id"] -      follower = Repo.get(User, follower.id) +      follower = User.get_cached_by_id(follower.id)        assert User.following?(follower, followed) == true      end @@ -652,7 +726,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        :error = Transmogrifier.handle_incoming(accept_data) -      follower = Repo.get(User, follower.id) +      follower = User.get_cached_by_id(follower.id)        refute User.following?(follower, followed) == true      end @@ -671,7 +745,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        :error = Transmogrifier.handle_incoming(accept_data) -      follower = Repo.get(User, follower.id) +      follower = User.get_cached_by_id(follower.id)        refute User.following?(follower, followed) == true      end @@ -696,7 +770,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        {:ok, activity} = Transmogrifier.handle_incoming(reject_data)        refute activity.local -      follower = Repo.get(User, follower.id) +      follower = User.get_cached_by_id(follower.id)        assert User.following?(follower, followed) == false      end @@ -718,7 +792,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        {:ok, %Activity{data: _}} = Transmogrifier.handle_incoming(reject_data) -      follower = Repo.get(User, follower.id) +      follower = User.get_cached_by_id(follower.id)        assert User.following?(follower, followed) == false      end @@ -737,7 +811,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do      test "it remaps video URLs as attachments if necessary" do        {:ok, object} = -        ActivityPub.fetch_object_from_id( +        Fetcher.fetch_object_from_id(            "https://peertube.moe/videos/watch/df5f464b-be8d-46fb-ad81-2d4c2d1630e3"          ) @@ -764,6 +838,30 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        assert object.data["attachment"] == [attachment]      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.data["object"]) + +      message = %{ +        "@context" => "https://www.w3.org/ns/activitystreams", +        "cc" => [user.ap_id], +        "object" => [user.ap_id, object.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, object.data["id"]] +      assert activity.data["content"] == "blocked AND reported!!!" +      assert activity.data["actor"] == other_user.ap_id +      assert activity.data["cc"] == [user.ap_id] +    end    end    describe "prepare outgoing" do @@ -868,7 +966,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do      test "it strips internal fields" do        user = insert(:user) -      {:ok, activity} = CommonAPI.post(user, %{"status" => "#2hu :moominmamma:"}) +      {:ok, activity} = CommonAPI.post(user, %{"status" => "#2hu :firefox:"})        {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) @@ -948,7 +1046,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        {:ok, unrelated_activity} = CommonAPI.post(user_two, %{"status" => "test"})        assert "http://localhost:4001/users/rye@niu.moe/followers" in activity.recipients -      user = Repo.get(User, user.id) +      user = User.get_cached_by_id(user.id)        assert user.info.note_count == 1        {:ok, user} = Transmogrifier.upgrade_user_from_ap_id("https://niu.moe/users/rye") @@ -956,13 +1054,10 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        assert user.info.note_count == 1        assert user.follower_address == "https://niu.moe/users/rye/followers" -      # Wait for the background task -      :timer.sleep(1000) - -      user = Repo.get(User, user.id) +      user = User.get_cached_by_id(user.id)        assert user.info.note_count == 1 -      activity = Repo.get(Activity, activity.id) +      activity = Activity.get_by_id(activity.id)        assert user.follower_address in activity.recipients        assert %{ @@ -985,10 +1080,10 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        refute "..." in activity.recipients -      unrelated_activity = Repo.get(Activity, unrelated_activity.id) +      unrelated_activity = Activity.get_by_id(unrelated_activity.id)        refute user.follower_address in unrelated_activity.recipients -      user_two = Repo.get(User, user_two.id) +      user_two = User.get_cached_by_id(user_two.id)        assert user.follower_address in user_two.following        refute "..." in user_two.following      end @@ -1021,10 +1116,6 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do    end    describe "actor origin containment" do -    test "it rejects objects with a bogus origin" do -      {:error, _} = ActivityPub.fetch_object_from_id("https://info.pleroma.site/activity.json") -    end -      test "it rejects activities which reference objects with bogus origins" do        data = %{          "@context" => "https://www.w3.org/ns/activitystreams", @@ -1038,10 +1129,6 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        :error = Transmogrifier.handle_incoming(data)      end -    test "it rejects objects when attributedTo is wrong (variant 1)" do -      {:error, _} = ActivityPub.fetch_object_from_id("https://info.pleroma.site/activity2.json") -    end -      test "it rejects activities which reference objects that have an incorrect attribution (variant 1)" do        data = %{          "@context" => "https://www.w3.org/ns/activitystreams", @@ -1055,10 +1142,6 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        :error = Transmogrifier.handle_incoming(data)      end -    test "it rejects objects when attributedTo is wrong (variant 2)" do -      {:error, _} = ActivityPub.fetch_object_from_id("https://info.pleroma.site/activity3.json") -    end -      test "it rejects activities which reference objects that have an incorrect attribution (variant 2)" do        data = %{          "@context" => "https://www.w3.org/ns/activitystreams", @@ -1073,62 +1156,6 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do      end    end -  describe "general origin containment" do -    test "contain_origin_from_id() catches obvious spoofing attempts" do -      data = %{ -        "id" => "http://example.com/~alyssa/activities/1234.json" -      } - -      :error = -        Transmogrifier.contain_origin_from_id( -          "http://example.org/~alyssa/activities/1234.json", -          data -        ) -    end - -    test "contain_origin_from_id() allows alternate IDs within the same origin domain" do -      data = %{ -        "id" => "http://example.com/~alyssa/activities/1234.json" -      } - -      :ok = -        Transmogrifier.contain_origin_from_id( -          "http://example.com/~alyssa/activities/1234", -          data -        ) -    end - -    test "contain_origin_from_id() allows matching IDs" do -      data = %{ -        "id" => "http://example.com/~alyssa/activities/1234.json" -      } - -      :ok = -        Transmogrifier.contain_origin_from_id( -          "http://example.com/~alyssa/activities/1234.json", -          data -        ) -    end - -    test "users cannot be collided through fake direction spoofing attempts" do -      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"}) -      }) - -      {:error, _} = User.get_or_fetch_by_ap_id("https://n1u.moe/users/rye") -    end - -    test "all objects with fake directions are rejected by the object fetcher" do -      {:error, _} = -        ActivityPub.fetch_and_contain_remote_object_from_id( -          "https://info.pleroma.site/activity4.json" -        ) -    end -  end -    describe "reserialization" do      test "successfully reserializes a message with inReplyTo == nil" do        user = insert(:user) diff --git a/test/web/activity_pub/utils_test.exs b/test/web/activity_pub/utils_test.exs index 2bd3ddf93..c57fae437 100644 --- a/test/web/activity_pub/utils_test.exs +++ b/test/web/activity_pub/utils_test.exs @@ -1,10 +1,33 @@  defmodule Pleroma.Web.ActivityPub.UtilsTest do    use Pleroma.DataCase +  alias Pleroma.Activity +  alias Pleroma.User +  alias Pleroma.Web.ActivityPub.ActivityPub    alias Pleroma.Web.ActivityPub.Utils    alias Pleroma.Web.CommonAPI    import Pleroma.Factory +  describe "fetch the latest Follow" do +    test "fetches the latest Follow activity" do +      %Activity{data: %{"type" => "Follow"}} = activity = insert(:follow_activity) +      follower = User.get_cached_by_ap_id(activity.data["actor"]) +      followed = User.get_cached_by_ap_id(activity.data["object"]) + +      assert activity == Utils.fetch_latest_follow(follower, followed) +    end +  end + +  describe "fetch the latest Block" do +    test "fetches the latest Block activity" do +      blocker = insert(:user) +      blocked = insert(:user) +      {:ok, activity} = ActivityPub.block(blocker, blocked) + +      assert activity == Utils.fetch_latest_block(blocker, blocked) +    end +  end +    describe "determine_explicit_mentions()" do      test "works with an object that has mentions" do        object = %{ @@ -169,4 +192,16 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do        assert Utils.fetch_ordered_collection("http://example.com/outbox", 5) == [0, 1]      end    end + +  test "make_json_ld_header/0" do +    assert Utils.make_json_ld_header() == %{ +             "@context" => [ +               "https://www.w3.org/ns/activitystreams", +               "http://localhost:4001/schemas/litepub-0.1.jsonld", +               %{ +                 "@language" => "und" +               } +             ] +           } +  end  end diff --git a/test/web/activity_pub/views/user_view_test.exs b/test/web/activity_pub/views/user_view_test.exs index 0bc1d4728..9fb9455d2 100644 --- a/test/web/activity_pub/views/user_view_test.exs +++ b/test/web/activity_pub/views/user_view_test.exs @@ -16,6 +16,29 @@ defmodule Pleroma.Web.ActivityPub.UserViewTest do      assert String.contains?(result["publicKey"]["publicKeyPem"], "BEGIN PUBLIC KEY")    end +  test "Does not add an avatar image if the user hasn't set one" do +    user = insert(:user) +    {:ok, user} = Pleroma.Web.WebFinger.ensure_keys_present(user) + +    result = UserView.render("user.json", %{user: user}) +    refute result["icon"] +    refute result["image"] + +    user = +      insert(:user, +        avatar: %{"url" => [%{"href" => "https://someurl"}]}, +        info: %{ +          banner: %{"url" => [%{"href" => "https://somebanner"}]} +        } +      ) + +    {:ok, user} = Pleroma.Web.WebFinger.ensure_keys_present(user) + +    result = UserView.render("user.json", %{user: user}) +    assert result["icon"]["url"] == "https://someurl" +    assert result["image"]["url"] == "https://somebanner" +  end +    describe "endpoints" do      test "local users have a usable endpoints structure" do        user = insert(:user) diff --git a/test/web/admin_api/admin_api_controller_test.exs b/test/web/admin_api/admin_api_controller_test.exs index e50f0edde..b89c42327 100644 --- a/test/web/admin_api/admin_api_controller_test.exs +++ b/test/web/admin_api/admin_api_controller_test.exs @@ -5,8 +5,8 @@  defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do    use Pleroma.Web.ConnCase -  alias Pleroma.Repo    alias Pleroma.User +  alias Pleroma.UserInviteToken    import Pleroma.Factory    describe "/api/pleroma/admin/user" do @@ -40,6 +40,85 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do      end    end +  describe "/api/pleroma/admin/users/:nickname" do +    test "Show", %{conn: conn} do +      admin = insert(:user, info: %{is_admin: true}) +      user = insert(:user) + +      conn = +        conn +        |> assign(:user, admin) +        |> get("/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" => [] +      } + +      assert expected == json_response(conn, 200) +    end + +    test "when the user doesn't exist", %{conn: conn} do +      admin = insert(:user, info: %{is_admin: true}) +      user = build(:user) + +      conn = +        conn +        |> assign(:user, admin) +        |> get("/api/pleroma/admin/users/#{user.nickname}") + +      assert "Not found" == json_response(conn, 404) +    end +  end + +  describe "/api/pleroma/admin/user/follow" do +    test "allows to force-follow another user" do +      admin = insert(:user, info: %{is_admin: true}) +      user = insert(:user) +      follower = insert(:user) + +      build_conn() +      |> assign(:user, admin) +      |> put_req_header("accept", "application/json") +      |> post("/api/pleroma/admin/user/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) +    end +  end + +  describe "/api/pleroma/admin/user/unfollow" do +    test "allows to force-unfollow another user" do +      admin = insert(:user, info: %{is_admin: true}) +      user = insert(:user) +      follower = insert(:user) + +      User.follow(follower, user) + +      build_conn() +      |> assign(:user, admin) +      |> put_req_header("accept", "application/json") +      |> post("/api/pleroma/admin/user/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) +    end +  end +    describe "PUT /api/pleroma/admin/users/tag" do      setup do        admin = insert(:user, info: %{is_admin: true}) @@ -66,13 +145,13 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do        user2: user2      } do        assert json_response(conn, :no_content) -      assert Repo.get(User, user1.id).tags == ["x", "foo", "bar"] -      assert Repo.get(User, user2.id).tags == ["y", "foo", "bar"] +      assert User.get_cached_by_id(user1.id).tags == ["x", "foo", "bar"] +      assert User.get_cached_by_id(user2.id).tags == ["y", "foo", "bar"]      end      test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do        assert json_response(conn, :no_content) -      assert Repo.get(User, user3.id).tags == ["unchanged"] +      assert User.get_cached_by_id(user3.id).tags == ["unchanged"]      end    end @@ -102,13 +181,13 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do        user2: user2      } do        assert json_response(conn, :no_content) -      assert Repo.get(User, user1.id).tags == [] -      assert Repo.get(User, user2.id).tags == ["y"] +      assert User.get_cached_by_id(user1.id).tags == [] +      assert User.get_cached_by_id(user2.id).tags == ["y"]      end      test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do        assert json_response(conn, :no_content) -      assert Repo.get(User, user3.id).tags == ["unchanged"] +      assert User.get_cached_by_id(user3.id).tags == ["unchanged"]      end    end @@ -178,7 +257,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do          conn          |> put("/api/pleroma/admin/activation_status/#{user.nickname}", %{status: false}) -      user = Repo.get(User, user.id) +      user = User.get_cached_by_id(user.id)        assert user.info.deactivated == true        assert json_response(conn, :no_content)      end @@ -190,7 +269,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do          conn          |> put("/api/pleroma/admin/activation_status/#{user.nickname}", %{status: true}) -      user = Repo.get(User, user.id) +      user = User.get_cached_by_id(user.id)        assert user.info.deactivated == false        assert json_response(conn, :no_content)      end @@ -238,13 +317,21 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do        assert token_record        refute token_record.used -      Swoosh.TestAssertions.assert_email_sent( -        Pleroma.UserEmail.user_invitation_email( +      notify_email = Pleroma.Config.get([:instance, :notify_email]) +      instance_name = Pleroma.Config.get([:instance, :name]) + +      email = +        Pleroma.Emails.UserEmail.user_invitation_email(            user,            token_record,            recipient_email,            recipient_name          ) + +      Swoosh.TestAssertions.assert_email_sent( +        from: {instance_name, notify_email}, +        to: {recipient_name, recipient_email}, +        html_body: email.html_body        )      end @@ -408,13 +495,13 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do      test "regular search with page size" do        admin = insert(:user, info: %{is_admin: true}) -      user = insert(:user, nickname: "bob") -      user2 = insert(:user, nickname: "bo") +      user = insert(:user, nickname: "aalice") +      user2 = insert(:user, nickname: "alice")        conn =          build_conn()          |> assign(:user, admin) -        |> get("/api/pleroma/admin/users?query=bo&page_size=1&page=1") +        |> get("/api/pleroma/admin/users?query=a&page_size=1&page=1")        assert json_response(conn, 200) == %{                 "count" => 2, @@ -434,7 +521,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do        conn =          build_conn()          |> assign(:user, admin) -        |> get("/api/pleroma/admin/users?query=bo&page_size=1&page=2") +        |> get("/api/pleroma/admin/users?query=a&page_size=1&page=2")        assert json_response(conn, 200) == %{                 "count" => 2, @@ -461,7 +548,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do        conn =          build_conn()          |> assign(:user, admin) -        |> get("/api/pleroma/admin/users?query=bo&local_only=true") +        |> get("/api/pleroma/admin/users?query=bo&filters=local")        assert json_response(conn, 200) == %{                 "count" => 1, @@ -488,26 +575,54 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do        conn =          build_conn()          |> assign(:user, admin) -        |> get("/api/pleroma/admin/users?local_only=true") +        |> get("/api/pleroma/admin/users?filters=local")        assert json_response(conn, 200) == %{                 "count" => 2,                 "page_size" => 50,                 "users" => [                   %{ +                   "deactivated" => user.info.deactivated, +                   "id" => user.id, +                   "nickname" => user.nickname, +                   "roles" => %{"admin" => false, "moderator" => false}, +                   "local" => true, +                   "tags" => [] +                 }, +                 %{                     "deactivated" => admin.info.deactivated,                     "id" => admin.id,                     "nickname" => admin.nickname,                     "roles" => %{"admin" => true, "moderator" => false},                     "local" => true,                     "tags" => [] -                 }, +                 } +               ] +             } +    end + +    test "it works with multiple filters" do +      admin = insert(:user, nickname: "john", info: %{is_admin: true}) +      user = insert(:user, nickname: "bob", local: false, info: %{deactivated: true}) + +      insert(:user, nickname: "ken", local: true, info: %{deactivated: true}) +      insert(:user, nickname: "bobb", local: false, info: %{deactivated: false}) + +      conn = +        build_conn() +        |> assign(:user, admin) +        |> get("/api/pleroma/admin/users?filters=deactivated,external") + +      assert json_response(conn, 200) == %{ +               "count" => 1, +               "page_size" => 50, +               "users" => [                   %{                     "deactivated" => user.info.deactivated,                     "id" => user.id,                     "nickname" => user.nickname,                     "roles" => %{"admin" => false, "moderator" => false}, -                   "local" => true, +                   "local" => user.local,                     "tags" => []                   }                 ] @@ -534,4 +649,136 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do                 "tags" => []               }    end + +  describe "GET /api/pleroma/admin/invite_token" do +    test "without options" do +      admin = insert(:user, info: %{is_admin: true}) + +      conn = +        build_conn() +        |> assign(:user, admin) +        |> get("/api/pleroma/admin/invite_token") + +      token = json_response(conn, 200) +      invite = UserInviteToken.find_by_token!(token) +      refute invite.used +      refute invite.expires_at +      refute invite.max_use +      assert invite.invite_type == "one_time" +    end + +    test "with expires_at" do +      admin = insert(:user, info: %{is_admin: true}) + +      conn = +        build_conn() +        |> assign(:user, admin) +        |> get("/api/pleroma/admin/invite_token", %{ +          "invite" => %{"expires_at" => Date.to_string(Date.utc_today())} +        }) + +      token = json_response(conn, 200) +      invite = UserInviteToken.find_by_token!(token) + +      refute invite.used +      assert invite.expires_at == Date.utc_today() +      refute invite.max_use +      assert invite.invite_type == "date_limited" +    end + +    test "with max_use" do +      admin = insert(:user, info: %{is_admin: true}) + +      conn = +        build_conn() +        |> assign(:user, admin) +        |> get("/api/pleroma/admin/invite_token", %{ +          "invite" => %{"max_use" => 150} +        }) + +      token = json_response(conn, 200) +      invite = UserInviteToken.find_by_token!(token) +      refute invite.used +      refute invite.expires_at +      assert invite.max_use == 150 +      assert invite.invite_type == "reusable" +    end + +    test "with max use and expires_at" do +      admin = insert(:user, info: %{is_admin: true}) + +      conn = +        build_conn() +        |> assign(:user, admin) +        |> get("/api/pleroma/admin/invite_token", %{ +          "invite" => %{"max_use" => 150, "expires_at" => Date.to_string(Date.utc_today())} +        }) + +      token = json_response(conn, 200) +      invite = UserInviteToken.find_by_token!(token) +      refute invite.used +      assert invite.expires_at == Date.utc_today() +      assert invite.max_use == 150 +      assert invite.invite_type == "reusable_date_limited" +    end +  end + +  describe "GET /api/pleroma/admin/invites" do +    test "no invites" do +      admin = insert(:user, info: %{is_admin: true}) + +      conn = +        build_conn() +        |> assign(:user, admin) +        |> get("/api/pleroma/admin/invites") + +      assert json_response(conn, 200) == %{"invites" => []} +    end + +    test "with invite" do +      admin = insert(:user, info: %{is_admin: true}) +      {:ok, invite} = UserInviteToken.create_invite() + +      conn = +        build_conn() +        |> assign(:user, admin) +        |> get("/api/pleroma/admin/invites") + +      assert json_response(conn, 200) == %{ +               "invites" => [ +                 %{ +                   "expires_at" => nil, +                   "id" => invite.id, +                   "invite_type" => "one_time", +                   "max_use" => nil, +                   "token" => invite.token, +                   "used" => false, +                   "uses" => 0 +                 } +               ] +             } +    end +  end + +  describe "POST /api/pleroma/admin/revoke_invite" do +    test "with token" do +      admin = insert(:user, info: %{is_admin: true}) +      {:ok, invite} = UserInviteToken.create_invite() + +      conn = +        build_conn() +        |> assign(:user, admin) +        |> post("/api/pleroma/admin/revoke_invite", %{"token" => invite.token}) + +      assert json_response(conn, 200) == %{ +               "expires_at" => nil, +               "id" => invite.id, +               "invite_type" => "one_time", +               "max_use" => nil, +               "token" => invite.token, +               "used" => true, +               "uses" => 0 +             } +    end +  end  end diff --git a/test/web/admin_api/search_test.exs b/test/web/admin_api/search_test.exs new file mode 100644 index 000000000..3950996ed --- /dev/null +++ b/test/web/admin_api/search_test.exs @@ -0,0 +1,88 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.AdminAPI.SearchTest do +  use Pleroma.Web.ConnCase + +  alias Pleroma.Web.AdminAPI.Search + +  import Pleroma.Factory + +  describe "search for admin" do +    test "it ignores case" do +      insert(:user, nickname: "papercoach") +      insert(:user, nickname: "CanadaPaperCoach") + +      {:ok, _results, count} = +        Search.user(%{ +          query: "paper", +          local: false, +          page: 1, +          page_size: 50 +        }) + +      assert count == 2 +    end + +    test "it returns local/external users" do +      insert(:user, local: true) +      insert(:user, local: false) +      insert(:user, local: false) + +      {:ok, _results, local_count} = +        Search.user(%{ +          query: "", +          local: true +        }) + +      {:ok, _results, external_count} = +        Search.user(%{ +          query: "", +          external: true +        }) + +      assert local_count == 1 +      assert external_count == 2 +    end + +    test "it returns active/deactivated users" do +      insert(:user, info: %{deactivated: true}) +      insert(:user, info: %{deactivated: true}) +      insert(:user, info: %{deactivated: false}) + +      {:ok, _results, active_count} = +        Search.user(%{ +          query: "", +          active: true +        }) + +      {:ok, _results, deactivated_count} = +        Search.user(%{ +          query: "", +          deactivated: true +        }) + +      assert active_count == 1 +      assert deactivated_count == 2 +    end + +    test "it returns specific user" do +      insert(:user) +      insert(:user) +      insert(:user, nickname: "bob", local: true, info: %{deactivated: false}) + +      {:ok, _results, total_count} = Search.user(%{query: ""}) + +      {:ok, _results, count} = +        Search.user(%{ +          query: "Bo", +          active: true, +          local: true +        }) + +      assert total_count == 3 +      assert count == 1 +    end +  end +end diff --git a/test/web/common_api/common_api_test.exs b/test/web/common_api/common_api_test.exs index 181813c76..a5b07c446 100644 --- a/test/web/common_api/common_api_test.exs +++ b/test/web/common_api/common_api_test.exs @@ -5,33 +5,54 @@  defmodule Pleroma.Web.CommonAPITest do    use Pleroma.DataCase    alias Pleroma.Activity +  alias Pleroma.Object    alias Pleroma.User    alias Pleroma.Web.CommonAPI    import Pleroma.Factory +  test "with the safe_dm_mention option set, it does not mention people beyond the initial tags" do +    har = insert(:user) +    jafnhar = insert(:user) +    tridi = insert(:user) +    option = Pleroma.Config.get([:instance, :safe_dm_mentions]) +    Pleroma.Config.put([:instance, :safe_dm_mentions], true) + +    {:ok, activity} = +      CommonAPI.post(har, %{ +        "status" => "@#{jafnhar.nickname} hey, i never want to see @#{tridi.nickname} again", +        "visibility" => "direct" +      }) + +    refute tridi.ap_id in activity.recipients +    assert jafnhar.ap_id in activity.recipients +    Pleroma.Config.put([:instance, :safe_dm_mentions], option) +  end +    test "it de-duplicates tags" do      user = insert(:user)      {:ok, activity} = CommonAPI.post(user, %{"status" => "#2hu #2HU"}) -    assert activity.data["object"]["tag"] == ["2hu"] +    object = Object.normalize(activity.data["object"]) + +    assert object.data["tag"] == ["2hu"]    end    test "it adds emoji in the object" do      user = insert(:user) -    {:ok, activity} = CommonAPI.post(user, %{"status" => ":moominmamma:"}) +    {:ok, activity} = CommonAPI.post(user, %{"status" => ":firefox:"}) -    assert activity.data["object"]["emoji"]["moominmamma"] +    assert Object.normalize(activity).data["emoji"]["firefox"]    end    test "it adds emoji when updating profiles" do -    user = insert(:user, %{name: ":karjalanpiirakka:"}) +    user = insert(:user, %{name: ":firefox:"})      CommonAPI.update(user)      user = User.get_cached_by_ap_id(user.ap_id) -    [karjalanpiirakka] = user.info.source_data["tag"] +    [firefox] = user.info.source_data["tag"] -    assert karjalanpiirakka["name"] == ":karjalanpiirakka:" +    assert firefox["name"] == ":firefox:"    end    describe "posting" do @@ -46,8 +67,9 @@ defmodule Pleroma.Web.CommonAPITest do            "content_type" => "text/html"          }) -      content = activity.data["object"]["content"] -      assert content == "<p><b>2hu</b></p>alert('xss')" +      object = Object.normalize(activity.data["object"]) + +      assert object.data["content"] == "<p><b>2hu</b></p>alert('xss')"      end      test "it filters out obviously bad tags when accepting a post as Markdown" do @@ -61,8 +83,9 @@ defmodule Pleroma.Web.CommonAPITest do            "content_type" => "text/markdown"          }) -      content = activity.data["object"]["content"] -      assert content == "<p><b>2hu</b></p>alert('xss')" +      object = Object.normalize(activity.data["object"]) + +      assert object.data["content"] == "<p><b>2hu</b></p>alert('xss')"      end    end @@ -221,4 +244,27 @@ defmodule Pleroma.Web.CommonAPITest do               } = flag_activity      end    end + +  describe "reblog muting" do +    setup do +      muter = insert(:user) + +      muted = insert(:user) + +      [muter: muter, muted: muted] +    end + +    test "add a reblog mute", %{muter: muter, muted: muted} do +      {:ok, muter} = CommonAPI.hide_reblogs(muter, muted) + +      assert Pleroma.User.showing_reblogs?(muter, muted) == false +    end + +    test "remove a reblog mute", %{muter: muter, muted: muted} do +      {:ok, muter} = CommonAPI.hide_reblogs(muter, muted) +      {:ok, muter} = CommonAPI.show_reblogs(muter, muted) + +      assert Pleroma.User.showing_reblogs?(muter, muted) == true +    end +  end  end diff --git a/test/web/common_api/common_api_utils_test.exs b/test/web/common_api/common_api_utils_test.exs index 4c97b0d62..ab4c62b35 100644 --- a/test/web/common_api/common_api_utils_test.exs +++ b/test/web/common_api/common_api_utils_test.exs @@ -4,6 +4,7 @@  defmodule Pleroma.Web.CommonAPI.UtilsTest do    alias Pleroma.Builders.UserBuilder +  alias Pleroma.Object    alias Pleroma.Web.CommonAPI.Utils    alias Pleroma.Web.Endpoint    use Pleroma.DataCase @@ -36,21 +37,21 @@ defmodule Pleroma.Web.CommonAPI.UtilsTest do    end    test "parses emoji from name and bio" do -    {:ok, user} = UserBuilder.insert(%{name: ":karjalanpiirakka:", bio: ":perkele:"}) +    {:ok, user} = UserBuilder.insert(%{name: ":blank:", bio: ":firefox:"})      expected = [        %{          "type" => "Emoji", -        "icon" => %{"type" => "Image", "url" => "#{Endpoint.url()}/finmoji/128px/perkele-128.png"}, -        "name" => ":perkele:" +        "icon" => %{"type" => "Image", "url" => "#{Endpoint.url()}/emoji/Firefox.gif"}, +        "name" => ":firefox:"        },        %{          "type" => "Emoji",          "icon" => %{            "type" => "Image", -          "url" => "#{Endpoint.url()}/finmoji/128px/karjalanpiirakka-128.png" +          "url" => "#{Endpoint.url()}/emoji/blank.png"          }, -        "name" => ":karjalanpiirakka:" +        "name" => ":blank:"        }      ] @@ -118,6 +119,31 @@ defmodule Pleroma.Web.CommonAPI.UtilsTest do        assert output == expected      end +    test "works for bare text/bbcode" do +      text = "[b]hello world[/b]" +      expected = "<strong>hello world</strong>" + +      {output, [], []} = Utils.format_input(text, "text/bbcode") + +      assert output == expected + +      text = "[b]hello world![/b]\n\nsecond paragraph!" +      expected = "<strong>hello world!</strong><br>\n<br>\nsecond paragraph!" + +      {output, [], []} = Utils.format_input(text, "text/bbcode") + +      assert output == expected + +      text = "[b]hello world![/b]\n\n<strong>second paragraph!</strong>" + +      expected = +        "<strong>hello world!</strong><br>\n<br>\n<strong>second paragraph!</strong>" + +      {output, [], []} = Utils.format_input(text, "text/bbcode") + +      assert output == expected +    end +      test "works for text/markdown with mentions" do        {:ok, user} =          UserBuilder.insert(%{nickname: "user__test", ap_id: "http://foo.com/user__test"}) @@ -136,4 +162,56 @@ defmodule Pleroma.Web.CommonAPI.UtilsTest do        assert output == expected      end    end + +  describe "context_to_conversation_id" do +    test "creates a mapping object" do +      conversation_id = Utils.context_to_conversation_id("random context") +      object = Object.get_by_ap_id("random context") + +      assert conversation_id == object.id +    end + +    test "returns an existing mapping for an existing object" do +      {:ok, object} = Object.context_mapping("random context") |> Repo.insert() +      conversation_id = Utils.context_to_conversation_id("random context") + +      assert conversation_id == object.id +    end +  end + +  describe "formats date to asctime" do +    test "when date is in ISO 8601 format" do +      date = DateTime.utc_now() |> DateTime.to_iso8601() + +      expected = +        date +        |> DateTime.from_iso8601() +        |> elem(1) +        |> Calendar.Strftime.strftime!("%a %b %d %H:%M:%S %z %Y") + +      assert Utils.date_to_asctime(date) == expected +    end + +    test "when date is a binary in wrong format" do +      date = DateTime.utc_now() + +      expected = "" + +      assert Utils.date_to_asctime(date) == expected +    end + +    test "when date is a Unix timestamp" do +      date = DateTime.utc_now() |> DateTime.to_unix() + +      expected = "" + +      assert Utils.date_to_asctime(date) == expected +    end + +    test "when date is nil" do +      expected = "" + +      assert Utils.date_to_asctime(nil) == expected +    end +  end  end diff --git a/test/web/mastodon_api/account_view_test.exs b/test/web/mastodon_api/account_view_test.exs index c2ffc21da..a24f2a050 100644 --- a/test/web/mastodon_api/account_view_test.exs +++ b/test/web/mastodon_api/account_view_test.exs @@ -56,14 +56,17 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do        bot: false,        source: %{          note: "", -        privacy: "public", -        sensitive: false +        sensitive: false, +        pleroma: %{}        },        pleroma: %{          confirmation_pending: false,          tags: [],          is_admin: false,          is_moderator: false, +        hide_favorites: true, +        hide_followers: false, +        hide_follows: false,          relationship: %{}        }      } @@ -71,6 +74,24 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do      assert expected == AccountView.render("account.json", %{user: user})    end +  test "Represent the user account for the account owner" do +    user = insert(:user) + +    notification_settings = %{ +      "remote" => true, +      "local" => true, +      "followers" => true, +      "follows" => true +    } + +    privacy = user.info.default_scope + +    assert %{ +             pleroma: %{notification_settings: ^notification_settings}, +             source: %{privacy: ^privacy} +           } = AccountView.render("account.json", %{user: user, for: user}) +  end +    test "Represent a Service(bot) account" do      user =        insert(:user, %{ @@ -100,14 +121,17 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do        bot: true,        source: %{          note: "", -        privacy: "public", -        sensitive: false +        sensitive: false, +        pleroma: %{}        },        pleroma: %{          confirmation_pending: false,          tags: [],          is_admin: false,          is_moderator: false, +        hide_favorites: true, +        hide_followers: false, +        hide_follows: false,          relationship: %{}        }      } @@ -142,9 +166,10 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do        blocking: true,        muting: false,        muting_notifications: false, +      subscribing: false,        requested: false,        domain_blocking: false, -      showing_reblogs: false, +      showing_reblogs: true,        endorsed: false      } @@ -154,15 +179,15 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do    test "represent an embedded relationship" do      user =        insert(:user, %{ -        info: %{note_count: 5, follower_count: 3, source_data: %{"type" => "Service"}}, +        info: %{note_count: 5, follower_count: 0, source_data: %{"type" => "Service"}},          nickname: "shp@shitposter.club",          inserted_at: ~N[2017-08-15 15:47:06.597036]        })      other_user = insert(:user) -      {:ok, other_user} = User.follow(other_user, user)      {:ok, other_user} = User.block(other_user, user) +    {:ok, _} = User.follow(insert(:user), user)      expected = %{        id: to_string(user.id), @@ -171,7 +196,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do        display_name: user.name,        locked: false,        created_at: "2017-08-15T15:47:06.000Z", -      followers_count: 3, +      followers_count: 1,        following_count: 0,        statuses_count: 5,        note: user.bio, @@ -185,24 +210,28 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do        bot: true,        source: %{          note: "", -        privacy: "public", -        sensitive: false +        sensitive: false, +        pleroma: %{}        },        pleroma: %{          confirmation_pending: false,          tags: [],          is_admin: false,          is_moderator: false, +        hide_favorites: true, +        hide_followers: false, +        hide_follows: false,          relationship: %{            id: to_string(user.id),            following: false,            followed_by: false,            blocking: true, +          subscribing: false,            muting: false,            muting_notifications: false,            requested: false,            domain_blocking: false, -          showing_reblogs: false, +          showing_reblogs: true,            endorsed: false          }        } diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index 059d5237d..c2a12d3c7 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -10,11 +10,14 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do    alias Pleroma.Notification    alias Pleroma.Object    alias Pleroma.Repo +  alias Pleroma.ScheduledActivity    alias Pleroma.User    alias Pleroma.Web.ActivityPub.ActivityPub    alias Pleroma.Web.CommonAPI    alias Pleroma.Web.MastodonAPI.FilterView +  alias Pleroma.Web.OAuth.App    alias Pleroma.Web.OStatus +  alias Pleroma.Web.Push    alias Pleroma.Web.TwitterAPI.TwitterAPI    import Pleroma.Factory    import ExUnit.CaptureLog @@ -99,7 +102,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do      assert %{"content" => "cofe", "id" => id, "spoiler_text" => "2hu", "sensitive" => false} =               json_response(conn_one, 200) -    assert Repo.get(Activity, id) +    assert Activity.get_by_id(id)      conn_two =        conn @@ -138,7 +141,56 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do        |> post("/api/v1/statuses", %{"status" => "cofe", "sensitive" => true})      assert %{"content" => "cofe", "id" => id, "sensitive" => true} = json_response(conn, 200) -    assert Repo.get(Activity, id) +    assert Activity.get_by_id(id) +  end + +  test "posting a fake status", %{conn: conn} do +    user = insert(:user) + +    real_conn = +      conn +      |> assign(:user, user) +      |> post("/api/v1/statuses", %{ +        "status" => +          "\"Tenshi Eating a Corndog\" is a much discussed concept on /jp/. The significance of it is disputed, so I will focus on one core concept: the symbolism behind it" +      }) + +    real_status = json_response(real_conn, 200) + +    assert real_status +    assert Object.get_by_ap_id(real_status["uri"]) + +    real_status = +      real_status +      |> Map.put("id", nil) +      |> Map.put("url", nil) +      |> Map.put("uri", nil) +      |> Map.put("created_at", nil) +      |> Kernel.put_in(["pleroma", "conversation_id"], nil) + +    fake_conn = +      conn +      |> assign(:user, user) +      |> post("/api/v1/statuses", %{ +        "status" => +          "\"Tenshi Eating a Corndog\" is a much discussed concept on /jp/. The significance of it is disputed, so I will focus on one core concept: the symbolism behind it", +        "preview" => true +      }) + +    fake_status = json_response(fake_conn, 200) + +    assert fake_status +    refute Object.get_by_ap_id(fake_status["uri"]) + +    fake_status = +      fake_status +      |> Map.put("id", nil) +      |> Map.put("url", nil) +      |> Map.put("uri", nil) +      |> Map.put("created_at", nil) +      |> Kernel.put_in(["pleroma", "conversation_id"], nil) + +    assert real_status == fake_status    end    test "posting a status with OGP link preview", %{conn: conn} do @@ -153,7 +205,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do        })      assert %{"id" => id, "card" => %{"title" => "The Rock"}} = json_response(conn, 200) -    assert Repo.get(Activity, id) +    assert Activity.get_by_id(id)      Pleroma.Config.put([:rich_media, :enabled], false)    end @@ -168,7 +220,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do        |> post("api/v1/statuses", %{"status" => content, "visibility" => "direct"})      assert %{"id" => id, "visibility" => "direct"} = json_response(conn, 200) -    assert activity = Repo.get(Activity, id) +    assert activity = Activity.get_by_id(id)      assert activity.recipients == [user2.ap_id, user1.ap_id]      assert activity.data["to"] == [user2.ap_id]      assert activity.data["cc"] == [] @@ -287,10 +339,10 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do      assert %{"content" => "xD", "id" => id} = json_response(conn, 200) -    activity = Repo.get(Activity, id) +    activity = Activity.get_by_id(id)      assert activity.data["context"] == replied_to.data["context"] -    assert activity.data["object"]["inReplyToStatusId"] == replied_to.id +    assert Activity.get_in_reply_to_activity(activity).id == replied_to.id    end    test "posting a status with an invalid in_reply_to_id", %{conn: conn} do @@ -303,7 +355,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do      assert %{"content" => "xD", "id" => id} = json_response(conn, 200) -    activity = Repo.get(Activity, id) +    activity = Activity.get_by_id(id)      assert activity    end @@ -332,6 +384,53 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do      assert id == to_string(user.id)    end +  test "apps/verify_credentials", %{conn: conn} do +    token = insert(:oauth_token) + +    conn = +      conn +      |> assign(:user, token.user) +      |> assign(: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(conn, 200) +  end + +  test "creates an oauth app", %{conn: conn} do +    user = insert(:user) +    app_attrs = build(:oauth_app) + +    conn = +      conn +      |> assign(:user, user) +      |> post("/api/v1/apps", %{ +        client_name: app_attrs.client_name, +        redirect_uris: app_attrs.redirect_uris +      }) + +    [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(conn, 200) +  end +    test "get a status", %{conn: conn} do      activity = insert(:note_activity) @@ -346,7 +445,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do    describe "deleting a status" do      test "when you created it", %{conn: conn} do        activity = insert(:note_activity) -      author = User.get_by_ap_id(activity.data["actor"]) +      author = User.get_cached_by_ap_id(activity.data["actor"])        conn =          conn @@ -355,7 +454,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do        assert %{} = json_response(conn, 200) -      refute Repo.get(Activity, activity.id) +      refute Activity.get_by_id(activity.id)      end      test "when you didn't create it", %{conn: conn} do @@ -369,7 +468,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do        assert %{"error" => _} = json_response(conn, 403) -      assert Repo.get(Activity, activity.id) == activity +      assert Activity.get_by_id(activity.id) == activity      end      test "when you're an admin or moderator", %{conn: conn} do @@ -392,8 +491,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do        assert %{} = json_response(res_conn, 200) -      refute Repo.get(Activity, activity1.id) -      refute Repo.get(Activity, activity2.id) +      refute Activity.get_by_id(activity1.id) +      refute Activity.get_by_id(activity2.id)      end    end @@ -755,6 +854,148 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do        assert all = json_response(conn, 200)        assert all == []      end + +    test "paginates notifications using min_id, since_id, max_id, and limit", %{conn: conn} do +      user = insert(:user) +      other_user = insert(:user) + +      {:ok, activity1} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"}) +      {:ok, activity2} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"}) +      {:ok, activity3} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"}) +      {:ok, activity4} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"}) + +      notification1_id = Repo.get_by(Notification, activity_id: activity1.id).id |> to_string() +      notification2_id = Repo.get_by(Notification, activity_id: activity2.id).id |> to_string() +      notification3_id = Repo.get_by(Notification, activity_id: activity3.id).id |> to_string() +      notification4_id = Repo.get_by(Notification, activity_id: activity4.id).id |> to_string() + +      conn = +        conn +        |> assign(:user, user) + +      # min_id +      conn_res = +        conn +        |> get("/api/v1/notifications?limit=2&min_id=#{notification1_id}") + +      result = json_response(conn_res, 200) +      assert [%{"id" => ^notification3_id}, %{"id" => ^notification2_id}] = result + +      # since_id +      conn_res = +        conn +        |> get("/api/v1/notifications?limit=2&since_id=#{notification1_id}") + +      result = json_response(conn_res, 200) +      assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result + +      # max_id +      conn_res = +        conn +        |> get("/api/v1/notifications?limit=2&max_id=#{notification4_id}") + +      result = json_response(conn_res, 200) +      assert [%{"id" => ^notification3_id}, %{"id" => ^notification2_id}] = result +    end + +    test "filters notifications using exclude_types", %{conn: conn} do +      user = insert(:user) +      other_user = insert(:user) + +      {:ok, mention_activity} = CommonAPI.post(other_user, %{"status" => "hey @#{user.nickname}"}) +      {:ok, create_activity} = CommonAPI.post(user, %{"status" => "hey"}) +      {:ok, favorite_activity, _} = CommonAPI.favorite(create_activity.id, other_user) +      {:ok, reblog_activity, _} = CommonAPI.repeat(create_activity.id, other_user) +      {:ok, _, _, follow_activity} = CommonAPI.follow(other_user, user) + +      mention_notification_id = +        Repo.get_by(Notification, activity_id: mention_activity.id).id |> to_string() + +      favorite_notification_id = +        Repo.get_by(Notification, activity_id: favorite_activity.id).id |> to_string() + +      reblog_notification_id = +        Repo.get_by(Notification, activity_id: reblog_activity.id).id |> to_string() + +      follow_notification_id = +        Repo.get_by(Notification, activity_id: follow_activity.id).id |> to_string() + +      conn = +        conn +        |> assign(:user, user) + +      conn_res = +        get(conn, "/api/v1/notifications", %{exclude_types: ["mention", "favourite", "reblog"]}) + +      assert [%{"id" => ^follow_notification_id}] = json_response(conn_res, 200) + +      conn_res = +        get(conn, "/api/v1/notifications", %{exclude_types: ["favourite", "reblog", "follow"]}) + +      assert [%{"id" => ^mention_notification_id}] = json_response(conn_res, 200) + +      conn_res = +        get(conn, "/api/v1/notifications", %{exclude_types: ["reblog", "follow", "mention"]}) + +      assert [%{"id" => ^favorite_notification_id}] = json_response(conn_res, 200) + +      conn_res = +        get(conn, "/api/v1/notifications", %{exclude_types: ["follow", "mention", "favourite"]}) + +      assert [%{"id" => ^reblog_notification_id}] = json_response(conn_res, 200) +    end + +    test "destroy multiple", %{conn: conn} do +      user = insert(:user) +      other_user = insert(:user) + +      {:ok, activity1} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"}) +      {:ok, activity2} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"}) +      {:ok, activity3} = CommonAPI.post(user, %{"status" => "hi @#{other_user.nickname}"}) +      {:ok, activity4} = CommonAPI.post(user, %{"status" => "hi @#{other_user.nickname}"}) + +      notification1_id = Repo.get_by(Notification, activity_id: activity1.id).id |> to_string() +      notification2_id = Repo.get_by(Notification, activity_id: activity2.id).id |> to_string() +      notification3_id = Repo.get_by(Notification, activity_id: activity3.id).id |> to_string() +      notification4_id = Repo.get_by(Notification, activity_id: activity4.id).id |> to_string() + +      conn = +        conn +        |> assign(:user, user) + +      conn_res = +        conn +        |> get("/api/v1/notifications") + +      result = json_response(conn_res, 200) +      assert [%{"id" => ^notification2_id}, %{"id" => ^notification1_id}] = result + +      conn2 = +        conn +        |> assign(:user, other_user) + +      conn_res = +        conn2 +        |> get("/api/v1/notifications") + +      result = json_response(conn_res, 200) +      assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result + +      conn_destroy = +        conn +        |> delete("/api/v1/notifications/destroy_multiple", %{ +          "ids" => [notification1_id, notification2_id] +        }) + +      assert json_response(conn_destroy, 200) == %{} + +      conn_res = +        conn2 +        |> get("/api/v1/notifications") + +      result = json_response(conn_res, 200) +      assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result +    end    end    describe "reblogging" do @@ -767,8 +1008,47 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do          |> assign(:user, user)          |> post("/api/v1/statuses/#{activity.id}/reblog") -      assert %{"reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1}} = -               json_response(conn, 200) +      assert %{ +               "reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1}, +               "reblogged" => true +             } = json_response(conn, 200) + +      assert to_string(activity.id) == id +    end + +    test "reblogged status for another user", %{conn: conn} do +      activity = insert(:note_activity) +      user1 = insert(:user) +      user2 = insert(:user) +      user3 = insert(:user) +      CommonAPI.favorite(activity.id, user2) +      {:ok, _bookmark} = Pleroma.Bookmark.create(user2.id, activity.id) +      {:ok, reblog_activity1, _object} = CommonAPI.repeat(activity.id, user1) +      {:ok, _, _object} = CommonAPI.repeat(activity.id, user2) + +      conn_res = +        conn +        |> assign(:user, user3) +        |> get("/api/v1/statuses/#{reblog_activity1.id}") + +      assert %{ +               "reblog" => %{"id" => id, "reblogged" => false, "reblogs_count" => 2}, +               "reblogged" => false, +               "favourited" => false, +               "bookmarked" => false +             } = json_response(conn_res, 200) + +      conn_res = +        conn +        |> assign(:user, user2) +        |> get("/api/v1/statuses/#{reblog_activity1.id}") + +      assert %{ +               "reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 2}, +               "reblogged" => true, +               "favourited" => true, +               "bookmarked" => true +             } = json_response(conn_res, 200)        assert to_string(activity.id) == id      end @@ -887,7 +1167,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do      test "unimplemented pinned statuses feature", %{conn: conn} do        note = insert(:note_activity) -      user = User.get_by_ap_id(note.data["actor"]) +      user = User.get_cached_by_ap_id(note.data["actor"])        conn =          conn @@ -898,7 +1178,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do      test "gets an users media", %{conn: conn} do        note = insert(:note_activity) -      user = User.get_by_ap_id(note.data["actor"]) +      user = User.get_cached_by_ap_id(note.data["actor"])        file = %Plug.Upload{          content_type: "image/jpg", @@ -973,8 +1253,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do        {:ok, _activity} = ActivityPub.follow(other_user, user) -      user = Repo.get(User, user.id) -      other_user = Repo.get(User, other_user.id) +      user = User.get_cached_by_id(user.id) +      other_user = User.get_cached_by_id(other_user.id)        assert User.following?(other_user, user) == false @@ -993,8 +1273,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do        {:ok, _activity} = ActivityPub.follow(other_user, user) -      user = Repo.get(User, user.id) -      other_user = Repo.get(User, other_user.id) +      user = User.get_cached_by_id(user.id) +      other_user = User.get_cached_by_id(other_user.id)        assert User.following?(other_user, user) == false @@ -1006,8 +1286,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do        assert relationship = json_response(conn, 200)        assert to_string(other_user.id) == relationship["id"] -      user = Repo.get(User, user.id) -      other_user = Repo.get(User, other_user.id) +      user = User.get_cached_by_id(user.id) +      other_user = User.get_cached_by_id(other_user.id)        assert User.following?(other_user, user) == true      end @@ -1030,7 +1310,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do        {:ok, _activity} = ActivityPub.follow(other_user, user) -      user = Repo.get(User, user.id) +      user = User.get_cached_by_id(user.id)        conn =          build_conn() @@ -1040,8 +1320,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do        assert relationship = json_response(conn, 200)        assert to_string(other_user.id) == relationship["id"] -      user = Repo.get(User, user.id) -      other_user = Repo.get(User, other_user.id) +      user = User.get_cached_by_id(user.id) +      other_user = User.get_cached_by_id(other_user.id)        assert User.following?(other_user, user) == false      end @@ -1232,7 +1512,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do      assert id2 == follower2.id      assert [link_header] = get_resp_header(res_conn, "link") -    assert link_header =~ ~r/since_id=#{follower2.id}/ +    assert link_header =~ ~r/min_id=#{follower2.id}/      assert link_header =~ ~r/max_id=#{follower2.id}/    end @@ -1311,7 +1591,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do      assert id2 == following2.id      assert [link_header] = get_resp_header(res_conn, "link") -    assert link_header =~ ~r/since_id=#{following2.id}/ +    assert link_header =~ ~r/min_id=#{following2.id}/      assert link_header =~ ~r/max_id=#{following2.id}/    end @@ -1326,7 +1606,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do      assert %{"id" => _id, "following" => true} = json_response(conn, 200) -    user = Repo.get(User, user.id) +    user = User.get_cached_by_id(user.id)      conn =        build_conn() @@ -1335,7 +1615,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do      assert %{"id" => _id, "following" => false} = json_response(conn, 200) -    user = Repo.get(User, user.id) +    user = User.get_cached_by_id(user.id)      conn =        build_conn() @@ -1346,6 +1626,78 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do      assert id == to_string(other_user.id)    end +  test "following without reblogs" do +    follower = insert(:user) +    followed = insert(:user) +    other_user = insert(:user) + +    conn = +      build_conn() +      |> assign(:user, follower) +      |> post("/api/v1/accounts/#{followed.id}/follow?reblogs=false") + +    assert %{"showing_reblogs" => false} = json_response(conn, 200) + +    {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hey"}) +    {:ok, reblog, _} = CommonAPI.repeat(activity.id, followed) + +    conn = +      build_conn() +      |> assign(:user, User.get_cached_by_id(follower.id)) +      |> get("/api/v1/timelines/home") + +    assert [] == json_response(conn, 200) + +    conn = +      build_conn() +      |> assign(:user, follower) +      |> post("/api/v1/accounts/#{followed.id}/follow?reblogs=true") + +    assert %{"showing_reblogs" => true} = json_response(conn, 200) + +    conn = +      build_conn() +      |> assign(:user, User.get_cached_by_id(follower.id)) +      |> get("/api/v1/timelines/home") + +    expected_activity_id = reblog.id +    assert [%{"id" => ^expected_activity_id}] = json_response(conn, 200) +  end + +  test "following / unfollowing errors" do +    user = insert(:user) + +    conn = +      build_conn() +      |> assign(:user, user) + +    # self follow +    conn_res = post(conn, "/api/v1/accounts/#{user.id}/follow") +    assert %{"error" => "Record not found"} = json_response(conn_res, 404) + +    # self unfollow +    user = User.get_cached_by_id(user.id) +    conn_res = post(conn, "/api/v1/accounts/#{user.id}/unfollow") +    assert %{"error" => "Record not found"} = json_response(conn_res, 404) + +    # self follow via uri +    user = User.get_cached_by_id(user.id) +    conn_res = post(conn, "/api/v1/follows", %{"uri" => user.nickname}) +    assert %{"error" => "Record not found"} = json_response(conn_res, 404) + +    # follow non existing user +    conn_res = post(conn, "/api/v1/accounts/doesntexist/follow") +    assert %{"error" => "Record not found"} = json_response(conn_res, 404) + +    # follow non existing user via uri +    conn_res = post(conn, "/api/v1/follows", %{"uri" => "doesntexist"}) +    assert %{"error" => "Record not found"} = json_response(conn_res, 404) + +    # unfollow non existing user +    conn_res = post(conn, "/api/v1/accounts/doesntexist/unfollow") +    assert %{"error" => "Record not found"} = json_response(conn_res, 404) +  end +    test "muting / unmuting a user", %{conn: conn} do      user = insert(:user)      other_user = insert(:user) @@ -1357,7 +1709,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do      assert %{"id" => _id, "muting" => true} = json_response(conn, 200) -    user = Repo.get(User, user.id) +    user = User.get_cached_by_id(user.id)      conn =        build_conn() @@ -1367,6 +1719,25 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do      assert %{"id" => _id, "muting" => false} = json_response(conn, 200)    end +  test "subscribing / unsubscribing to a user", %{conn: conn} do +    user = insert(:user) +    subscription_target = insert(:user) + +    conn = +      conn +      |> assign(:user, user) +      |> post("/api/v1/pleroma/accounts/#{subscription_target.id}/subscribe") + +    assert %{"id" => _id, "subscribing" => true} = json_response(conn, 200) + +    conn = +      build_conn() +      |> assign(:user, user) +      |> post("/api/v1/pleroma/accounts/#{subscription_target.id}/unsubscribe") + +    assert %{"id" => _id, "subscribing" => false} = json_response(conn, 200) +  end +    test "getting a list of mutes", %{conn: conn} do      user = insert(:user)      other_user = insert(:user) @@ -1393,7 +1764,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do      assert %{"id" => _id, "blocking" => true} = json_response(conn, 200) -    user = Repo.get(User, user.id) +    user = User.get_cached_by_id(user.id)      conn =        build_conn() @@ -1552,7 +1923,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do      capture_log(fn ->        conn =          conn -        |> get("/api/v1/search", %{"q" => activity.data["object"]["id"]}) +        |> get("/api/v1/search", %{"q" => Object.normalize(activity).data["id"]})        assert results = json_response(conn, 200) @@ -1617,6 +1988,199 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do      assert [] = json_response(third_conn, 200)    end +  describe "getting favorites timeline of specified user" do +    setup do +      [current_user, user] = insert_pair(:user, %{info: %{hide_favorites: false}}) +      [current_user: current_user, user: user] +    end + +    test "returns list of statuses favorited by specified user", %{ +      conn: conn, +      current_user: current_user, +      user: user +    } do +      [activity | _] = insert_pair(:note_activity) +      CommonAPI.favorite(activity.id, user) + +      response = +        conn +        |> assign(:user, current_user) +        |> get("/api/v1/pleroma/accounts/#{user.id}/favourites") +        |> json_response(:ok) + +      [like] = response + +      assert length(response) == 1 +      assert like["id"] == activity.id +    end + +    test "returns favorites for specified user_id when user is not logged in", %{ +      conn: conn, +      user: user +    } do +      activity = insert(:note_activity) +      CommonAPI.favorite(activity.id, user) + +      response = +        conn +        |> get("/api/v1/pleroma/accounts/#{user.id}/favourites") +        |> json_response(:ok) + +      assert length(response) == 1 +    end + +    test "returns favorited DM only when user is logged in and he is one of recipients", %{ +      conn: conn, +      current_user: current_user, +      user: user +    } do +      {:ok, direct} = +        CommonAPI.post(current_user, %{ +          "status" => "Hi @#{user.nickname}!", +          "visibility" => "direct" +        }) + +      CommonAPI.favorite(direct.id, user) + +      response = +        conn +        |> assign(:user, current_user) +        |> get("/api/v1/pleroma/accounts/#{user.id}/favourites") +        |> json_response(:ok) + +      assert length(response) == 1 + +      anonymous_response = +        conn +        |> get("/api/v1/pleroma/accounts/#{user.id}/favourites") +        |> json_response(:ok) + +      assert length(anonymous_response) == 0 +    end + +    test "does not return others' favorited DM when user is not one of recipients", %{ +      conn: conn, +      current_user: current_user, +      user: user +    } do +      user_two = insert(:user) + +      {:ok, direct} = +        CommonAPI.post(user_two, %{ +          "status" => "Hi @#{user.nickname}!", +          "visibility" => "direct" +        }) + +      CommonAPI.favorite(direct.id, user) + +      response = +        conn +        |> assign(:user, current_user) +        |> get("/api/v1/pleroma/accounts/#{user.id}/favourites") +        |> json_response(:ok) + +      assert length(response) == 0 +    end + +    test "paginates favorites using since_id and max_id", %{ +      conn: conn, +      current_user: current_user, +      user: user +    } do +      activities = insert_list(10, :note_activity) + +      Enum.each(activities, fn activity -> +        CommonAPI.favorite(activity.id, user) +      end) + +      third_activity = Enum.at(activities, 2) +      seventh_activity = Enum.at(activities, 6) + +      response = +        conn +        |> assign(:user, current_user) +        |> get("/api/v1/pleroma/accounts/#{user.id}/favourites", %{ +          since_id: third_activity.id, +          max_id: seventh_activity.id +        }) +        |> json_response(:ok) + +      assert length(response) == 3 +      refute third_activity in response +      refute seventh_activity in response +    end + +    test "limits favorites using limit parameter", %{ +      conn: conn, +      current_user: current_user, +      user: user +    } do +      7 +      |> insert_list(:note_activity) +      |> Enum.each(fn activity -> +        CommonAPI.favorite(activity.id, user) +      end) + +      response = +        conn +        |> assign(:user, current_user) +        |> get("/api/v1/pleroma/accounts/#{user.id}/favourites", %{limit: "3"}) +        |> json_response(:ok) + +      assert length(response) == 3 +    end + +    test "returns empty response when user does not have any favorited statuses", %{ +      conn: conn, +      current_user: current_user, +      user: user +    } do +      response = +        conn +        |> assign(:user, current_user) +        |> get("/api/v1/pleroma/accounts/#{user.id}/favourites") +        |> json_response(:ok) + +      assert Enum.empty?(response) +    end + +    test "returns 404 error when specified user is not exist", %{conn: conn} do +      conn = get(conn, "/api/v1/pleroma/accounts/test/favourites") + +      assert json_response(conn, 404) == %{"error" => "Record not found"} +    end + +    test "returns 403 error when user has hidden own favorites", %{ +      conn: conn, +      current_user: current_user +    } do +      user = insert(:user, %{info: %{hide_favorites: true}}) +      activity = insert(:note_activity) +      CommonAPI.favorite(activity.id, user) + +      conn = +        conn +        |> assign(:user, current_user) +        |> get("/api/v1/pleroma/accounts/#{user.id}/favourites") + +      assert json_response(conn, 403) == %{"error" => "Can't get favorites"} +    end + +    test "hides favorites for new users by default", %{conn: conn, current_user: current_user} do +      user = insert(:user) +      activity = insert(:note_activity) +      CommonAPI.favorite(activity.id, user) + +      conn = +        conn +        |> assign(:user, current_user) +        |> get("/api/v1/pleroma/accounts/#{user.id}/favourites") + +      assert user.info.hide_favorites +      assert json_response(conn, 403) == %{"error" => "Can't get favorites"} +    end +  end +    describe "updating credentials" do      test "updates the user's bio", %{conn: conn} do        user = insert(:user) @@ -1632,7 +2196,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do        assert user = json_response(conn, 200)        assert user["note"] == -               ~s(I drink <a class="hashtag" data-tag="cofe" href="http://localhost:4001/tag/cofe">#cofe</a> with <span class="h-card"><a data-user=") <> +               ~s(I drink <a class="hashtag" data-tag="cofe" href="http://localhost:4001/tag/cofe" rel="tag">#cofe</a> with <span class="h-card"><a data-user=") <>                   user2.id <>                   ~s(" class="u-url mention" href=") <>                   user2.ap_id <> ~s(">@<span>) <> user2.nickname <> ~s(</span></a></span>) @@ -1650,6 +2214,78 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do        assert user["locked"] == true      end +    test "updates the user's default scope", %{conn: conn} do +      user = insert(:user) + +      conn = +        conn +        |> assign(:user, user) +        |> patch("/api/v1/accounts/update_credentials", %{default_scope: "cofe"}) + +      assert user = json_response(conn, 200) +      assert user["source"]["privacy"] == "cofe" +    end + +    test "updates the user's hide_followers status", %{conn: conn} do +      user = insert(:user) + +      conn = +        conn +        |> assign(:user, user) +        |> patch("/api/v1/accounts/update_credentials", %{hide_followers: "true"}) + +      assert user = json_response(conn, 200) +      assert user["pleroma"]["hide_followers"] == true +    end + +    test "updates the user's hide_follows status", %{conn: conn} do +      user = insert(:user) + +      conn = +        conn +        |> assign(:user, user) +        |> patch("/api/v1/accounts/update_credentials", %{hide_follows: "true"}) + +      assert user = json_response(conn, 200) +      assert user["pleroma"]["hide_follows"] == true +    end + +    test "updates the user's hide_favorites status", %{conn: conn} do +      user = insert(:user) + +      conn = +        conn +        |> assign(:user, user) +        |> patch("/api/v1/accounts/update_credentials", %{hide_favorites: "true"}) + +      assert user = json_response(conn, 200) +      assert user["pleroma"]["hide_favorites"] == true +    end + +    test "updates the user's show_role status", %{conn: conn} do +      user = insert(:user) + +      conn = +        conn +        |> assign(:user, user) +        |> patch("/api/v1/accounts/update_credentials", %{show_role: "false"}) + +      assert user = json_response(conn, 200) +      assert user["source"]["pleroma"]["show_role"] == false +    end + +    test "updates the user's no_rich_text status", %{conn: conn} do +      user = insert(:user) + +      conn = +        conn +        |> assign(:user, user) +        |> patch("/api/v1/accounts/update_credentials", %{no_rich_text: "true"}) + +      assert user = json_response(conn, 200) +      assert user["source"]["pleroma"]["no_rich_text"] == true +    end +      test "updates the user's name", %{conn: conn} do        user = insert(:user) @@ -1718,6 +2354,30 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do    end    test "get instance information", %{conn: conn} do +    conn = get(conn, "/api/v1/instance") +    assert result = json_response(conn, 200) + +    email = Pleroma.Config.get([:instance, :email]) +    # Note: not checking for "max_toot_chars" since it's optional +    assert %{ +             "uri" => _, +             "title" => _, +             "description" => _, +             "version" => _, +             "email" => from_config_email, +             "urls" => %{ +               "streaming_api" => _ +             }, +             "stats" => _, +             "thumbnail" => _, +             "languages" => _, +             "registrations" => _ +           } = result + +    assert email == from_config_email +  end + +  test "get instance stats", %{conn: conn} do      user = insert(:user, %{local: true})      user2 = insert(:user, %{local: true}) @@ -1729,7 +2389,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do      {:ok, _} = TwitterAPI.create_status(user, %{"status" => "cofe"})      # Stats should count users with missing or nil `info.deactivated` value -    user = Repo.get(User, user.id) +    user = User.get_cached_by_id(user.id)      info_change = Changeset.change(user.info, %{deactivated: nil})      {:ok, _user} = @@ -2101,8 +2761,372 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do        assert [link_header] = get_resp_header(conn, "link")        assert link_header =~ ~r/media_only=true/ -      assert link_header =~ ~r/since_id=#{notification2.id}/ +      assert link_header =~ ~r/min_id=#{notification2.id}/        assert link_header =~ ~r/max_id=#{notification1.id}/      end    end + +  test "accounts fetches correct account for nicknames beginning with numbers", %{conn: conn} do +    # Need to set an old-style integer ID to reproduce the problem +    # (these are no longer assigned to new accounts but were preserved +    # for existing accounts during the migration to flakeIDs) +    user_one = insert(:user, %{id: 1212}) +    user_two = insert(:user, %{nickname: "#{user_one.id}garbage"}) + +    resp_one = +      conn +      |> get("/api/v1/accounts/#{user_one.id}") + +    resp_two = +      conn +      |> get("/api/v1/accounts/#{user_two.nickname}") + +    resp_three = +      conn +      |> get("/api/v1/accounts/#{user_two.id}") + +    acc_one = json_response(resp_one, 200) +    acc_two = json_response(resp_two, 200) +    acc_three = json_response(resp_three, 200) +    refute acc_one == acc_two +    assert acc_two == acc_three +  end + +  describe "custom emoji" do +    test "with tags", %{conn: conn} do +      [emoji | _body] = +        conn +        |> get("/api/v1/custom_emojis") +        |> json_response(200) + +      assert Map.has_key?(emoji, "shortcode") +      assert Map.has_key?(emoji, "static_url") +      assert Map.has_key?(emoji, "tags") +      assert is_list(emoji["tags"]) +      assert Map.has_key?(emoji, "url") +      assert Map.has_key?(emoji, "visible_in_picker") +    end +  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 "does not redirect logged in users to the login page", %{conn: conn, path: path} do +      token = insert(:oauth_token) + +      conn = +        conn +        |> assign(:user, token.user) +        |> put_session(:oauth_token, 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 + +    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 "scheduled activities" do +    test "creates a scheduled activity", %{conn: conn} do +      user = insert(:user) +      scheduled_at = NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond) + +      conn = +        conn +        |> assign(:user, user) +        |> post("/api/v1/statuses", %{ +          "status" => "scheduled", +          "scheduled_at" => scheduled_at +        }) + +      assert %{"scheduled_at" => expected_scheduled_at} = json_response(conn, 200) +      assert expected_scheduled_at == Pleroma.Web.CommonAPI.Utils.to_masto_date(scheduled_at) +      assert [] == Repo.all(Activity) +    end + +    test "creates a scheduled activity with a media attachment", %{conn: conn} do +      user = insert(:user) +      scheduled_at = NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond) + +      file = %Plug.Upload{ +        content_type: "image/jpg", +        path: Path.absname("test/fixtures/image.jpg"), +        filename: "an_image.jpg" +      } + +      {:ok, upload} = ActivityPub.upload(file, actor: user.ap_id) + +      conn = +        conn +        |> assign(:user, user) +        |> post("/api/v1/statuses", %{ +          "media_ids" => [to_string(upload.id)], +          "status" => "scheduled", +          "scheduled_at" => scheduled_at +        }) + +      assert %{"media_attachments" => [media_attachment]} = json_response(conn, 200) +      assert %{"type" => "image"} = media_attachment +    end + +    test "skips the scheduling and creates the activity if scheduled_at is earlier than 5 minutes from now", +         %{conn: conn} do +      user = insert(:user) + +      scheduled_at = +        NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(5) - 1, :millisecond) + +      conn = +        conn +        |> assign(:user, user) +        |> post("/api/v1/statuses", %{ +          "status" => "not scheduled", +          "scheduled_at" => scheduled_at +        }) + +      assert %{"content" => "not scheduled"} = json_response(conn, 200) +      assert [] == Repo.all(ScheduledActivity) +    end + +    test "returns error when daily user limit is exceeded", %{conn: conn} do +      user = insert(:user) + +      today = +        NaiveDateTime.utc_now() +        |> NaiveDateTime.add(:timer.minutes(6), :millisecond) +        |> NaiveDateTime.to_iso8601() + +      attrs = %{params: %{}, scheduled_at: today} +      {:ok, _} = ScheduledActivity.create(user, attrs) +      {:ok, _} = ScheduledActivity.create(user, attrs) + +      conn = +        conn +        |> assign(:user, user) +        |> post("/api/v1/statuses", %{"status" => "scheduled", "scheduled_at" => today}) + +      assert %{"error" => "daily limit exceeded"} == json_response(conn, 422) +    end + +    test "returns error when total user limit is exceeded", %{conn: conn} do +      user = insert(:user) + +      today = +        NaiveDateTime.utc_now() +        |> NaiveDateTime.add(:timer.minutes(6), :millisecond) +        |> NaiveDateTime.to_iso8601() + +      tomorrow = +        NaiveDateTime.utc_now() +        |> NaiveDateTime.add(:timer.hours(36), :millisecond) +        |> NaiveDateTime.to_iso8601() + +      attrs = %{params: %{}, scheduled_at: today} +      {:ok, _} = ScheduledActivity.create(user, attrs) +      {:ok, _} = ScheduledActivity.create(user, attrs) +      {:ok, _} = ScheduledActivity.create(user, %{params: %{}, scheduled_at: tomorrow}) + +      conn = +        conn +        |> assign(:user, user) +        |> post("/api/v1/statuses", %{"status" => "scheduled", "scheduled_at" => tomorrow}) + +      assert %{"error" => "total limit exceeded"} == json_response(conn, 422) +    end + +    test "shows scheduled activities", %{conn: conn} do +      user = insert(:user) +      scheduled_activity_id1 = insert(:scheduled_activity, user: user).id |> to_string() +      scheduled_activity_id2 = insert(:scheduled_activity, user: user).id |> to_string() +      scheduled_activity_id3 = insert(:scheduled_activity, user: user).id |> to_string() +      scheduled_activity_id4 = insert(:scheduled_activity, user: user).id |> to_string() + +      conn = +        conn +        |> assign(:user, user) + +      # min_id +      conn_res = +        conn +        |> get("/api/v1/scheduled_statuses?limit=2&min_id=#{scheduled_activity_id1}") + +      result = json_response(conn_res, 200) +      assert [%{"id" => ^scheduled_activity_id3}, %{"id" => ^scheduled_activity_id2}] = result + +      # since_id +      conn_res = +        conn +        |> get("/api/v1/scheduled_statuses?limit=2&since_id=#{scheduled_activity_id1}") + +      result = json_response(conn_res, 200) +      assert [%{"id" => ^scheduled_activity_id4}, %{"id" => ^scheduled_activity_id3}] = result + +      # max_id +      conn_res = +        conn +        |> get("/api/v1/scheduled_statuses?limit=2&max_id=#{scheduled_activity_id4}") + +      result = json_response(conn_res, 200) +      assert [%{"id" => ^scheduled_activity_id3}, %{"id" => ^scheduled_activity_id2}] = result +    end + +    test "shows a scheduled activity", %{conn: conn} do +      user = insert(:user) +      scheduled_activity = insert(:scheduled_activity, user: user) + +      res_conn = +        conn +        |> assign(:user, user) +        |> get("/api/v1/scheduled_statuses/#{scheduled_activity.id}") + +      assert %{"id" => scheduled_activity_id} = json_response(res_conn, 200) +      assert scheduled_activity_id == scheduled_activity.id |> to_string() + +      res_conn = +        conn +        |> assign(:user, user) +        |> get("/api/v1/scheduled_statuses/404") + +      assert %{"error" => "Record not found"} = json_response(res_conn, 404) +    end + +    test "updates a scheduled activity", %{conn: conn} do +      user = insert(:user) +      scheduled_activity = insert(:scheduled_activity, user: user) + +      new_scheduled_at = +        NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond) + +      res_conn = +        conn +        |> assign(:user, user) +        |> put("/api/v1/scheduled_statuses/#{scheduled_activity.id}", %{ +          scheduled_at: new_scheduled_at +        }) + +      assert %{"scheduled_at" => expected_scheduled_at} = json_response(res_conn, 200) +      assert expected_scheduled_at == Pleroma.Web.CommonAPI.Utils.to_masto_date(new_scheduled_at) + +      res_conn = +        conn +        |> assign(:user, user) +        |> put("/api/v1/scheduled_statuses/404", %{scheduled_at: new_scheduled_at}) + +      assert %{"error" => "Record not found"} = json_response(res_conn, 404) +    end + +    test "deletes a scheduled activity", %{conn: conn} do +      user = insert(:user) +      scheduled_activity = insert(:scheduled_activity, user: user) + +      res_conn = +        conn +        |> assign(:user, user) +        |> delete("/api/v1/scheduled_statuses/#{scheduled_activity.id}") + +      assert %{} = json_response(res_conn, 200) +      assert nil == Repo.get(ScheduledActivity, scheduled_activity.id) + +      res_conn = +        conn +        |> assign(:user, user) +        |> delete("/api/v1/scheduled_statuses/#{scheduled_activity.id}") + +      assert %{"error" => "Record not found"} = json_response(res_conn, 404) +    end +  end + +  test "Repeated posts that are replies incorrectly have in_reply_to_id null", %{conn: conn} do +    user1 = insert(:user) +    user2 = insert(:user) +    user3 = insert(:user) + +    {:ok, replied_to} = TwitterAPI.create_status(user1, %{"status" => "cofe"}) + +    # Reply to status from another user +    conn1 = +      conn +      |> assign(:user, user2) +      |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => replied_to.id}) + +    assert %{"content" => "xD", "id" => id} = json_response(conn1, 200) + +    activity = Activity.get_by_id_with_object(id) + +    assert Object.normalize(activity).data["inReplyTo"] == Object.normalize(replied_to).data["id"] +    assert Activity.get_in_reply_to_activity(activity).id == replied_to.id + +    # Reblog from the third user +    conn2 = +      conn +      |> assign(:user, user3) +      |> post("/api/v1/statuses/#{activity.id}/reblog") + +    assert %{"reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1}} = +             json_response(conn2, 200) + +    assert to_string(activity.id) == id + +    # Getting third user status +    conn3 = +      conn +      |> assign(:user, user3) +      |> get("api/v1/timelines/home") + +    [reblogged_activity] = json_response(conn3, 200) + +    assert reblogged_activity["reblog"]["in_reply_to_id"] == replied_to.id + +    replied_to_user = User.get_by_ap_id(replied_to.data["actor"]) +    assert reblogged_activity["reblog"]["in_reply_to_account_id"] == replied_to_user.id +  end  end diff --git a/test/web/mastodon_api/notification_view_test.exs b/test/web/mastodon_api/notification_view_test.exs new file mode 100644 index 000000000..977ea1e87 --- /dev/null +++ b/test/web/mastodon_api/notification_view_test.exs @@ -0,0 +1,104 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do +  use Pleroma.DataCase + +  alias Pleroma.Activity +  alias Pleroma.Notification +  alias Pleroma.Repo +  alias Pleroma.User +  alias Pleroma.Web.CommonAPI +  alias Pleroma.Web.CommonAPI.Utils +  alias Pleroma.Web.MastodonAPI.AccountView +  alias Pleroma.Web.MastodonAPI.NotificationView +  alias Pleroma.Web.MastodonAPI.StatusView +  import Pleroma.Factory + +  test "Mention notification" do +    user = insert(:user) +    mentioned_user = insert(:user) +    {:ok, activity} = CommonAPI.post(user, %{"status" => "hey @#{mentioned_user.nickname}"}) +    {:ok, [notification]} = Notification.create_notifications(activity) +    user = User.get_cached_by_id(user.id) + +    expected = %{ +      id: to_string(notification.id), +      pleroma: %{is_seen: false}, +      type: "mention", +      account: AccountView.render("account.json", %{user: user, for: mentioned_user}), +      status: StatusView.render("status.json", %{activity: activity, for: mentioned_user}), +      created_at: Utils.to_masto_date(notification.inserted_at) +    } + +    result = +      NotificationView.render("index.json", %{notifications: [notification], for: mentioned_user}) + +    assert [expected] == result +  end + +  test "Favourite notification" do +    user = insert(:user) +    another_user = insert(:user) +    {:ok, create_activity} = CommonAPI.post(user, %{"status" => "hey"}) +    {:ok, favorite_activity, _object} = CommonAPI.favorite(create_activity.id, another_user) +    {:ok, [notification]} = Notification.create_notifications(favorite_activity) +    create_activity = Activity.get_by_id(create_activity.id) + +    expected = %{ +      id: to_string(notification.id), +      pleroma: %{is_seen: false}, +      type: "favourite", +      account: AccountView.render("account.json", %{user: another_user, for: user}), +      status: StatusView.render("status.json", %{activity: create_activity, for: user}), +      created_at: Utils.to_masto_date(notification.inserted_at) +    } + +    result = NotificationView.render("index.json", %{notifications: [notification], for: user}) + +    assert [expected] == result +  end + +  test "Reblog notification" do +    user = insert(:user) +    another_user = insert(:user) +    {:ok, create_activity} = CommonAPI.post(user, %{"status" => "hey"}) +    {:ok, reblog_activity, _object} = CommonAPI.repeat(create_activity.id, another_user) +    {:ok, [notification]} = Notification.create_notifications(reblog_activity) +    reblog_activity = Activity.get_by_id(create_activity.id) + +    expected = %{ +      id: to_string(notification.id), +      pleroma: %{is_seen: false}, +      type: "reblog", +      account: AccountView.render("account.json", %{user: another_user, for: user}), +      status: StatusView.render("status.json", %{activity: reblog_activity, for: user}), +      created_at: Utils.to_masto_date(notification.inserted_at) +    } + +    result = NotificationView.render("index.json", %{notifications: [notification], for: user}) + +    assert [expected] == result +  end + +  test "Follow notification" do +    follower = insert(:user) +    followed = insert(:user) +    {:ok, follower, followed, _activity} = CommonAPI.follow(follower, followed) +    notification = Notification |> Repo.one() |> Repo.preload(:activity) + +    expected = %{ +      id: to_string(notification.id), +      pleroma: %{is_seen: false}, +      type: "follow", +      account: AccountView.render("account.json", %{user: follower, for: followed}), +      created_at: Utils.to_masto_date(notification.inserted_at) +    } + +    result = +      NotificationView.render("index.json", %{notifications: [notification], for: followed}) + +    assert [expected] == result +  end +end diff --git a/test/web/mastodon_api/scheduled_activity_view_test.exs b/test/web/mastodon_api/scheduled_activity_view_test.exs new file mode 100644 index 000000000..ecbb855d4 --- /dev/null +++ b/test/web/mastodon_api/scheduled_activity_view_test.exs @@ -0,0 +1,68 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.ScheduledActivityViewTest do +  use Pleroma.DataCase +  alias Pleroma.ScheduledActivity +  alias Pleroma.Web.ActivityPub.ActivityPub +  alias Pleroma.Web.CommonAPI +  alias Pleroma.Web.CommonAPI.Utils +  alias Pleroma.Web.MastodonAPI.ScheduledActivityView +  alias Pleroma.Web.MastodonAPI.StatusView +  import Pleroma.Factory + +  test "A scheduled activity with a media attachment" do +    user = insert(:user) +    {:ok, activity} = CommonAPI.post(user, %{"status" => "hi"}) + +    scheduled_at = +      NaiveDateTime.utc_now() +      |> NaiveDateTime.add(:timer.minutes(10), :millisecond) +      |> NaiveDateTime.to_iso8601() + +    file = %Plug.Upload{ +      content_type: "image/jpg", +      path: Path.absname("test/fixtures/image.jpg"), +      filename: "an_image.jpg" +    } + +    {:ok, upload} = ActivityPub.upload(file, actor: user.ap_id) + +    attrs = %{ +      params: %{ +        "media_ids" => [upload.id], +        "status" => "hi", +        "sensitive" => true, +        "spoiler_text" => "spoiler", +        "visibility" => "unlisted", +        "in_reply_to_id" => to_string(activity.id) +      }, +      scheduled_at: scheduled_at +    } + +    {:ok, scheduled_activity} = ScheduledActivity.create(user, attrs) +    result = ScheduledActivityView.render("show.json", %{scheduled_activity: scheduled_activity}) + +    expected = %{ +      id: to_string(scheduled_activity.id), +      media_attachments: +        %{"media_ids" => [upload.id]} +        |> Utils.attachments_from_ids() +        |> Enum.map(&StatusView.render("attachment.json", %{attachment: &1})), +      params: %{ +        in_reply_to_id: to_string(activity.id), +        media_ids: [upload.id], +        poll: nil, +        scheduled_at: nil, +        sensitive: true, +        spoiler_text: "spoiler", +        text: "hi", +        visibility: "unlisted" +      }, +      scheduled_at: Utils.to_masto_date(scheduled_activity.scheduled_at) +    } + +    assert expected == result +  end +end diff --git a/test/web/mastodon_api/status_view_test.exs b/test/web/mastodon_api/status_view_test.exs index 3eec2cb5b..5fddc6c58 100644 --- a/test/web/mastodon_api/status_view_test.exs +++ b/test/web/mastodon_api/status_view_test.exs @@ -6,9 +6,12 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do    use Pleroma.DataCase    alias Pleroma.Activity +  alias Pleroma.Bookmark +  alias Pleroma.Object +  alias Pleroma.Repo    alias Pleroma.User -  alias Pleroma.Web.ActivityPub.ActivityPub    alias Pleroma.Web.CommonAPI +  alias Pleroma.Web.CommonAPI.Utils    alias Pleroma.Web.MastodonAPI.AccountView    alias Pleroma.Web.MastodonAPI.StatusView    alias Pleroma.Web.OStatus @@ -52,14 +55,14 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do    test "a note with null content" do      note = insert(:note_activity) +    note_object = Object.normalize(note.data["object"])      data = -      note.data -      |> put_in(["object", "content"], nil) +      note_object.data +      |> Map.put("content", nil) -    note = -      note -      |> Map.put(:data, data) +    Object.change(note_object, %{data: data}) +    |> Object.update_and_set_cache()      User.get_cached_by_ap_id(note.data["actor"]) @@ -72,6 +75,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do      note = insert(:note_activity)      user = User.get_cached_by_ap_id(note.data["actor"]) +    convo_id = Utils.context_to_conversation_id(note.data["object"]["context"]) +      status = StatusView.render("status.json", %{activity: note})      created_at = @@ -98,7 +103,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do        muted: false,        pinned: false,        sensitive: false, -      spoiler_text: note.data["object"]["summary"], +      spoiler_text: HtmlSanitizeEx.basic_html(note.data["object"]["summary"]),        visibility: "public",        media_attachments: [],        mentions: [], @@ -122,7 +127,11 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do          }        ],        pleroma: %{ -        local: true +        local: true, +        conversation_id: convo_id, +        in_reply_to_account_acct: nil, +        content: %{"text/plain" => HtmlSanitizeEx.strip_tags(note.data["object"]["content"])}, +        spoiler_text: %{"text/plain" => HtmlSanitizeEx.strip_tags(note.data["object"]["summary"])}        }      } @@ -145,6 +154,25 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do      assert status.muted == true    end +  test "tells if the status is bookmarked" do +    user = insert(:user) + +    {:ok, activity} = CommonAPI.post(user, %{"status" => "Cute girls doing cute things"}) +    status = StatusView.render("status.json", %{activity: activity}) + +    assert status.bookmarked == false + +    status = StatusView.render("status.json", %{activity: activity, for: user}) + +    assert status.bookmarked == false + +    {:ok, _bookmark} = Bookmark.create(user.id, activity.id) + +    status = StatusView.render("status.json", %{activity: activity, for: user}) + +    assert status.bookmarked == true +  end +    test "a reply" do      note = insert(:note_activity)      user = insert(:user) @@ -171,7 +199,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do      status = StatusView.render("status.json", %{activity: activity}) -    actor = Repo.get_by(User, ap_id: activity.actor) +    actor = User.get_cached_by_ap_id(activity.actor)      assert status.mentions ==               Enum.map([user, actor], fn u -> AccountView.render("mention.json", %{user: u}) end) @@ -196,7 +224,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do        remote_url: "someurl",        preview_url: "someurl",        text_url: "someurl", -      description: nil +      description: nil, +      pleroma: %{mime_type: "image/png"}      }      assert expected == StatusView.render("attachment.json", %{attachment: object}) @@ -223,7 +252,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do      user = insert(:user)      {:ok, object} = -      ActivityPub.fetch_object_from_id( +      Pleroma.Object.Fetcher.fetch_object_from_id(          "https://peertube.moe/videos/watch/df5f464b-be8d-46fb-ad81-2d4c2d1630e3"        ) diff --git a/test/web/metadata/rel_me_test.exs b/test/web/metadata/rel_me_test.exs new file mode 100644 index 000000000..f66bf7834 --- /dev/null +++ b/test/web/metadata/rel_me_test.exs @@ -0,0 +1,18 @@ +defmodule Pleroma.Web.Metadata.Providers.RelMeTest do +  use Pleroma.DataCase +  import Pleroma.Factory +  alias Pleroma.Web.Metadata.Providers.RelMe + +  test "it renders all links with rel='me' from user bio" do +    bio = +      ~s(<a href="https://some-link.com">https://some-link.com</a> <a rel="me" href="https://another-link.com">https://another-link.com</a> +    <link href="http://some.com"> <link rel="me" href="http://some3.com>") + +    user = insert(:user, %{bio: bio}) + +    assert RelMe.build_tags(%{user: user}) == [ +             {:link, [rel: "me", href: "http://some3.com>"], []}, +             {:link, [rel: "me", href: "https://another-link.com"], []} +           ] +  end +end diff --git a/test/web/node_info_test.exs b/test/web/node_info_test.exs index 038feecc1..2fc42b7cc 100644 --- a/test/web/node_info_test.exs +++ b/test/web/node_info_test.exs @@ -108,4 +108,27 @@ defmodule Pleroma.Web.NodeInfoTest do      assert result = json_response(conn, 200)      assert Pleroma.Application.repository() == result["software"]["repository"]    end + +  test "it returns the safe_dm_mentions feature if enabled", %{conn: conn} do +    option = Pleroma.Config.get([:instance, :safe_dm_mentions]) +    Pleroma.Config.put([:instance, :safe_dm_mentions], true) + +    response = +      conn +      |> get("/nodeinfo/2.1.json") +      |> json_response(:ok) + +    assert "safe_dm_mentions" in response["metadata"]["features"] + +    Pleroma.Config.put([:instance, :safe_dm_mentions], false) + +    response = +      conn +      |> get("/nodeinfo/2.1.json") +      |> json_response(:ok) + +    refute "safe_dm_mentions" in response["metadata"]["features"] + +    Pleroma.Config.put([:instance, :safe_dm_mentions], option) +  end  end diff --git a/test/web/oauth/ldap_authorization_test.exs b/test/web/oauth/ldap_authorization_test.exs new file mode 100644 index 000000000..0eb191c76 --- /dev/null +++ b/test/web/oauth/ldap_authorization_test.exs @@ -0,0 +1,195 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.OAuth.LDAPAuthorizationTest do +  use Pleroma.Web.ConnCase +  alias Pleroma.Repo +  alias Pleroma.Web.OAuth.Token +  import Pleroma.Factory +  import ExUnit.CaptureLog +  import Mock + +  @skip if !Code.ensure_loaded?(:eldap), do: :skip + +  setup_all do +    ldap_authenticator = +      Pleroma.Config.get(Pleroma.Web.Auth.Authenticator, Pleroma.Web.Auth.PleromaAuthenticator) + +    ldap_enabled = Pleroma.Config.get([:ldap, :enabled]) + +    on_exit(fn -> +      Pleroma.Config.put(Pleroma.Web.Auth.Authenticator, ldap_authenticator) +      Pleroma.Config.put([:ldap, :enabled], ldap_enabled) +    end) + +    Pleroma.Config.put(Pleroma.Web.Auth.Authenticator, Pleroma.Web.Auth.LDAPAuthenticator) +    Pleroma.Config.put([:ldap, :enabled], true) + +    :ok +  end + +  @tag @skip +  test "authorizes the existing user using LDAP credentials" do +    password = "testpassword" +    user = insert(:user, password_hash: Comeonin.Pbkdf2.hashpwsalt(password)) +    app = insert(:oauth_app, scopes: ["read", "write"]) + +    host = Pleroma.Config.get([:ldap, :host]) |> to_charlist +    port = Pleroma.Config.get([:ldap, :port]) + +    with_mocks [ +      {:eldap, [], +       [ +         open: fn [^host], [{:port, ^port}, {:ssl, false} | _] -> {:ok, self()} end, +         simple_bind: fn _connection, _dn, ^password -> :ok end, +         close: fn _connection -> +           send(self(), :close_connection) +           :ok +         end +       ]} +    ] do +      conn = +        build_conn() +        |> post("/oauth/token", %{ +          "grant_type" => "password", +          "username" => user.nickname, +          "password" => password, +          "client_id" => app.client_id, +          "client_secret" => app.client_secret +        }) + +      assert %{"access_token" => token} = json_response(conn, 200) + +      token = Repo.get_by(Token, token: token) + +      assert token.user_id == user.id +      assert_received :close_connection +    end +  end + +  @tag @skip +  test "creates a new user after successful LDAP authorization" do +    password = "testpassword" +    user = build(:user) +    app = insert(:oauth_app, scopes: ["read", "write"]) + +    host = Pleroma.Config.get([:ldap, :host]) |> to_charlist +    port = Pleroma.Config.get([:ldap, :port]) + +    with_mocks [ +      {:eldap, [], +       [ +         open: fn [^host], [{:port, ^port}, {:ssl, false} | _] -> {:ok, self()} end, +         simple_bind: fn _connection, _dn, ^password -> :ok end, +         equalityMatch: fn _type, _value -> :ok end, +         wholeSubtree: fn -> :ok end, +         search: fn _connection, _options -> +           {:ok, +            {:eldap_search_result, [{:eldap_entry, '', [{'mail', [to_charlist(user.email)]}]}], +             []}} +         end, +         close: fn _connection -> +           send(self(), :close_connection) +           :ok +         end +       ]} +    ] do +      conn = +        build_conn() +        |> post("/oauth/token", %{ +          "grant_type" => "password", +          "username" => user.nickname, +          "password" => password, +          "client_id" => app.client_id, +          "client_secret" => app.client_secret +        }) + +      assert %{"access_token" => token} = json_response(conn, 200) + +      token = Repo.get_by(Token, token: token) |> Repo.preload(:user) + +      assert token.user.nickname == user.nickname +      assert_received :close_connection +    end +  end + +  @tag @skip +  test "falls back to the default authorization when LDAP is unavailable" do +    password = "testpassword" +    user = insert(:user, password_hash: Comeonin.Pbkdf2.hashpwsalt(password)) +    app = insert(:oauth_app, scopes: ["read", "write"]) + +    host = Pleroma.Config.get([:ldap, :host]) |> to_charlist +    port = Pleroma.Config.get([:ldap, :port]) + +    with_mocks [ +      {:eldap, [], +       [ +         open: fn [^host], [{:port, ^port}, {:ssl, false} | _] -> {:error, 'connect failed'} end, +         simple_bind: fn _connection, _dn, ^password -> :ok end, +         close: fn _connection -> +           send(self(), :close_connection) +           :ok +         end +       ]} +    ] do +      log = +        capture_log(fn -> +          conn = +            build_conn() +            |> post("/oauth/token", %{ +              "grant_type" => "password", +              "username" => user.nickname, +              "password" => password, +              "client_id" => app.client_id, +              "client_secret" => app.client_secret +            }) + +          assert %{"access_token" => token} = json_response(conn, 200) + +          token = Repo.get_by(Token, token: token) + +          assert token.user_id == user.id +        end) + +      assert log =~ "Could not open LDAP connection: 'connect failed'" +      refute_received :close_connection +    end +  end + +  @tag @skip +  test "disallow authorization for wrong LDAP credentials" do +    password = "testpassword" +    user = insert(:user, password_hash: Comeonin.Pbkdf2.hashpwsalt(password)) +    app = insert(:oauth_app, scopes: ["read", "write"]) + +    host = Pleroma.Config.get([:ldap, :host]) |> to_charlist +    port = Pleroma.Config.get([:ldap, :port]) + +    with_mocks [ +      {:eldap, [], +       [ +         open: fn [^host], [{:port, ^port}, {:ssl, false} | _] -> {:ok, self()} end, +         simple_bind: fn _connection, _dn, ^password -> {:error, :invalidCredentials} end, +         close: fn _connection -> +           send(self(), :close_connection) +           :ok +         end +       ]} +    ] do +      conn = +        build_conn() +        |> post("/oauth/token", %{ +          "grant_type" => "password", +          "username" => user.nickname, +          "password" => password, +          "client_id" => app.client_id, +          "client_secret" => app.client_secret +        }) + +      assert %{"error" => "Invalid credentials"} = json_response(conn, 400) +      assert_received :close_connection +    end +  end +end diff --git a/test/web/oauth/oauth_controller_test.exs b/test/web/oauth/oauth_controller_test.exs index ed94416ff..6e96537ec 100644 --- a/test/web/oauth/oauth_controller_test.exs +++ b/test/web/oauth/oauth_controller_test.exs @@ -5,265 +5,713 @@  defmodule Pleroma.Web.OAuth.OAuthControllerTest do    use Pleroma.Web.ConnCase    import Pleroma.Factory +  import Mock +  alias Pleroma.Registration    alias Pleroma.Repo    alias Pleroma.Web.OAuth.Authorization    alias Pleroma.Web.OAuth.Token -  test "redirects with oauth authorization" do -    user = insert(:user) -    app = insert(:oauth_app, scopes: ["read", "write", "follow"]) +  @session_opts [ +    store: :cookie, +    key: "_test", +    signing_salt: "cooldude" +  ] + +  describe "in OAuth consumer mode, " do +    setup do +      oauth_consumer_strategies_path = [:auth, :oauth_consumer_strategies] +      oauth_consumer_strategies = Pleroma.Config.get(oauth_consumer_strategies_path) +      Pleroma.Config.put(oauth_consumer_strategies_path, ~w(twitter facebook)) + +      on_exit(fn -> +        Pleroma.Config.put(oauth_consumer_strategies_path, oauth_consumer_strategies) +      end) + +      [ +        app: insert(:oauth_app), +        conn: +          build_conn() +          |> Plug.Session.call(Plug.Session.init(@session_opts)) +          |> fetch_session() +      ] +    end -    conn = -      build_conn() -      |> post("/oauth/authorize", %{ -        "authorization" => %{ -          "name" => user.nickname, -          "password" => "test", -          "client_id" => app.client_id, -          "redirect_uri" => app.redirect_uris, -          "scope" => "read write", -          "state" => "statepassed" -        } -      }) +    test "GET /oauth/authorize renders auth forms, including OAuth consumer form", %{ +      app: app, +      conn: conn +    } do +      conn = +        get( +          conn, +          "/oauth/authorize", +          %{ +            "response_type" => "code", +            "client_id" => app.client_id, +            "redirect_uri" => app.redirect_uris, +            "scope" => "read" +          } +        ) + +      assert response = html_response(conn, 200) +      assert response =~ "Sign in with Twitter" +      assert response =~ o_auth_path(conn, :prepare_request) +    end -    target = redirected_to(conn) -    assert target =~ app.redirect_uris +    test "GET /oauth/prepare_request encodes parameters as `state` and redirects", %{ +      app: app, +      conn: conn +    } do +      conn = +        get( +          conn, +          "/oauth/prepare_request", +          %{ +            "provider" => "twitter", +            "authorization" => %{ +              "scope" => "read follow", +              "client_id" => app.client_id, +              "redirect_uri" => app.redirect_uris, +              "state" => "a_state" +            } +          } +        ) + +      assert response = 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) + +      expected_client_id = app.client_id +      expected_redirect_uri = app.redirect_uris + +      assert %{ +               "scope" => "read follow", +               "client_id" => ^expected_client_id, +               "redirect_uri" => ^expected_redirect_uri, +               "state" => "a_state" +             } = state_components +    end -    query = URI.parse(target).query |> URI.query_decoder() |> Map.new() +    test "with user-bound registration, GET /oauth/<provider>/callback redirects to `redirect_uri` with `code`", +         %{app: app, conn: conn} do +      registration = insert(:registration) -    assert %{"state" => "statepassed", "code" => code} = query -    auth = Repo.get_by(Authorization, token: code) -    assert auth -    assert auth.scopes == ["read", "write"] -  end +      state_params = %{ +        "scope" => Enum.join(app.scopes, " "), +        "client_id" => app.client_id, +        "redirect_uri" => app.redirect_uris, +        "state" => "" +      } + +      with_mock Pleroma.Web.Auth.Authenticator, +        get_registration: fn _ -> {:ok, registration} end do +        conn = +          get( +            conn, +            "/oauth/twitter/callback", +            %{ +              "oauth_token" => "G-5a3AAAAAAAwMH9AAABaektfSM", +              "oauth_verifier" => "QZl8vUqNvXMTKpdmUnGejJxuHG75WWWs", +              "provider" => "twitter", +              "state" => Poison.encode!(state_params) +            } +          ) + +        assert response = html_response(conn, 302) +        assert redirected_to(conn) =~ ~r/#{app.redirect_uris}\?code=.+/ +      end +    end -  test "returns 401 for wrong credentials", %{conn: conn} do -    user = insert(:user) -    app = insert(:oauth_app) +    test "with user-unbound registration, GET /oauth/<provider>/callback renders registration_details page", +         %{app: app, conn: conn} do +      registration = insert(:registration, user: nil) -    result = -      conn -      |> post("/oauth/authorize", %{ -        "authorization" => %{ -          "name" => user.nickname, -          "password" => "wrong", -          "client_id" => app.client_id, -          "redirect_uri" => app.redirect_uris, -          "state" => "statepassed", -          "scope" => Enum.join(app.scopes, " ") -        } -      }) -      |> html_response(:unauthorized) +      state_params = %{ +        "scope" => "read write", +        "client_id" => app.client_id, +        "redirect_uri" => app.redirect_uris, +        "state" => "a_state" +      } + +      with_mock Pleroma.Web.Auth.Authenticator, +        get_registration: fn _ -> {:ok, registration} end do +        conn = +          get( +            conn, +            "/oauth/twitter/callback", +            %{ +              "oauth_token" => "G-5a3AAAAAAAwMH9AAABaektfSM", +              "oauth_verifier" => "QZl8vUqNvXMTKpdmUnGejJxuHG75WWWs", +              "provider" => "twitter", +              "state" => Poison.encode!(state_params) +            } +          ) + +        assert response = html_response(conn, 200) +        assert response =~ ~r/name="op" type="submit" value="register"/ +        assert response =~ ~r/name="op" type="submit" value="connect"/ +        assert response =~ Registration.email(registration) +        assert response =~ Registration.nickname(registration) +      end +    end -    # Keep the details -    assert result =~ app.client_id -    assert result =~ app.redirect_uris +    test "on authentication error, GET /oauth/<provider>/callback redirects to `redirect_uri`", %{ +      app: app, +      conn: conn +    } do +      state_params = %{ +        "scope" => Enum.join(app.scopes, " "), +        "client_id" => app.client_id, +        "redirect_uri" => app.redirect_uris, +        "state" => "" +      } + +      conn = +        conn +        |> assign(:ueberauth_failure, %{errors: [%{message: "(error description)"}]}) +        |> get( +          "/oauth/twitter/callback", +          %{ +            "oauth_token" => "G-5a3AAAAAAAwMH9AAABaektfSM", +            "oauth_verifier" => "QZl8vUqNvXMTKpdmUnGejJxuHG75WWWs", +            "provider" => "twitter", +            "state" => Poison.encode!(state_params) +          } +        ) + +      assert response = html_response(conn, 302) +      assert redirected_to(conn) == app.redirect_uris +      assert get_flash(conn, :error) == "Failed to authenticate: (error description)." +    end -    # Error message -    assert result =~ "Invalid Username/Password" -  end +    test "GET /oauth/registration_details renders registration details form", %{ +      app: app, +      conn: conn +    } do +      conn = +        get( +          conn, +          "/oauth/registration_details", +          %{ +            "authorization" => %{ +              "scopes" => app.scopes, +              "client_id" => app.client_id, +              "redirect_uri" => app.redirect_uris, +              "state" => "a_state", +              "nickname" => nil, +              "email" => "john@doe.com" +            } +          } +        ) + +      assert response = html_response(conn, 200) +      assert response =~ ~r/name="op" type="submit" value="register"/ +      assert response =~ ~r/name="op" type="submit" value="connect"/ +    end -  test "returns 401 for missing scopes", %{conn: conn} do -    user = insert(:user) -    app = insert(:oauth_app) +    test "with valid params, POST /oauth/register?op=register redirects to `redirect_uri` with `code`", +         %{ +           app: app, +           conn: conn +         } do +      registration = insert(:registration, user: nil, info: %{"nickname" => nil, "email" => nil}) + +      conn = +        conn +        |> put_session(:registration_id, registration.id) +        |> post( +          "/oauth/register", +          %{ +            "op" => "register", +            "authorization" => %{ +              "scopes" => app.scopes, +              "client_id" => app.client_id, +              "redirect_uri" => app.redirect_uris, +              "state" => "a_state", +              "nickname" => "availablenick", +              "email" => "available@email.com" +            } +          } +        ) + +      assert response = html_response(conn, 302) +      assert redirected_to(conn) =~ ~r/#{app.redirect_uris}\?code=.+/ +    end + +    test "with invalid params, POST /oauth/register?op=register renders registration_details page", +         %{ +           app: app, +           conn: conn +         } do +      another_user = insert(:user) +      registration = insert(:registration, user: nil, info: %{"nickname" => nil, "email" => nil}) -    result = -      conn -      |> post("/oauth/authorize", %{ +      params = %{ +        "op" => "register",          "authorization" => %{ -          "name" => user.nickname, -          "password" => "test", +          "scopes" => app.scopes,            "client_id" => app.client_id,            "redirect_uri" => app.redirect_uris, -          "state" => "statepassed", -          "scope" => "" +          "state" => "a_state", +          "nickname" => "availablenickname", +          "email" => "available@email.com"          } -      }) -      |> html_response(:unauthorized) +      } -    # Keep the details -    assert result =~ app.client_id -    assert result =~ app.redirect_uris +      for {bad_param, bad_param_value} <- +            [{"nickname", another_user.nickname}, {"email", another_user.email}] do +        bad_registration_attrs = %{ +          "authorization" => Map.put(params["authorization"], bad_param, bad_param_value) +        } -    # Error message -    assert result =~ "Permissions not specified" -  end +        bad_params = Map.merge(params, bad_registration_attrs) -  test "returns 401 for scopes beyond app scopes", %{conn: conn} do -    user = insert(:user) -    app = insert(:oauth_app, scopes: ["read", "write"]) +        conn = +          conn +          |> put_session(:registration_id, registration.id) +          |> post("/oauth/register", bad_params) -    result = -      conn -      |> post("/oauth/authorize", %{ +        assert html_response(conn, 403) =~ ~r/name="op" type="submit" value="register"/ +        assert get_flash(conn, :error) == "Error: #{bad_param} has already been taken." +      end +    end + +    test "with valid params, POST /oauth/register?op=connect redirects to `redirect_uri` with `code`", +         %{ +           app: app, +           conn: conn +         } do +      user = insert(:user, password_hash: Comeonin.Pbkdf2.hashpwsalt("testpassword")) +      registration = insert(:registration, user: nil) + +      conn = +        conn +        |> put_session(:registration_id, registration.id) +        |> post( +          "/oauth/register", +          %{ +            "op" => "connect", +            "authorization" => %{ +              "scopes" => app.scopes, +              "client_id" => app.client_id, +              "redirect_uri" => app.redirect_uris, +              "state" => "a_state", +              "name" => user.nickname, +              "password" => "testpassword" +            } +          } +        ) + +      assert response = html_response(conn, 302) +      assert redirected_to(conn) =~ ~r/#{app.redirect_uris}\?code=.+/ +    end + +    test "with invalid params, POST /oauth/register?op=connect renders registration_details page", +         %{ +           app: app, +           conn: conn +         } do +      user = insert(:user) +      registration = insert(:registration, user: nil) + +      params = %{ +        "op" => "connect",          "authorization" => %{ -          "name" => user.nickname, -          "password" => "test", +          "scopes" => app.scopes,            "client_id" => app.client_id,            "redirect_uri" => app.redirect_uris, -          "state" => "statepassed", -          "scope" => "read write follow" +          "state" => "a_state", +          "name" => user.nickname, +          "password" => "wrong password"          } -      }) -      |> html_response(:unauthorized) +      } -    # Keep the details -    assert result =~ app.client_id -    assert result =~ app.redirect_uris +      conn = +        conn +        |> put_session(:registration_id, registration.id) +        |> post("/oauth/register", params) -    # Error message -    assert result =~ "Permissions not specified" +      assert html_response(conn, 401) =~ ~r/name="op" type="submit" value="connect"/ +      assert get_flash(conn, :error) == "Invalid Username/Password" +    end    end -  test "issues a token for an all-body request" do -    user = insert(:user) -    app = insert(:oauth_app, scopes: ["read", "write"]) +  describe "GET /oauth/authorize" do +    setup do +      [ +        app: insert(:oauth_app, redirect_uris: "https://redirect.url"), +        conn: +          build_conn() +          |> Plug.Session.call(Plug.Session.init(@session_opts)) +          |> fetch_session() +      ] +    end -    {:ok, auth} = Authorization.create_authorization(app, user, ["write"]) +    test "renders authentication page", %{app: app, conn: conn} do +      conn = +        get( +          conn, +          "/oauth/authorize", +          %{ +            "response_type" => "code", +            "client_id" => app.client_id, +            "redirect_uri" => app.redirect_uris, +            "scope" => "read" +          } +        ) + +      assert html_response(conn, 200) =~ ~s(type="submit") +    end -    conn = -      build_conn() -      |> post("/oauth/token", %{ -        "grant_type" => "authorization_code", -        "code" => auth.token, -        "redirect_uri" => app.redirect_uris, -        "client_id" => app.client_id, -        "client_secret" => app.client_secret -      }) +    test "properly handles internal calls with `authorization`-wrapped params", %{ +      app: app, +      conn: conn +    } do +      conn = +        get( +          conn, +          "/oauth/authorize", +          %{ +            "authorization" => %{ +              "response_type" => "code", +              "client_id" => app.client_id, +              "redirect_uri" => app.redirect_uris, +              "scope" => "read" +            } +          } +        ) + +      assert html_response(conn, 200) =~ ~s(type="submit") +    end -    assert %{"access_token" => token} = json_response(conn, 200) +    test "renders authentication page if user is already authenticated but `force_login` is tru-ish", +         %{app: app, conn: conn} do +      token = insert(:oauth_token, app_id: app.id) + +      conn = +        conn +        |> put_session(:oauth_token, token.token) +        |> get( +          "/oauth/authorize", +          %{ +            "response_type" => "code", +            "client_id" => app.client_id, +            "redirect_uri" => app.redirect_uris, +            "scope" => "read", +            "force_login" => "true" +          } +        ) + +      assert html_response(conn, 200) =~ ~s(type="submit") +    end -    token = Repo.get_by(Token, token: token) -    assert token -    assert token.scopes == auth.scopes +    test "redirects to app if user is already authenticated", %{app: app, conn: conn} do +      token = insert(:oauth_token, app_id: app.id) + +      conn = +        conn +        |> put_session(:oauth_token, token.token) +        |> get( +          "/oauth/authorize", +          %{ +            "response_type" => "code", +            "client_id" => app.client_id, +            "redirect_uri" => app.redirect_uris, +            "scope" => "read" +          } +        ) + +      assert redirected_to(conn) == "https://redirect.url" +    end    end -  test "issues a token for `password` grant_type with valid credentials, with full permissions by default" do -    password = "testpassword" -    user = insert(:user, password_hash: Comeonin.Pbkdf2.hashpwsalt(password)) - -    app = insert(:oauth_app, scopes: ["read", "write"]) +  describe "POST /oauth/authorize" do +    test "redirects with oauth authorization" do +      user = insert(:user) +      app = insert(:oauth_app, scopes: ["read", "write", "follow"]) + +      conn = +        build_conn() +        |> post("/oauth/authorize", %{ +          "authorization" => %{ +            "name" => user.nickname, +            "password" => "test", +            "client_id" => app.client_id, +            "redirect_uri" => app.redirect_uris, +            "scope" => "read write", +            "state" => "statepassed" +          } +        }) + +      target = redirected_to(conn) +      assert target =~ app.redirect_uris + +      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 == ["read", "write"] +    end -    # Note: "scope" param is intentionally omitted -    conn = -      build_conn() -      |> post("/oauth/token", %{ -        "grant_type" => "password", -        "username" => user.nickname, -        "password" => password, -        "client_id" => app.client_id, -        "client_secret" => app.client_secret -      }) +    test "returns 401 for wrong credentials", %{conn: conn} do +      user = insert(:user) +      app = insert(:oauth_app) + +      result = +        conn +        |> post("/oauth/authorize", %{ +          "authorization" => %{ +            "name" => user.nickname, +            "password" => "wrong", +            "client_id" => app.client_id, +            "redirect_uri" => app.redirect_uris, +            "state" => "statepassed", +            "scope" => Enum.join(app.scopes, " ") +          } +        }) +        |> html_response(:unauthorized) + +      # Keep the details +      assert result =~ app.client_id +      assert result =~ app.redirect_uris + +      # Error message +      assert result =~ "Invalid Username/Password" +    end -    assert %{"access_token" => token} = json_response(conn, 200) +    test "returns 401 for missing scopes", %{conn: conn} do +      user = insert(:user) +      app = insert(:oauth_app) + +      result = +        conn +        |> post("/oauth/authorize", %{ +          "authorization" => %{ +            "name" => user.nickname, +            "password" => "test", +            "client_id" => app.client_id, +            "redirect_uri" => app.redirect_uris, +            "state" => "statepassed", +            "scope" => "" +          } +        }) +        |> html_response(:unauthorized) + +      # Keep the details +      assert result =~ app.client_id +      assert result =~ app.redirect_uris + +      # Error message +      assert result =~ "This action is outside the authorized scopes" +    end -    token = Repo.get_by(Token, token: token) -    assert token -    assert token.scopes == app.scopes +    test "returns 401 for scopes beyond app scopes", %{conn: conn} do +      user = insert(:user) +      app = insert(:oauth_app, scopes: ["read", "write"]) + +      result = +        conn +        |> post("/oauth/authorize", %{ +          "authorization" => %{ +            "name" => user.nickname, +            "password" => "test", +            "client_id" => app.client_id, +            "redirect_uri" => app.redirect_uris, +            "state" => "statepassed", +            "scope" => "read write follow" +          } +        }) +        |> html_response(:unauthorized) + +      # Keep the details +      assert result =~ app.client_id +      assert result =~ app.redirect_uris + +      # Error message +      assert result =~ "This action is outside the authorized scopes" +    end    end -  test "issues a token for request with HTTP basic auth client credentials" do -    user = insert(:user) -    app = insert(:oauth_app, scopes: ["scope1", "scope2", "scope3"]) +  describe "POST /oauth/token" do +    test "issues a token for an all-body request" do +      user = insert(:user) +      app = insert(:oauth_app, scopes: ["read", "write"]) -    {:ok, auth} = Authorization.create_authorization(app, user, ["scope1", "scope2"]) -    assert auth.scopes == ["scope1", "scope2"] +      {:ok, auth} = Authorization.create_authorization(app, user, ["write"]) -    app_encoded = -      (URI.encode_www_form(app.client_id) <> ":" <> URI.encode_www_form(app.client_secret)) -      |> Base.encode64() +      conn = +        build_conn() +        |> post("/oauth/token", %{ +          "grant_type" => "authorization_code", +          "code" => auth.token, +          "redirect_uri" => app.redirect_uris, +          "client_id" => app.client_id, +          "client_secret" => app.client_secret +        }) -    conn = -      build_conn() -      |> put_req_header("authorization", "Basic " <> app_encoded) -      |> post("/oauth/token", %{ -        "grant_type" => "authorization_code", -        "code" => auth.token, -        "redirect_uri" => app.redirect_uris -      }) +      assert %{"access_token" => token, "me" => ap_id} = json_response(conn, 200) -    assert %{"access_token" => token, "scope" => scope} = json_response(conn, 200) +      token = Repo.get_by(Token, token: token) +      assert token +      assert token.scopes == auth.scopes +      assert user.ap_id == ap_id +    end -    assert scope == "scope1 scope2" +    test "issues a token for `password` grant_type with valid credentials, with full permissions by default" do +      password = "testpassword" +      user = insert(:user, password_hash: Comeonin.Pbkdf2.hashpwsalt(password)) -    token = Repo.get_by(Token, token: token) -    assert token -    assert token.scopes == ["scope1", "scope2"] -  end +      app = insert(:oauth_app, scopes: ["read", "write"]) -  test "rejects token exchange with invalid client credentials" do -    user = insert(:user) -    app = insert(:oauth_app) +      # Note: "scope" param is intentionally omitted +      conn = +        build_conn() +        |> post("/oauth/token", %{ +          "grant_type" => "password", +          "username" => user.nickname, +          "password" => password, +          "client_id" => app.client_id, +          "client_secret" => app.client_secret +        }) -    {:ok, auth} = Authorization.create_authorization(app, user) +      assert %{"access_token" => token} = json_response(conn, 200) -    conn = -      build_conn() -      |> put_req_header("authorization", "Basic JTIxOiVGMCU5RiVBNCVCNwo=") -      |> post("/oauth/token", %{ -        "grant_type" => "authorization_code", -        "code" => auth.token, -        "redirect_uri" => app.redirect_uris -      }) +      token = Repo.get_by(Token, token: token) +      assert token +      assert token.scopes == app.scopes +    end -    assert resp = json_response(conn, 400) -    assert %{"error" => _} = resp -    refute Map.has_key?(resp, "access_token") -  end +    test "issues a token for request with HTTP basic auth client credentials" do +      user = insert(:user) +      app = insert(:oauth_app, scopes: ["scope1", "scope2", "scope3"]) + +      {:ok, auth} = Authorization.create_authorization(app, user, ["scope1", "scope2"]) +      assert auth.scopes == ["scope1", "scope2"] -  test "rejects token exchange for valid credentials belonging to unconfirmed user and confirmation is required" do -    setting = Pleroma.Config.get([:instance, :account_activation_required]) +      app_encoded = +        (URI.encode_www_form(app.client_id) <> ":" <> URI.encode_www_form(app.client_secret)) +        |> Base.encode64() -    unless setting do -      Pleroma.Config.put([:instance, :account_activation_required], true) -      on_exit(fn -> Pleroma.Config.put([:instance, :account_activation_required], setting) end) +      conn = +        build_conn() +        |> put_req_header("authorization", "Basic " <> app_encoded) +        |> post("/oauth/token", %{ +          "grant_type" => "authorization_code", +          "code" => auth.token, +          "redirect_uri" => app.redirect_uris +        }) + +      assert %{"access_token" => token, "scope" => scope} = json_response(conn, 200) + +      assert scope == "scope1 scope2" + +      token = Repo.get_by(Token, token: token) +      assert token +      assert token.scopes == ["scope1", "scope2"]      end -    password = "testpassword" -    user = insert(:user, password_hash: Comeonin.Pbkdf2.hashpwsalt(password)) -    info_change = Pleroma.User.Info.confirmation_changeset(user.info, :unconfirmed) +    test "rejects token exchange with invalid client credentials" do +      user = insert(:user) +      app = insert(:oauth_app) -    {:ok, user} = -      user -      |> Ecto.Changeset.change() -      |> Ecto.Changeset.put_embed(:info, info_change) -      |> Repo.update() +      {:ok, auth} = Authorization.create_authorization(app, user) -    refute Pleroma.User.auth_active?(user) +      conn = +        build_conn() +        |> put_req_header("authorization", "Basic JTIxOiVGMCU5RiVBNCVCNwo=") +        |> post("/oauth/token", %{ +          "grant_type" => "authorization_code", +          "code" => auth.token, +          "redirect_uri" => app.redirect_uris +        }) -    app = insert(:oauth_app) +      assert resp = json_response(conn, 400) +      assert %{"error" => _} = resp +      refute Map.has_key?(resp, "access_token") +    end -    conn = -      build_conn() -      |> post("/oauth/token", %{ -        "grant_type" => "password", -        "username" => user.nickname, -        "password" => password, -        "client_id" => app.client_id, -        "client_secret" => app.client_secret -      }) +    test "rejects token exchange for valid credentials belonging to unconfirmed user and confirmation is required" do +      setting = Pleroma.Config.get([:instance, :account_activation_required]) -    assert resp = json_response(conn, 403) -    assert %{"error" => _} = resp -    refute Map.has_key?(resp, "access_token") -  end +      unless setting do +        Pleroma.Config.put([:instance, :account_activation_required], true) +        on_exit(fn -> Pleroma.Config.put([:instance, :account_activation_required], setting) end) +      end -  test "rejects an invalid authorization code" do -    app = insert(:oauth_app) +      password = "testpassword" +      user = insert(:user, password_hash: Comeonin.Pbkdf2.hashpwsalt(password)) +      info_change = Pleroma.User.Info.confirmation_changeset(user.info, :unconfirmed) -    conn = -      build_conn() -      |> post("/oauth/token", %{ -        "grant_type" => "authorization_code", -        "code" => "Imobviouslyinvalid", -        "redirect_uri" => app.redirect_uris, -        "client_id" => app.client_id, -        "client_secret" => app.client_secret -      }) +      {:ok, user} = +        user +        |> Ecto.Changeset.change() +        |> Ecto.Changeset.put_embed(:info, info_change) +        |> Repo.update() + +      refute Pleroma.User.auth_active?(user) + +      app = insert(:oauth_app) + +      conn = +        build_conn() +        |> post("/oauth/token", %{ +          "grant_type" => "password", +          "username" => user.nickname, +          "password" => password, +          "client_id" => app.client_id, +          "client_secret" => app.client_secret +        }) + +      assert resp = json_response(conn, 403) +      assert %{"error" => _} = resp +      refute Map.has_key?(resp, "access_token") +    end + +    test "rejects token exchange for valid credentials belonging to deactivated user" do +      password = "testpassword" + +      user = +        insert(:user, +          password_hash: Comeonin.Pbkdf2.hashpwsalt(password), +          info: %{deactivated: true} +        ) -    assert resp = json_response(conn, 400) -    assert %{"error" => _} = json_response(conn, 400) -    refute Map.has_key?(resp, "access_token") +      app = insert(:oauth_app) + +      conn = +        build_conn() +        |> post("/oauth/token", %{ +          "grant_type" => "password", +          "username" => user.nickname, +          "password" => password, +          "client_id" => app.client_id, +          "client_secret" => app.client_secret +        }) + +      assert resp = json_response(conn, 403) +      assert %{"error" => _} = resp +      refute Map.has_key?(resp, "access_token") +    end + +    test "rejects an invalid authorization code" do +      app = insert(:oauth_app) + +      conn = +        build_conn() +        |> post("/oauth/token", %{ +          "grant_type" => "authorization_code", +          "code" => "Imobviouslyinvalid", +          "redirect_uri" => app.redirect_uris, +          "client_id" => app.client_id, +          "client_secret" => app.client_secret +        }) + +      assert resp = json_response(conn, 400) +      assert %{"error" => _} = json_response(conn, 400) +      refute Map.has_key?(resp, "access_token") +    end    end  end diff --git a/test/web/ostatus/activity_representer_test.exs b/test/web/ostatus/activity_representer_test.exs index 5cb135b4c..a4bb68c4d 100644 --- a/test/web/ostatus/activity_representer_test.exs +++ b/test/web/ostatus/activity_representer_test.exs @@ -116,10 +116,10 @@ defmodule Pleroma.Web.OStatus.ActivityRepresenterTest do      {:ok, announce, _object} = ActivityPub.announce(user, object) -    announce = Repo.get(Activity, announce.id) +    announce = Activity.get_by_id(announce.id)      note_user = User.get_cached_by_ap_id(note.data["actor"]) -    note = Repo.get(Activity, note.id) +    note = Activity.get_by_id(note.id)      note_xml =        ActivityRepresenter.to_simple_form(note, note_user, true) diff --git a/test/web/ostatus/incoming_documents/delete_handling_test.exs b/test/web/ostatus/incoming_documents/delete_handling_test.exs index 412d894fd..ca6e61339 100644 --- a/test/web/ostatus/incoming_documents/delete_handling_test.exs +++ b/test/web/ostatus/incoming_documents/delete_handling_test.exs @@ -6,7 +6,6 @@ defmodule Pleroma.Web.OStatus.DeleteHandlingTest do    alias Pleroma.Activity    alias Pleroma.Object -  alias Pleroma.Repo    alias Pleroma.Web.OStatus    setup do @@ -32,10 +31,10 @@ defmodule Pleroma.Web.OStatus.DeleteHandlingTest do        {:ok, [delete]} = OStatus.handle_incoming(incoming) -      refute Repo.get(Activity, note.id) -      refute Repo.get(Activity, like.id) +      refute Activity.get_by_id(note.id) +      refute Activity.get_by_id(like.id)        assert Object.get_by_ap_id(note.data["object"]["id"]).data["type"] == "Tombstone" -      assert Repo.get(Activity, second_note.id) +      assert Activity.get_by_id(second_note.id)        assert Object.get_by_ap_id(second_note.data["object"]["id"])        assert delete.data["type"] == "Delete" diff --git a/test/web/ostatus/ostatus_controller_test.exs b/test/web/ostatus/ostatus_controller_test.exs index 2950f11c0..7441e5fce 100644 --- a/test/web/ostatus/ostatus_controller_test.exs +++ b/test/web/ostatus/ostatus_controller_test.exs @@ -6,7 +6,6 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do    use Pleroma.Web.ConnCase    import Pleroma.Factory    alias Pleroma.Object -  alias Pleroma.Repo    alias Pleroma.User    alias Pleroma.Web.CommonAPI    alias Pleroma.Web.OStatus.ActivityRepresenter @@ -41,7 +40,8 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do        assert response(conn, 200)        # Set a wrong magic-key for a user so it has to refetch -      salmon_user = User.get_by_ap_id("http://gs.example.org:4040/index.php/user/1") +      salmon_user = User.get_cached_by_ap_id("http://gs.example.org:4040/index.php/user/1") +        # Wrong key        info_cng =          User.Info.remote_user_creation(salmon_user.info, %{ @@ -52,7 +52,7 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do        salmon_user        |> Ecto.Changeset.change()        |> Ecto.Changeset.put_embed(:info, info_cng) -      |> Repo.update() +      |> User.update_and_set_cache()        conn =          build_conn() @@ -86,7 +86,7 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do    test "gets an object", %{conn: conn} do      note_activity = insert(:note_activity) -    user = User.get_by_ap_id(note_activity.data["actor"]) +    user = User.get_cached_by_ap_id(note_activity.data["actor"])      [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, note_activity.data["object"]["id"]))      url = "/objects/#{uuid}" diff --git a/test/web/ostatus/ostatus_test.exs b/test/web/ostatus/ostatus_test.exs index 76b90e186..2916caf8d 100644 --- a/test/web/ostatus/ostatus_test.exs +++ b/test/web/ostatus/ostatus_test.exs @@ -28,34 +28,35 @@ defmodule Pleroma.Web.OStatusTest do    test "handle incoming note - GS, Salmon" do      incoming = File.read!("test/fixtures/incoming_note_activity.xml")      {:ok, [activity]} = OStatus.handle_incoming(incoming) +    object = Object.normalize(activity.data["object"]) -    user = User.get_by_ap_id(activity.data["actor"]) +    user = User.get_cached_by_ap_id(activity.data["actor"])      assert user.info.note_count == 1      assert activity.data["type"] == "Create" -    assert activity.data["object"]["type"] == "Note" +    assert object.data["type"] == "Note" -    assert activity.data["object"]["id"] == -             "tag:gs.example.org:4040,2017-04-23:noticeId=29:objectType=note" +    assert object.data["id"] == "tag:gs.example.org:4040,2017-04-23:noticeId=29:objectType=note"      assert activity.data["published"] == "2017-04-23T14:51:03+00:00" -    assert activity.data["object"]["published"] == "2017-04-23T14:51:03+00:00" +    assert object.data["published"] == "2017-04-23T14:51:03+00:00"      assert activity.data["context"] ==               "tag:gs.example.org:4040,2017-04-23:objectType=thread:nonce=f09e22f58abd5c7b"      assert "http://pleroma.example.org:4000/users/lain3" in activity.data["to"] -    assert activity.data["object"]["emoji"] == %{"marko" => "marko.png", "reimu" => "reimu.png"} +    assert object.data["emoji"] == %{"marko" => "marko.png", "reimu" => "reimu.png"}      assert activity.local == false    end    test "handle incoming notes - GS, subscription" do      incoming = File.read!("test/fixtures/ostatus_incoming_post.xml")      {:ok, [activity]} = OStatus.handle_incoming(incoming) +    object = Object.normalize(activity.data["object"])      assert activity.data["type"] == "Create" -    assert activity.data["object"]["type"] == "Note" -    assert activity.data["object"]["actor"] == "https://social.heldscal.la/user/23211" -    assert activity.data["object"]["content"] == "Will it blend?" +    assert object.data["type"] == "Note" +    assert object.data["actor"] == "https://social.heldscal.la/user/23211" +    assert object.data["content"] == "Will it blend?"      user = User.get_cached_by_ap_id(activity.data["actor"])      assert User.ap_followers(user) in activity.data["to"]      assert "https://www.w3.org/ns/activitystreams#Public" in activity.data["to"] @@ -64,20 +65,22 @@ defmodule Pleroma.Web.OStatusTest do    test "handle incoming notes with attachments - GS, subscription" do      incoming = File.read!("test/fixtures/incoming_websub_gnusocial_attachments.xml")      {:ok, [activity]} = OStatus.handle_incoming(incoming) +    object = Object.normalize(activity.data["object"])      assert activity.data["type"] == "Create" -    assert activity.data["object"]["type"] == "Note" -    assert activity.data["object"]["actor"] == "https://social.heldscal.la/user/23211" -    assert activity.data["object"]["attachment"] |> length == 2 -    assert activity.data["object"]["external_url"] == "https://social.heldscal.la/notice/2020923" +    assert object.data["type"] == "Note" +    assert object.data["actor"] == "https://social.heldscal.la/user/23211" +    assert object.data["attachment"] |> length == 2 +    assert object.data["external_url"] == "https://social.heldscal.la/notice/2020923"      assert "https://www.w3.org/ns/activitystreams#Public" in activity.data["to"]    end    test "handle incoming notes with tags" do      incoming = File.read!("test/fixtures/ostatus_incoming_post_tag.xml")      {:ok, [activity]} = OStatus.handle_incoming(incoming) +    object = Object.normalize(activity.data["object"]) -    assert activity.data["object"]["tag"] == ["nsfw"] +    assert object.data["tag"] == ["nsfw"]      assert "https://www.w3.org/ns/activitystreams#Public" in activity.data["to"]    end @@ -92,10 +95,11 @@ defmodule Pleroma.Web.OStatusTest do      incoming = File.read!("test/fixtures/incoming_reply_mastodon.xml")      {:ok, [activity]} = OStatus.handle_incoming(incoming) +    object = Object.normalize(activity.data["object"])      assert activity.data["type"] == "Create" -    assert activity.data["object"]["type"] == "Note" -    assert activity.data["object"]["actor"] == "https://mastodon.social/users/lambadalambda" +    assert object.data["type"] == "Note" +    assert object.data["actor"] == "https://mastodon.social/users/lambadalambda"      assert activity.data["context"] == "2hu"      assert "https://www.w3.org/ns/activitystreams#Public" in activity.data["to"]    end @@ -103,42 +107,47 @@ defmodule Pleroma.Web.OStatusTest do    test "handle incoming notes - Mastodon, with CW" do      incoming = File.read!("test/fixtures/mastodon-note-cw.xml")      {:ok, [activity]} = OStatus.handle_incoming(incoming) +    object = Object.normalize(activity.data["object"])      assert activity.data["type"] == "Create" -    assert activity.data["object"]["type"] == "Note" -    assert activity.data["object"]["actor"] == "https://mastodon.social/users/lambadalambda" -    assert activity.data["object"]["summary"] == "technologic" +    assert object.data["type"] == "Note" +    assert object.data["actor"] == "https://mastodon.social/users/lambadalambda" +    assert object.data["summary"] == "technologic"      assert "https://www.w3.org/ns/activitystreams#Public" in activity.data["to"]    end    test "handle incoming unlisted messages, put public into cc" do      incoming = File.read!("test/fixtures/mastodon-note-unlisted.xml")      {:ok, [activity]} = OStatus.handle_incoming(incoming) +    object = Object.normalize(activity.data["object"]) +      refute "https://www.w3.org/ns/activitystreams#Public" in activity.data["to"]      assert "https://www.w3.org/ns/activitystreams#Public" in activity.data["cc"] -    refute "https://www.w3.org/ns/activitystreams#Public" in activity.data["object"]["to"] -    assert "https://www.w3.org/ns/activitystreams#Public" in activity.data["object"]["cc"] +    refute "https://www.w3.org/ns/activitystreams#Public" in object.data["to"] +    assert "https://www.w3.org/ns/activitystreams#Public" in object.data["cc"]    end    test "handle incoming retweets - Mastodon, with CW" do      incoming = File.read!("test/fixtures/cw_retweet.xml")      {:ok, [[_activity, retweeted_activity]]} = OStatus.handle_incoming(incoming) +    retweeted_object = Object.normalize(retweeted_activity.data["object"]) -    assert retweeted_activity.data["object"]["summary"] == "Hey." +    assert retweeted_object.data["summary"] == "Hey."    end    test "handle incoming notes - GS, subscription, reply" do      incoming = File.read!("test/fixtures/ostatus_incoming_reply.xml")      {:ok, [activity]} = OStatus.handle_incoming(incoming) +    object = Object.normalize(activity.data["object"])      assert activity.data["type"] == "Create" -    assert activity.data["object"]["type"] == "Note" -    assert activity.data["object"]["actor"] == "https://social.heldscal.la/user/23211" +    assert object.data["type"] == "Note" +    assert object.data["actor"] == "https://social.heldscal.la/user/23211" -    assert activity.data["object"]["content"] == +    assert object.data["content"] ==               "@<a href=\"https://gs.archae.me/user/4687\" class=\"h-card u-url p-nickname mention\" title=\"shpbot\">shpbot</a> why not indeed." -    assert activity.data["object"]["inReplyTo"] == +    assert object.data["inReplyTo"] ==               "tag:gs.archae.me,2017-04-30:noticeId=778260:objectType=note"      assert "https://www.w3.org/ns/activitystreams#Public" in activity.data["to"] @@ -150,17 +159,18 @@ defmodule Pleroma.Web.OStatusTest do      assert activity.data["type"] == "Announce"      assert activity.data["actor"] == "https://social.heldscal.la/user/23211" -    assert activity.data["object"] == retweeted_activity.data["object"]["id"] +    assert activity.data["object"] == retweeted_activity.data["object"]      assert "https://pleroma.soykaf.com/users/lain" in activity.data["to"]      refute activity.local -    retweeted_activity = Repo.get(Activity, retweeted_activity.id) +    retweeted_activity = Activity.get_by_id(retweeted_activity.id) +    retweeted_object = Object.normalize(retweeted_activity.data["object"])      assert retweeted_activity.data["type"] == "Create"      assert retweeted_activity.data["actor"] == "https://pleroma.soykaf.com/users/lain"      refute retweeted_activity.local -    assert retweeted_activity.data["object"]["announcement_count"] == 1 -    assert String.contains?(retweeted_activity.data["object"]["content"], "mastodon") -    refute String.contains?(retweeted_activity.data["object"]["content"], "Test account") +    assert retweeted_object.data["announcement_count"] == 1 +    assert String.contains?(retweeted_object.data["content"], "mastodon") +    refute String.contains?(retweeted_object.data["content"], "Test account")    end    test "handle incoming retweets - GS, subscription - local message" do @@ -181,7 +191,7 @@ defmodule Pleroma.Web.OStatusTest do      assert user.ap_id in activity.data["to"]      refute activity.local -    retweeted_activity = Repo.get(Activity, retweeted_activity.id) +    retweeted_activity = Activity.get_by_id(retweeted_activity.id)      assert note_activity.id == retweeted_activity.id      assert retweeted_activity.data["type"] == "Create"      assert retweeted_activity.data["actor"] == user.ap_id @@ -192,10 +202,11 @@ defmodule Pleroma.Web.OStatusTest do    test "handle incoming retweets - Mastodon, salmon" do      incoming = File.read!("test/fixtures/share.xml")      {:ok, [[activity, retweeted_activity]]} = OStatus.handle_incoming(incoming) +    retweeted_object = Object.normalize(retweeted_activity.data["object"])      assert activity.data["type"] == "Announce"      assert activity.data["actor"] == "https://mastodon.social/users/lambadalambda" -    assert activity.data["object"] == retweeted_activity.data["object"]["id"] +    assert activity.data["object"] == retweeted_activity.data["object"]      assert activity.data["id"] ==               "tag:mastodon.social,2017-05-03:objectId=4934452:objectType=Status" @@ -204,7 +215,7 @@ defmodule Pleroma.Web.OStatusTest do      assert retweeted_activity.data["type"] == "Create"      assert retweeted_activity.data["actor"] == "https://pleroma.soykaf.com/users/lain"      refute retweeted_activity.local -    refute String.contains?(retweeted_activity.data["object"]["content"], "Test account") +    refute String.contains?(retweeted_object.data["content"], "Test account")    end    test "handle incoming favorites - GS, websub" do @@ -214,7 +225,7 @@ defmodule Pleroma.Web.OStatusTest do        assert activity.data["type"] == "Like"        assert activity.data["actor"] == "https://social.heldscal.la/user/23211" -      assert activity.data["object"] == favorited_activity.data["object"]["id"] +      assert activity.data["object"] == favorited_activity.data["object"]        assert activity.data["id"] ==                 "tag:social.heldscal.la,2017-05-05:fave:23211:comment:2061643:2017-05-05T09:12:50+00:00" @@ -223,7 +234,7 @@ defmodule Pleroma.Web.OStatusTest do        assert favorited_activity.data["type"] == "Create"        assert favorited_activity.data["actor"] == "https://shitposter.club/user/1" -      assert favorited_activity.data["object"]["id"] == +      assert favorited_activity.data["object"] ==                 "tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment"        refute favorited_activity.local @@ -258,17 +269,17 @@ defmodule Pleroma.Web.OStatusTest do    test "handle incoming replies" do      incoming = File.read!("test/fixtures/incoming_note_activity_answer.xml")      {:ok, [activity]} = OStatus.handle_incoming(incoming) +    object = Object.normalize(activity.data["object"])      assert activity.data["type"] == "Create" -    assert activity.data["object"]["type"] == "Note" +    assert object.data["type"] == "Note" -    assert activity.data["object"]["inReplyTo"] == +    assert object.data["inReplyTo"] ==               "http://pleroma.example.org:4000/objects/55bce8fc-b423-46b1-af71-3759ab4670bc"      assert "http://pleroma.example.org:4000/users/lain5" in activity.data["to"] -    assert activity.data["object"]["id"] == -             "tag:gs.example.org:4040,2017-04-25:noticeId=55:objectType=note" +    assert object.data["id"] == "tag:gs.example.org:4040,2017-04-25:noticeId=55:objectType=note"      assert "https://www.w3.org/ns/activitystreams#Public" in activity.data["to"]    end @@ -285,8 +296,8 @@ defmodule Pleroma.Web.OStatusTest do      assert activity.data["object"] == "https://pawoo.net/users/pekorino"      refute activity.local -    follower = User.get_by_ap_id(activity.data["actor"]) -    followed = User.get_by_ap_id(activity.data["object"]) +    follower = User.get_cached_by_ap_id(activity.data["actor"]) +    followed = User.get_cached_by_ap_id(activity.data["object"])      assert User.following?(follower, followed)    end @@ -309,8 +320,8 @@ defmodule Pleroma.Web.OStatusTest do      assert activity.data["object"]["object"] == "https://pawoo.net/users/pekorino"      refute activity.local -    follower = User.get_by_ap_id(activity.data["actor"]) -    followed = User.get_by_ap_id(activity.data["object"]["object"]) +    follower = User.get_cached_by_ap_id(activity.data["actor"]) +    followed = User.get_cached_by_ap_id(activity.data["object"]["object"])      refute User.following?(follower, followed)    end @@ -344,7 +355,7 @@ defmodule Pleroma.Web.OStatusTest do        {:ok, user} = OStatus.find_or_make_user(uri) -      user = Repo.get(Pleroma.User, user.id) +      user = Pleroma.User.get_cached_by_id(user.id)        assert user.name == "Constance Variable"        assert user.nickname == "lambadalambda@social.heldscal.la"        assert user.local == false @@ -495,7 +506,7 @@ defmodule Pleroma.Web.OStatusTest do          assert activity.data["actor"] == "https://shitposter.club/user/1" -        assert activity.data["object"]["id"] == +        assert activity.data["object"] ==                   "tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment"        end)      end @@ -504,7 +515,7 @@ defmodule Pleroma.Web.OStatusTest do        url = "https://social.sakamoto.gq/objects/0ccc1a2c-66b0-4305-b23a-7f7f2b040056"        {:ok, [activity]} = OStatus.fetch_activity_from_url(url)        assert activity.data["actor"] == "https://social.sakamoto.gq/users/eal" -      assert activity.data["object"]["id"] == url +      assert activity.data["object"] == url      end    end diff --git a/test/web/push/impl_test.exs b/test/web/push/impl_test.exs index 3f9f3d809..1e948086a 100644 --- a/test/web/push/impl_test.exs +++ b/test/web/push/impl_test.exs @@ -5,6 +5,8 @@  defmodule Pleroma.Web.Push.ImplTest do    use Pleroma.DataCase +  alias Pleroma.Object +  alias Pleroma.Web.CommonAPI    alias Pleroma.Web.Push.Impl    alias Pleroma.Web.Push.Subscription @@ -52,29 +54,27 @@ defmodule Pleroma.Web.Push.ImplTest do        data: %{alerts: %{"follow" => true, "mention" => false}}      ) +    {:ok, activity} = CommonAPI.post(user, %{"status" => "<Lorem ipsum dolor sit amet."}) +      notif =        insert(:notification,          user: user, -        activity: %Pleroma.Activity{ -          data: %{ -            "type" => "Create", -            "actor" => user.ap_id, -            "object" => %{"content" => "<Lorem ipsum dolor sit amet."} -          } -        } +        activity: activity        ) -    assert Impl.perform_send(notif) == [:ok, :ok] +    assert Impl.perform(notif) == [:ok, :ok]    end +  @tag capture_log: true    test "returns error if notif does not match " do -    assert Impl.perform_send(%{}) == :error +    assert Impl.perform(%{}) == :error    end    test "successful message sending" do      assert Impl.push_message(@message, @sub, @api_key, %Subscription{}) == :ok    end +  @tag capture_log: true    test "fail message sending" do      assert Impl.push_message(               @message, @@ -98,48 +98,65 @@ defmodule Pleroma.Web.Push.ImplTest do    end    test "renders body for create activity" do +    user = insert(:user, nickname: "Bob") + +    {:ok, activity} = +      CommonAPI.post(user, %{ +        "status" => +          "<span>Lorem ipsum dolor sit amet</span>, consectetur :firefox: adipiscing elit. Fusce sagittis finibus turpis." +      }) + +    object = Object.normalize(activity) +      assert Impl.format_body(               %{ -               activity: %{ -                 data: %{ -                   "type" => "Create", -                   "object" => %{ -                     "content" => -                       "<span>Lorem ipsum dolor sit amet</span>, consectetur :bear: adipiscing elit. Fusce sagittis finibus turpis." -                   } -                 } -               } +               activity: activity               }, -             %{nickname: "Bob"} +             user, +             object             ) ==               "@Bob: Lorem ipsum dolor sit amet, consectetur  adipiscing elit. Fusce sagittis fini..."    end    test "renders body for follow activity" do -    assert Impl.format_body(%{activity: %{data: %{"type" => "Follow"}}}, %{nickname: "Bob"}) == +    user = insert(:user, nickname: "Bob") +    other_user = insert(:user) +    {:ok, _, _, activity} = CommonAPI.follow(user, other_user) +    object = Object.normalize(activity) + +    assert Impl.format_body(%{activity: activity}, user, object) ==               "@Bob has followed you"    end    test "renders body for announce activity" do      user = insert(:user) -    note = -      insert(:note, %{ -        data: %{ -          "content" => -            "<span>Lorem ipsum dolor sit amet</span>, consectetur :bear: adipiscing elit. Fusce sagittis finibus turpis." -        } +    {:ok, activity} = +      CommonAPI.post(user, %{ +        "status" => +          "<span>Lorem ipsum dolor sit amet</span>, consectetur :firefox: adipiscing elit. Fusce sagittis finibus turpis."        }) -    note_activity = insert(:note_activity, %{note: note}) -    announce_activity = insert(:announce_activity, %{user: user, note_activity: note_activity}) +    {:ok, announce_activity, _} = CommonAPI.repeat(activity.id, user) +    object = Object.normalize(activity) -    assert Impl.format_body(%{activity: announce_activity}, user) == +    assert Impl.format_body(%{activity: announce_activity}, user, object) ==               "@#{user.nickname} repeated: Lorem ipsum dolor sit amet, consectetur  adipiscing elit. Fusce sagittis fini..."    end    test "renders body for like activity" do -    assert Impl.format_body(%{activity: %{data: %{"type" => "Like"}}}, %{nickname: "Bob"}) == +    user = insert(:user, nickname: "Bob") + +    {:ok, activity} = +      CommonAPI.post(user, %{ +        "status" => +          "<span>Lorem ipsum dolor sit amet</span>, consectetur :firefox: adipiscing elit. Fusce sagittis finibus turpis." +      }) + +    {:ok, activity, _} = CommonAPI.favorite(activity.id, user) +    object = Object.normalize(activity) + +    assert Impl.format_body(%{activity: activity}, user, object) ==               "@Bob has favorited your post"    end  end diff --git a/test/web/salmon/salmon_test.exs b/test/web/salmon/salmon_test.exs index 265e1abbd..7532578ca 100644 --- a/test/web/salmon/salmon_test.exs +++ b/test/web/salmon/salmon_test.exs @@ -99,7 +99,7 @@ defmodule Pleroma.Web.Salmon.SalmonTest do      }      {:ok, activity} = Repo.insert(%Activity{data: activity_data, recipients: activity_data["to"]}) -    user = Repo.get_by(User, ap_id: activity.data["actor"]) +    user = User.get_cached_by_ap_id(activity.data["actor"])      {:ok, user} = Pleroma.Web.WebFinger.ensure_keys_present(user)      poster = fn url, _data, _headers -> diff --git a/test/web/streamer_test.exs b/test/web/streamer_test.exs index 0a2e91298..bfe18cb7f 100644 --- a/test/web/streamer_test.exs +++ b/test/web/streamer_test.exs @@ -202,4 +202,34 @@ defmodule Pleroma.Web.StreamerTest do      Task.await(task)    end + +  test "it doesn't send muted reblogs" do +    user1 = insert(:user) +    user2 = insert(:user) +    user3 = insert(:user) +    CommonAPI.hide_reblogs(user1, user2) + +    task = +      Task.async(fn -> +        refute_receive {:text, _}, 1_000 +      end) + +    fake_socket = %{ +      transport_pid: task.pid, +      assigns: %{ +        user: user1 +      } +    } + +    {:ok, create_activity} = CommonAPI.post(user3, %{"status" => "I'm kawen"}) +    {:ok, announce_activity, _} = CommonAPI.repeat(create_activity.id, user2) + +    topics = %{ +      "public" => [fake_socket] +    } + +    Streamer.push_to_socket(topics, "public", announce_activity) + +    Task.await(task) +  end  end diff --git a/test/web/twitter_api/representers/activity_representer_test.exs b/test/web/twitter_api/representers/activity_representer_test.exs deleted file mode 100644 index d154385a0..000000000 --- a/test/web/twitter_api/representers/activity_representer_test.exs +++ /dev/null @@ -1,170 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.TwitterAPI.Representers.ActivityRepresenterTest do -  use Pleroma.DataCase -  alias Pleroma.Activity -  alias Pleroma.Object -  alias Pleroma.User -  alias Pleroma.Web.ActivityPub.ActivityPub -  alias Pleroma.Web.TwitterAPI.Representers.ActivityRepresenter -  alias Pleroma.Web.TwitterAPI.Representers.ObjectRepresenter -  alias Pleroma.Web.TwitterAPI.UserView -  import Pleroma.Factory - -  test "a like activity" do -    user = insert(:user) -    note_activity = insert(:note_activity) -    object = Object.get_by_ap_id(note_activity.data["object"]["id"]) - -    {:ok, like_activity, _object} = ActivityPub.like(user, object) - -    status = -      ActivityRepresenter.to_map(like_activity, %{user: user, liked_activity: note_activity}) - -    assert status["id"] == like_activity.id -    assert status["in_reply_to_status_id"] == note_activity.id - -    note_activity = Activity.get_by_ap_id(note_activity.data["id"]) -    activity_actor = Repo.get_by(User, ap_id: note_activity.data["actor"]) -    liked_status = ActivityRepresenter.to_map(note_activity, %{user: activity_actor, for: user}) -    assert liked_status["favorited"] == true -    assert status["activity_type"] == "like" -  end - -  test "an activity" do -    user = insert(:user) -    #   {:ok, mentioned_user } = UserBuilder.insert(%{nickname: "shp", ap_id: "shp"}) -    mentioned_user = insert(:user, %{nickname: "shp"}) - -    # {:ok, follower} = UserBuilder.insert(%{following: [User.ap_followers(user)]}) -    follower = insert(:user, %{following: [User.ap_followers(user)]}) - -    object = %Object{ -      data: %{ -        "type" => "Image", -        "url" => [ -          %{ -            "type" => "Link", -            "mediaType" => "image/jpg", -            "href" => "http://example.org/image.jpg" -          } -        ], -        "uuid" => 1 -      } -    } - -    content_html = -      "<script>alert('YAY')</script>Some :2hu: content mentioning <a href='#{mentioned_user.ap_id}'>@shp</shp>" - -    content = HtmlSanitizeEx.strip_tags(content_html) -    date = DateTime.from_naive!(~N[2016-05-24 13:26:08.003], "Etc/UTC") |> DateTime.to_iso8601() - -    {:ok, convo_object} = Object.context_mapping("2hu") |> Repo.insert() - -    to = [ -      User.ap_followers(user), -      "https://www.w3.org/ns/activitystreams#Public", -      mentioned_user.ap_id -    ] - -    activity = %Activity{ -      id: 1, -      data: %{ -        "type" => "Create", -        "id" => "id", -        "to" => to, -        "actor" => User.ap_id(user), -        "object" => %{ -          "published" => date, -          "type" => "Note", -          "content" => content_html, -          "summary" => "2hu :2hu:", -          "inReplyToStatusId" => 213_123, -          "attachment" => [ -            object -          ], -          "external_url" => "some url", -          "like_count" => 5, -          "announcement_count" => 3, -          "context" => "2hu", -          "tag" => ["content", "mentioning", "nsfw"], -          "emoji" => %{ -            "2hu" => "corndog.png" -          } -        }, -        "published" => date, -        "context" => "2hu" -      }, -      local: false, -      recipients: to -    } - -    corndog_emojo = ~s(<img height="32px" width="32px" alt="2hu" title="2hu" src="corndog.png" />) - -    expected_html = -      ~s(<p>2hu ) <> -        corndog_emojo <> -        ~s(</p>alert\('YAY'\)Some ) <> -        corndog_emojo <> -        ~s( content mentioning <a href=") <> mentioned_user.ap_id <> ~s(">@shp</a>) - -    expected_status = %{ -      "id" => activity.id, -      "user" => UserView.render("show.json", %{user: user, for: follower}), -      "is_local" => false, -      "statusnet_html" => expected_html, -      "text" => "2hu :2hu:" <> content, -      "is_post_verb" => true, -      "created_at" => "Tue May 24 13:26:08 +0000 2016", -      "in_reply_to_status_id" => 213_123, -      "in_reply_to_screen_name" => nil, -      "in_reply_to_user_id" => nil, -      "in_reply_to_profileurl" => nil, -      "in_reply_to_ostatus_uri" => nil, -      "statusnet_conversation_id" => convo_object.id, -      "attachments" => [ -        ObjectRepresenter.to_map(object) -      ], -      "attentions" => [ -        UserView.render("show.json", %{user: mentioned_user, for: follower}) -      ], -      "fave_num" => 5, -      "repeat_num" => 3, -      "favorited" => false, -      "repeated" => false, -      "pinned" => false, -      "external_url" => "some url", -      "tags" => ["nsfw", "content", "mentioning"], -      "activity_type" => "post", -      "possibly_sensitive" => true, -      "uri" => activity.data["object"]["id"], -      "visibility" => "direct", -      "card" => nil, -      "muted" => false, -      "summary" => "2hu :2hu:", -      "summary_html" => -        "2hu <img height=\"32px\" width=\"32px\" alt=\"2hu\" title=\"2hu\" src=\"corndog.png\" />" -    } - -    assert ActivityRepresenter.to_map(activity, %{ -             user: user, -             for: follower, -             mentioned: [mentioned_user] -           }) == expected_status -  end - -  test "a delete activity" do -    object = insert(:note) -    user = User.get_by_ap_id(object.data["actor"]) - -    {:ok, delete} = ActivityPub.delete(object) - -    map = ActivityRepresenter.to_map(delete, %{user: user}) - -    assert map["is_post_verb"] == false -    assert map["activity_type"] == "delete" -    assert map["uri"] == object.data["id"] -  end -end diff --git a/test/web/twitter_api/twitter_api_controller_test.exs b/test/web/twitter_api/twitter_api_controller_test.exs index 1b810c9a0..43ad71a16 100644 --- a/test/web/twitter_api/twitter_api_controller_test.exs +++ b/test/web/twitter_api/twitter_api_controller_test.exs @@ -16,14 +16,15 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do    alias Pleroma.Web.ActivityPub.ActivityPub    alias Pleroma.Web.CommonAPI    alias Pleroma.Web.OAuth.Token +  alias Pleroma.Web.TwitterAPI.ActivityView    alias Pleroma.Web.TwitterAPI.Controller    alias Pleroma.Web.TwitterAPI.NotificationView -  alias Pleroma.Web.TwitterAPI.Representers.ActivityRepresenter    alias Pleroma.Web.TwitterAPI.TwitterAPI    alias Pleroma.Web.TwitterAPI.UserView -  import Pleroma.Factory    import Mock +  import Pleroma.Factory +  import Swoosh.TestAssertions    @banner "data:image/gif;base64,R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7" @@ -116,7 +117,11 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do          |> post(request_path, %{status: "Nice meme.", visibility: "private"})        assert json_response(conn, 200) == -               ActivityRepresenter.to_map(Repo.one(Activity), %{user: user, for: user}) +               ActivityView.render("activity.json", %{ +                 activity: Repo.one(Activity), +                 user: user, +                 for: user +               })      end    end @@ -265,7 +270,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do      test "returns one status", %{conn: conn} do        user = insert(:user)        {:ok, activity} = CommonAPI.post(user, %{"status" => "Hey!"}) -      actor = Repo.get_by!(User, ap_id: activity.data["actor"]) +      actor = User.get_cached_by_ap_id(activity.data["actor"])        conn =          conn @@ -273,7 +278,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do        response = json_response(conn, 200) -      assert response == ActivityRepresenter.to_map(activity, %{user: actor}) +      assert response == ActivityView.render("activity.json", %{activity: activity, user: actor})      end    end @@ -372,7 +377,8 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do        assert response ==                 Enum.map(returned_activities, fn activity -> -                 ActivityRepresenter.to_map(activity, %{ +                 ActivityView.render("activity.json", %{ +                   activity: activity,                     user: User.get_cached_by_ap_id(activity.data["actor"]),                     for: current_user                   }) @@ -469,10 +475,10 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do        assert length(response) == 1        assert Enum.at(response, 0) == -               ActivityRepresenter.to_map(activity, %{ +               ActivityView.render("activity.json", %{                   user: current_user,                   for: current_user, -                 mentioned: [current_user] +                 activity: activity                 })      end @@ -594,7 +600,9 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do        conn = get(conn, "/api/statuses/user_timeline.json", %{"user_id" => user.id})        response = json_response(conn, 200)        assert length(response) == 1 -      assert Enum.at(response, 0) == ActivityRepresenter.to_map(activity, %{user: user}) + +      assert Enum.at(response, 0) == +               ActivityView.render("activity.json", %{user: user, activity: activity})      end      test "with screen_name", %{conn: conn} do @@ -604,7 +612,9 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do        conn = get(conn, "/api/statuses/user_timeline.json", %{"screen_name" => user.nickname})        response = json_response(conn, 200)        assert length(response) == 1 -      assert Enum.at(response, 0) == ActivityRepresenter.to_map(activity, %{user: user}) + +      assert Enum.at(response, 0) == +               ActivityView.render("activity.json", %{user: user, activity: activity})      end      test "with credentials", %{conn: conn, user: current_user} do @@ -620,7 +630,11 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do        assert length(response) == 1        assert Enum.at(response, 0) == -               ActivityRepresenter.to_map(activity, %{user: current_user, for: current_user}) +               ActivityView.render("activity.json", %{ +                 user: current_user, +                 for: current_user, +                 activity: activity +               })      end      test "with credentials with user_id", %{conn: conn, user: current_user} do @@ -635,7 +649,9 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do        response = json_response(conn, 200)        assert length(response) == 1 -      assert Enum.at(response, 0) == ActivityRepresenter.to_map(activity, %{user: user}) + +      assert Enum.at(response, 0) == +               ActivityView.render("activity.json", %{user: user, activity: activity})      end      test "with credentials screen_name", %{conn: conn, user: current_user} do @@ -650,7 +666,9 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do        response = json_response(conn, 200)        assert length(response) == 1 -      assert Enum.at(response, 0) == ActivityRepresenter.to_map(activity, %{user: user}) + +      assert Enum.at(response, 0) == +               ActivityView.render("activity.json", %{user: user, activity: activity})      end      test "with credentials with user_id, excluding RTs", %{conn: conn, user: current_user} do @@ -669,7 +687,9 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do        response = json_response(conn, 200)        assert length(response) == 1 -      assert Enum.at(response, 0) == ActivityRepresenter.to_map(activity, %{user: user}) + +      assert Enum.at(response, 0) == +               ActivityView.render("activity.json", %{user: user, activity: activity})        conn =          conn @@ -678,7 +698,9 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do        response = json_response(conn, 200)        assert length(response) == 1 -      assert Enum.at(response, 0) == ActivityRepresenter.to_map(activity, %{user: user}) + +      assert Enum.at(response, 0) == +               ActivityView.render("activity.json", %{user: user, activity: activity})      end    end @@ -698,7 +720,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do          |> with_credentials(current_user.nickname, "test")          |> post("/api/friendships/create.json", %{user_id: followed.id}) -      current_user = Repo.get(User, current_user.id) +      current_user = User.get_cached_by_id(current_user.id)        assert User.ap_followers(followed) in current_user.following        assert json_response(conn, 200) == @@ -713,8 +735,8 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do          |> with_credentials(current_user.nickname, "test")          |> post("/api/friendships/create.json", %{user_id: followed.id}) -      current_user = Repo.get(User, current_user.id) -      followed = Repo.get(User, followed.id) +      current_user = User.get_cached_by_id(current_user.id) +      followed = User.get_cached_by_id(followed.id)        refute User.ap_followers(followed) in current_user.following @@ -743,7 +765,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do          |> with_credentials(current_user.nickname, "test")          |> post("/api/friendships/destroy.json", %{user_id: followed.id}) -      current_user = Repo.get(User, current_user.id) +      current_user = User.get_cached_by_id(current_user.id)        assert current_user.following == [current_user.ap_id]        assert json_response(conn, 200) == @@ -767,7 +789,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do          |> with_credentials(current_user.nickname, "test")          |> post("/api/blocks/create.json", %{user_id: blocked.id}) -      current_user = Repo.get(User, current_user.id) +      current_user = User.get_cached_by_id(current_user.id)        assert User.blocks?(current_user, blocked)        assert json_response(conn, 200) == @@ -794,7 +816,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do          |> with_credentials(current_user.nickname, "test")          |> post("/api/blocks/destroy.json", %{user_id: blocked.id}) -      current_user = Repo.get(User, current_user.id) +      current_user = User.get_cached_by_id(current_user.id)        assert current_user.info.blocks == []        assert json_response(conn, 200) == @@ -825,7 +847,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do          |> with_credentials(current_user.nickname, "test")          |> post("/api/qvitter/update_avatar.json", %{img: avatar_image}) -      current_user = Repo.get(User, current_user.id) +      current_user = User.get_cached_by_id(current_user.id)        assert is_map(current_user.avatar)        assert json_response(conn, 200) == @@ -933,11 +955,15 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do          |> with_credentials(current_user.nickname, "test")          |> post(request_path) -      activity = Repo.get(Activity, note_activity.id) -      activity_user = Repo.get_by(User, ap_id: note_activity.data["actor"]) +      activity = Activity.get_by_id(note_activity.id) +      activity_user = User.get_cached_by_ap_id(note_activity.data["actor"])        assert json_response(response, 200) == -               ActivityRepresenter.to_map(activity, %{user: activity_user, for: current_user}) +               ActivityView.render("activity.json", %{ +                 user: activity_user, +                 for: current_user, +                 activity: activity +               })      end    end @@ -967,11 +993,15 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do          |> with_credentials(current_user.nickname, "test")          |> post(request_path) -      activity = Repo.get(Activity, note_activity.id) -      activity_user = Repo.get_by(User, ap_id: note_activity.data["actor"]) +      activity = Activity.get_by_id(note_activity.id) +      activity_user = User.get_cached_by_ap_id(note_activity.data["actor"])        assert json_response(response, 200) == -               ActivityRepresenter.to_map(activity, %{user: activity_user, for: current_user}) +               ActivityView.render("activity.json", %{ +                 user: activity_user, +                 for: current_user, +                 activity: activity +               })      end    end @@ -992,7 +1022,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do        user = json_response(conn, 200) -      fetched_user = Repo.get_by(User, nickname: "lain") +      fetched_user = User.get_cached_by_nickname("lain")        assert user == UserView.render("show.json", %{user: fetched_user})      end @@ -1034,8 +1064,14 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do      test "it sends an email to user", %{user: user} do        token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id) -      Swoosh.TestAssertions.assert_email_sent( -        Pleroma.UserEmail.password_reset_email(user, token_record.token) +      email = Pleroma.Emails.UserEmail.password_reset_email(user, token_record.token) +      notify_email = Pleroma.Config.get([:instance, :notify_email]) +      instance_name = Pleroma.Config.get([:instance, :name]) + +      assert_email_sent( +        from: {instance_name, notify_email}, +        to: {user.name, user.email}, +        html_body: email.html_body        )      end    end @@ -1080,7 +1116,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do      test "it confirms the user account", %{conn: conn, user: user} do        get(conn, "/api/account/confirm_email/#{user.id}/#{user.info.confirmation_token}") -      user = Repo.get(User, user.id) +      user = User.get_cached_by_id(user.id)        refute user.info.confirmation_pending        refute user.info.confirmation_token @@ -1134,7 +1170,15 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do        |> assign(:user, user)        |> post("/api/account/resend_confirmation_email?email=#{user.email}") -      Swoosh.TestAssertions.assert_email_sent(Pleroma.UserEmail.account_confirmation_email(user)) +      email = Pleroma.Emails.UserEmail.account_confirmation_email(user) +      notify_email = Pleroma.Config.get([:instance, :notify_email]) +      instance_name = Pleroma.Config.get([:instance, :name]) + +      assert_email_sent( +        from: {instance_name, notify_email}, +        to: {user.name, user.email}, +        html_body: email.html_body +      )      end    end @@ -1698,7 +1742,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do          })        assert json_response(conn, 200) == %{"status" => "success"} -      fetched_user = Repo.get(User, current_user.id) +      fetched_user = User.get_cached_by_id(current_user.id)        assert Pbkdf2.checkpw("newpass", fetched_user.password_hash) == true      end    end @@ -1739,8 +1783,8 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do        {:ok, _activity} = ActivityPub.follow(other_user, user) -      user = Repo.get(User, user.id) -      other_user = Repo.get(User, other_user.id) +      user = User.get_cached_by_id(user.id) +      other_user = User.get_cached_by_id(other_user.id)        assert User.following?(other_user, user) == false @@ -1779,8 +1823,8 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do        {:ok, _activity} = ActivityPub.follow(other_user, user) -      user = Repo.get(User, user.id) -      other_user = Repo.get(User, other_user.id) +      user = User.get_cached_by_id(user.id) +      other_user = User.get_cached_by_id(other_user.id)        assert User.following?(other_user, user) == false @@ -1802,8 +1846,8 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do        {:ok, _activity} = ActivityPub.follow(other_user, user) -      user = Repo.get(User, user.id) -      other_user = Repo.get(User, other_user.id) +      user = User.get_cached_by_id(user.id) +      other_user = User.get_cached_by_id(other_user.id)        assert User.following?(other_user, user) == false @@ -1872,7 +1916,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do    describe "POST /api/media/metadata/create" do      setup do        object = insert(:note) -      user = User.get_by_ap_id(object.data["actor"]) +      user = User.get_cached_by_ap_id(object.data["actor"])        %{object: object, user: user}      end @@ -1955,7 +1999,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do        user = refresh_record(user)        assert json_response(response, 200) == -               ActivityRepresenter.to_map(activity, %{user: user, for: user}) +               ActivityView.render("activity.json", %{user: user, for: user, activity: activity})      end    end @@ -1985,7 +2029,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do        user = refresh_record(user)        assert json_response(response, 200) == -               ActivityRepresenter.to_map(activity, %{user: user, for: user}) +               ActivityView.render("activity.json", %{user: user, for: user, activity: activity})      end    end diff --git a/test/web/twitter_api/twitter_api_test.exs b/test/web/twitter_api/twitter_api_test.exs index c8dd3fd7a..d601c8f1f 100644 --- a/test/web/twitter_api/twitter_api_test.exs +++ b/test/web/twitter_api/twitter_api_test.exs @@ -16,6 +16,11 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do    import Pleroma.Factory +  setup_all do +    Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) +    :ok +  end +    test "create a status" do      user = insert(:user)      mentioned_user = insert(:user, %{nickname: "shp", ap_id: "shp"}) @@ -36,18 +41,19 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do      input = %{        "status" => -        "Hello again, @shp.<script></script>\nThis is on another :moominmamma: line. #2hu #epic #phantasmagoric", +        "Hello again, @shp.<script></script>\nThis is on another :firefox: line. #2hu #epic #phantasmagoric",        "media_ids" => [object.id]      }      {:ok, activity = %Activity{}} = TwitterAPI.create_status(user, input) +    object = Object.normalize(activity.data["object"])      expected_text = -      "Hello again, <span class='h-card'><a data-user='#{mentioned_user.id}' class='u-url mention' href='shp'>@<span>shp</span></a></span>.<script></script><br>This is on another :moominmamma: line. <a class='hashtag' data-tag='2hu' href='http://localhost:4001/tag/2hu' rel='tag'>#2hu</a> <a class='hashtag' data-tag='epic' href='http://localhost:4001/tag/epic' rel='tag'>#epic</a> <a class='hashtag' data-tag='phantasmagoric' href='http://localhost:4001/tag/phantasmagoric' rel='tag'>#phantasmagoric</a><br><a href=\"http://example.org/image.jpg\" class='attachment'>image.jpg</a>" +      "Hello again, <span class='h-card'><a data-user='#{mentioned_user.id}' class='u-url mention' href='shp'>@<span>shp</span></a></span>.<script></script><br>This is on another :firefox: line. <a class='hashtag' data-tag='2hu' href='http://localhost:4001/tag/2hu' rel='tag'>#2hu</a> <a class='hashtag' data-tag='epic' href='http://localhost:4001/tag/epic' rel='tag'>#epic</a> <a class='hashtag' data-tag='phantasmagoric' href='http://localhost:4001/tag/phantasmagoric' rel='tag'>#phantasmagoric</a><br><a href=\"http://example.org/image.jpg\" class='attachment'>image.jpg</a>" -    assert get_in(activity.data, ["object", "content"]) == expected_text -    assert get_in(activity.data, ["object", "type"]) == "Note" -    assert get_in(activity.data, ["object", "actor"]) == user.ap_id +    assert get_in(object.data, ["content"]) == expected_text +    assert get_in(object.data, ["type"]) == "Note" +    assert get_in(object.data, ["actor"]) == user.ap_id      assert get_in(activity.data, ["actor"]) == user.ap_id      assert Enum.member?(get_in(activity.data, ["cc"]), User.ap_followers(user)) @@ -59,21 +65,20 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do      assert Enum.member?(get_in(activity.data, ["to"]), "shp")      assert activity.local == true -    assert %{"moominmamma" => "http://localhost:4001/finmoji/128px/moominmamma-128.png"} = -             activity.data["object"]["emoji"] +    assert %{"firefox" => "http://localhost:4001/emoji/Firefox.gif"} = object.data["emoji"]      # hashtags -    assert activity.data["object"]["tag"] == ["2hu", "epic", "phantasmagoric"] +    assert object.data["tag"] == ["2hu", "epic", "phantasmagoric"]      # Add a context      assert is_binary(get_in(activity.data, ["context"])) -    assert is_binary(get_in(activity.data, ["object", "context"])) +    assert is_binary(get_in(object.data, ["context"])) -    assert is_list(activity.data["object"]["attachment"]) +    assert is_list(object.data["attachment"]) -    assert activity.data["object"] == Object.get_by_ap_id(activity.data["object"]["id"]).data +    assert activity.data["object"] == object.data["id"] -    user = User.get_by_ap_id(user.ap_id) +    user = User.get_cached_by_ap_id(user.ap_id)      assert user.info.note_count == 1    end @@ -86,6 +91,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do      }      {:ok, activity = %Activity{}} = TwitterAPI.create_status(user, input) +    object = Object.normalize(activity.data["object"])      input = %{        "status" => "Here's your (you).", @@ -93,14 +99,14 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do      }      {:ok, reply = %Activity{}} = TwitterAPI.create_status(user, input) +    reply_object = Object.normalize(reply.data["object"])      assert get_in(reply.data, ["context"]) == get_in(activity.data, ["context"]) -    assert get_in(reply.data, ["object", "context"]) == -             get_in(activity.data, ["object", "context"]) +    assert get_in(reply_object.data, ["context"]) == get_in(object.data, ["context"]) -    assert get_in(reply.data, ["object", "inReplyTo"]) == get_in(activity.data, ["object", "id"]) -    assert get_in(reply.data, ["object", "inReplyToStatusId"]) == activity.id +    assert get_in(reply_object.data, ["inReplyTo"]) == get_in(activity.data, ["object"]) +    assert Activity.get_in_reply_to_activity(reply).id == activity.id    end    test "Follow another user using user_id" do @@ -123,7 +129,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do      assert User.ap_followers(followed) in user.following -    followed = User.get_by_ap_id(followed.ap_id) +    followed = User.get_cached_by_ap_id(followed.ap_id)      assert followed.info.follower_count == 1      {:error, msg} = TwitterAPI.follow(user, %{"screen_name" => followed.nickname}) @@ -275,7 +281,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do      {:ok, user} = TwitterAPI.register_user(data) -    fetched_user = Repo.get_by(User, nickname: "lain") +    fetched_user = User.get_cached_by_nickname("lain")      assert UserView.render("show.json", %{user: user}) ==               UserView.render("show.json", %{user: fetched_user}) @@ -293,13 +299,12 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do      {:ok, user} = TwitterAPI.register_user(data) -    fetched_user = Repo.get_by(User, nickname: "lain") +    fetched_user = User.get_cached_by_nickname("lain")      assert UserView.render("show.json", %{user: user}) ==               UserView.render("show.json", %{user: fetched_user})    end -  @moduletag skip: "needs 'account_activation_required: true' in config"    test "it sends confirmation email if :account_activation_required is specified in instance config" do      setting = Pleroma.Config.get([:instance, :account_activation_required]) @@ -321,7 +326,16 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do      assert user.info.confirmation_pending -    Swoosh.TestAssertions.assert_email_sent(Pleroma.UserEmail.account_confirmation_email(user)) +    email = Pleroma.Emails.UserEmail.account_confirmation_email(user) + +    notify_email = Pleroma.Config.get([:instance, :notify_email]) +    instance_name = Pleroma.Config.get([:instance, :name]) + +    Swoosh.TestAssertions.assert_email_sent( +      from: {instance_name, notify_email}, +      to: {user.name, user.email}, +      html_body: email.html_body +    )    end    test "it registers a new user and parses mentions in the bio" do @@ -353,68 +367,313 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do      assert user2.bio == expected_text    end -  @moduletag skip: "needs 'registrations_open: false' in config" -  test "it registers a new user via invite token and returns the user." do -    {:ok, token} = UserInviteToken.create_token() +  describe "register with one time token" do +    setup do +      setting = Pleroma.Config.get([:instance, :registrations_open]) -    data = %{ -      "nickname" => "vinny", -      "email" => "pasta@pizza.vs", -      "fullname" => "Vinny Vinesauce", -      "bio" => "streamer", -      "password" => "hiptofbees", -      "confirm" => "hiptofbees", -      "token" => token.token -    } +      if setting do +        Pleroma.Config.put([:instance, :registrations_open], false) +        on_exit(fn -> Pleroma.Config.put([:instance, :registrations_open], setting) end) +      end -    {:ok, user} = TwitterAPI.register_user(data) +      :ok +    end -    fetched_user = Repo.get_by(User, nickname: "vinny") -    token = Repo.get_by(UserInviteToken, token: token.token) +    test "returns user on success" do +      {:ok, invite} = UserInviteToken.create_invite() -    assert token.used == true +      data = %{ +        "nickname" => "vinny", +        "email" => "pasta@pizza.vs", +        "fullname" => "Vinny Vinesauce", +        "bio" => "streamer", +        "password" => "hiptofbees", +        "confirm" => "hiptofbees", +        "token" => invite.token +      } -    assert UserView.render("show.json", %{user: user}) == -             UserView.render("show.json", %{user: fetched_user}) +      {:ok, user} = TwitterAPI.register_user(data) + +      fetched_user = User.get_cached_by_nickname("vinny") +      invite = Repo.get_by(UserInviteToken, token: invite.token) + +      assert invite.used == true + +      assert UserView.render("show.json", %{user: user}) == +               UserView.render("show.json", %{user: fetched_user}) +    end + +    test "returns error on invalid token" do +      data = %{ +        "nickname" => "GrimReaper", +        "email" => "death@reapers.afterlife", +        "fullname" => "Reaper Grim", +        "bio" => "Your time has come", +        "password" => "scythe", +        "confirm" => "scythe", +        "token" => "DudeLetMeInImAFairy" +      } + +      {:error, msg} = TwitterAPI.register_user(data) + +      assert msg == "Invalid token" +      refute User.get_cached_by_nickname("GrimReaper") +    end + +    test "returns error on expired token" do +      {:ok, invite} = UserInviteToken.create_invite() +      UserInviteToken.update_invite!(invite, used: true) + +      data = %{ +        "nickname" => "GrimReaper", +        "email" => "death@reapers.afterlife", +        "fullname" => "Reaper Grim", +        "bio" => "Your time has come", +        "password" => "scythe", +        "confirm" => "scythe", +        "token" => invite.token +      } + +      {:error, msg} = TwitterAPI.register_user(data) + +      assert msg == "Expired token" +      refute User.get_cached_by_nickname("GrimReaper") +    end    end -  @moduletag skip: "needs 'registrations_open: false' in config" -  test "it returns an error if invalid token submitted" do -    data = %{ -      "nickname" => "GrimReaper", -      "email" => "death@reapers.afterlife", -      "fullname" => "Reaper Grim", -      "bio" => "Your time has come", -      "password" => "scythe", -      "confirm" => "scythe", -      "token" => "DudeLetMeInImAFairy" -    } +  describe "registers with date limited token" do +    setup do +      setting = Pleroma.Config.get([:instance, :registrations_open]) + +      if setting do +        Pleroma.Config.put([:instance, :registrations_open], false) +        on_exit(fn -> Pleroma.Config.put([:instance, :registrations_open], setting) end) +      end + +      data = %{ +        "nickname" => "vinny", +        "email" => "pasta@pizza.vs", +        "fullname" => "Vinny Vinesauce", +        "bio" => "streamer", +        "password" => "hiptofbees", +        "confirm" => "hiptofbees" +      } + +      check_fn = fn invite -> +        data = Map.put(data, "token", invite.token) +        {:ok, user} = TwitterAPI.register_user(data) +        fetched_user = User.get_cached_by_nickname("vinny") + +        assert UserView.render("show.json", %{user: user}) == +                 UserView.render("show.json", %{user: fetched_user}) +      end + +      {:ok, data: data, check_fn: check_fn} +    end + +    test "returns user on success", %{check_fn: check_fn} do +      {:ok, invite} = UserInviteToken.create_invite(%{expires_at: Date.utc_today()}) + +      check_fn.(invite) + +      invite = Repo.get_by(UserInviteToken, token: invite.token) + +      refute invite.used +    end + +    test "returns user on token which expired tomorrow", %{check_fn: check_fn} do +      {:ok, invite} = UserInviteToken.create_invite(%{expires_at: Date.add(Date.utc_today(), 1)}) -    {:error, msg} = TwitterAPI.register_user(data) +      check_fn.(invite) -    assert msg == "Invalid token" -    refute Repo.get_by(User, nickname: "GrimReaper") +      invite = Repo.get_by(UserInviteToken, token: invite.token) + +      refute invite.used +    end + +    test "returns an error on overdue date", %{data: data} do +      {:ok, invite} = UserInviteToken.create_invite(%{expires_at: Date.add(Date.utc_today(), -1)}) + +      data = Map.put(data, "token", invite.token) + +      {:error, msg} = TwitterAPI.register_user(data) + +      assert msg == "Expired token" +      refute User.get_cached_by_nickname("vinny") +      invite = Repo.get_by(UserInviteToken, token: invite.token) + +      refute invite.used +    end    end -  @moduletag skip: "needs 'registrations_open: false' in config" -  test "it returns an error if expired token submitted" do -    {:ok, token} = UserInviteToken.create_token() -    UserInviteToken.mark_as_used(token.token) +  describe "registers with reusable token" do +    setup do +      setting = Pleroma.Config.get([:instance, :registrations_open]) -    data = %{ -      "nickname" => "GrimReaper", -      "email" => "death@reapers.afterlife", -      "fullname" => "Reaper Grim", -      "bio" => "Your time has come", -      "password" => "scythe", -      "confirm" => "scythe", -      "token" => token.token -    } +      if setting do +        Pleroma.Config.put([:instance, :registrations_open], false) +        on_exit(fn -> Pleroma.Config.put([:instance, :registrations_open], setting) end) +      end -    {:error, msg} = TwitterAPI.register_user(data) +      :ok +    end + +    test "returns user on success, after him registration fails" do +      {:ok, invite} = UserInviteToken.create_invite(%{max_use: 100}) + +      UserInviteToken.update_invite!(invite, uses: 99) + +      data = %{ +        "nickname" => "vinny", +        "email" => "pasta@pizza.vs", +        "fullname" => "Vinny Vinesauce", +        "bio" => "streamer", +        "password" => "hiptofbees", +        "confirm" => "hiptofbees", +        "token" => invite.token +      } + +      {:ok, user} = TwitterAPI.register_user(data) +      fetched_user = User.get_cached_by_nickname("vinny") +      invite = Repo.get_by(UserInviteToken, token: invite.token) + +      assert invite.used == true -    assert msg == "Expired token" -    refute Repo.get_by(User, nickname: "GrimReaper") +      assert UserView.render("show.json", %{user: user}) == +               UserView.render("show.json", %{user: fetched_user}) + +      data = %{ +        "nickname" => "GrimReaper", +        "email" => "death@reapers.afterlife", +        "fullname" => "Reaper Grim", +        "bio" => "Your time has come", +        "password" => "scythe", +        "confirm" => "scythe", +        "token" => invite.token +      } + +      {:error, msg} = TwitterAPI.register_user(data) + +      assert msg == "Expired token" +      refute User.get_cached_by_nickname("GrimReaper") +    end +  end + +  describe "registers with reusable date limited token" do +    setup do +      setting = Pleroma.Config.get([:instance, :registrations_open]) + +      if setting do +        Pleroma.Config.put([:instance, :registrations_open], false) +        on_exit(fn -> Pleroma.Config.put([:instance, :registrations_open], setting) end) +      end + +      :ok +    end + +    test "returns user on success" do +      {:ok, invite} = UserInviteToken.create_invite(%{expires_at: Date.utc_today(), max_use: 100}) + +      data = %{ +        "nickname" => "vinny", +        "email" => "pasta@pizza.vs", +        "fullname" => "Vinny Vinesauce", +        "bio" => "streamer", +        "password" => "hiptofbees", +        "confirm" => "hiptofbees", +        "token" => invite.token +      } + +      {:ok, user} = TwitterAPI.register_user(data) +      fetched_user = User.get_cached_by_nickname("vinny") +      invite = Repo.get_by(UserInviteToken, token: invite.token) + +      refute invite.used + +      assert UserView.render("show.json", %{user: user}) == +               UserView.render("show.json", %{user: fetched_user}) +    end + +    test "error after max uses" do +      {:ok, invite} = UserInviteToken.create_invite(%{expires_at: Date.utc_today(), max_use: 100}) + +      UserInviteToken.update_invite!(invite, uses: 99) + +      data = %{ +        "nickname" => "vinny", +        "email" => "pasta@pizza.vs", +        "fullname" => "Vinny Vinesauce", +        "bio" => "streamer", +        "password" => "hiptofbees", +        "confirm" => "hiptofbees", +        "token" => invite.token +      } + +      {:ok, user} = TwitterAPI.register_user(data) +      fetched_user = User.get_cached_by_nickname("vinny") +      invite = Repo.get_by(UserInviteToken, token: invite.token) +      assert invite.used == true + +      assert UserView.render("show.json", %{user: user}) == +               UserView.render("show.json", %{user: fetched_user}) + +      data = %{ +        "nickname" => "GrimReaper", +        "email" => "death@reapers.afterlife", +        "fullname" => "Reaper Grim", +        "bio" => "Your time has come", +        "password" => "scythe", +        "confirm" => "scythe", +        "token" => invite.token +      } + +      {:error, msg} = TwitterAPI.register_user(data) + +      assert msg == "Expired token" +      refute User.get_cached_by_nickname("GrimReaper") +    end + +    test "returns error on overdue date" do +      {:ok, invite} = +        UserInviteToken.create_invite(%{expires_at: Date.add(Date.utc_today(), -1), max_use: 100}) + +      data = %{ +        "nickname" => "GrimReaper", +        "email" => "death@reapers.afterlife", +        "fullname" => "Reaper Grim", +        "bio" => "Your time has come", +        "password" => "scythe", +        "confirm" => "scythe", +        "token" => invite.token +      } + +      {:error, msg} = TwitterAPI.register_user(data) + +      assert msg == "Expired token" +      refute User.get_cached_by_nickname("GrimReaper") +    end + +    test "returns error on with overdue date and after max" do +      {:ok, invite} = +        UserInviteToken.create_invite(%{expires_at: Date.add(Date.utc_today(), -1), max_use: 100}) + +      UserInviteToken.update_invite!(invite, uses: 100) + +      data = %{ +        "nickname" => "GrimReaper", +        "email" => "death@reapers.afterlife", +        "fullname" => "Reaper Grim", +        "bio" => "Your time has come", +        "password" => "scythe", +        "confirm" => "scythe", +        "token" => invite.token +      } + +      {:error, msg} = TwitterAPI.register_user(data) + +      assert msg == "Expired token" +      refute User.get_cached_by_nickname("GrimReaper") +    end    end    test "it returns the error on registration problems" do @@ -429,7 +688,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do      {:error, error_object} = TwitterAPI.register_user(data)      assert is_binary(error_object[:error]) -    refute Repo.get_by(User, nickname: "lain") +    refute User.get_cached_by_nickname("lain")    end    test "it assigns an integer conversation_id" do @@ -445,28 +704,12 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do      :ok    end -  describe "context_to_conversation_id" do -    test "creates a mapping object" do -      conversation_id = TwitterAPI.context_to_conversation_id("random context") -      object = Object.get_by_ap_id("random context") - -      assert conversation_id == object.id -    end - -    test "returns an existing mapping for an existing object" do -      {:ok, object} = Object.context_mapping("random context") |> Repo.insert() -      conversation_id = TwitterAPI.context_to_conversation_id("random context") - -      assert conversation_id == object.id -    end -  end -    describe "fetching a user by uri" do      test "fetches a user by uri" do        id = "https://mastodon.social/users/lambadalambda"        user = insert(:user)        {:ok, represented} = TwitterAPI.get_external_profile(user, id) -      remote = User.get_by_ap_id(id) +      remote = User.get_cached_by_ap_id(id)        assert represented["id"] == UserView.render("show.json", %{user: remote, for: user})["id"] diff --git a/test/web/twitter_api/util_controller_test.exs b/test/web/twitter_api/util_controller_test.exs index fc762ab18..56474447b 100644 --- a/test/web/twitter_api/util_controller_test.exs +++ b/test/web/twitter_api/util_controller_test.exs @@ -1,8 +1,17 @@  defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do    use Pleroma.Web.ConnCase +  alias Pleroma.Notification +  alias Pleroma.Repo +  alias Pleroma.User +  alias Pleroma.Web.CommonAPI    import Pleroma.Factory +  setup do +    Tesla.Mock.mock(fn env -> apply(HttpRequestMock, :request, [env]) end) +    :ok +  end +    describe "POST /api/pleroma/follow_import" do      test "it returns HTTP 200", %{conn: conn} do        user1 = insert(:user) @@ -17,6 +26,21 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do        assert response == "job started"      end +    test "it imports new-style mastodon follow lists", %{conn: conn} do +      user1 = insert(:user) +      user2 = insert(:user) + +      response = +        conn +        |> assign(:user, user1) +        |> 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' permission", %{conn: conn} do        token1 = insert(:oauth_token, scopes: ["read", "write"])        token2 = insert(:oauth_token, scopes: ["follow"]) @@ -52,7 +76,69 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do      end    end +  describe "POST /api/pleroma/notifications/read" do +    test "it marks a single notification as read", %{conn: conn} do +      user1 = insert(:user) +      user2 = insert(:user) +      {:ok, activity1} = CommonAPI.post(user2, %{"status" => "hi @#{user1.nickname}"}) +      {:ok, activity2} = CommonAPI.post(user2, %{"status" => "hi @#{user1.nickname}"}) +      {:ok, [notification1]} = Notification.create_notifications(activity1) +      {:ok, [notification2]} = Notification.create_notifications(activity2) + +      conn +      |> assign(:user, user1) +      |> post("/api/pleroma/notifications/read", %{"id" => "#{notification1.id}"}) +      |> json_response(:ok) + +      assert Repo.get(Notification, notification1.id).seen +      refute Repo.get(Notification, notification2.id).seen +    end +  end + +  describe "PUT /api/pleroma/notification_settings" do +    test "it updates notification settings", %{conn: conn} do +      user = insert(:user) + +      conn +      |> assign(:user, user) +      |> put("/api/pleroma/notification_settings", %{ +        "remote" => false, +        "followers" => false, +        "bar" => 1 +      }) +      |> json_response(:ok) + +      user = Repo.get(User, user.id) + +      assert %{"remote" => false, "local" => true, "followers" => false, "follows" => true} == +               user.info.notification_settings +    end +  end +    describe "GET /api/statusnet/config.json" do +    test "returns the state of safe_dm_mentions flag", %{conn: conn} do +      option = Pleroma.Config.get([:instance, :safe_dm_mentions]) +      Pleroma.Config.put([:instance, :safe_dm_mentions], true) + +      response = +        conn +        |> get("/api/statusnet/config.json") +        |> json_response(:ok) + +      assert response["site"]["safeDMMentionsEnabled"] == "1" + +      Pleroma.Config.put([:instance, :safe_dm_mentions], false) + +      response = +        conn +        |> get("/api/statusnet/config.json") +        |> json_response(:ok) + +      assert response["site"]["safeDMMentionsEnabled"] == "0" + +      Pleroma.Config.put([:instance, :safe_dm_mentions], option) +    end +      test "it returns the managed config", %{conn: conn} do        Pleroma.Config.put([:instance, :managed_config], false)        Pleroma.Config.put([:fe], theme: "rei-ayanami-towel") @@ -119,4 +205,50 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do        assert response == Jason.encode!(config |> Enum.into(%{})) |> Jason.decode!()      end    end + +  describe "/api/pleroma/emoji" do +    test "returns json with custom emoji with tags", %{conn: conn} do +      emoji = +        conn +        |> get("/api/pleroma/emoji") +        |> json_response(200) + +      assert Enum.all?(emoji, fn +               {_key, +                %{ +                  "image_url" => url, +                  "tags" => tags +                }} -> +                 is_binary(url) and is_list(tags) +             end) +    end +  end + +  describe "GET /ostatus_subscribe?acct=...." do +    test "adds status to pleroma instance if the `acct` is a status", %{conn: conn} do +      conn = +        get( +          conn, +          "/ostatus_subscribe?acct=https://mastodon.social/users/emelie/statuses/101849165031453009" +        ) + +      assert redirected_to(conn) =~ "/notice/" +    end + +    test "show follow account page if the `acct` is a account link", %{conn: conn} do +      response = +        get( +          conn, +          "/ostatus_subscribe?acct=https://mastodon.social/users/emelie" +        ) + +      assert html_response(response, 200) =~ "Log in to follow" +    end +  end + +  test "GET /api/pleroma/healthcheck", %{conn: conn} do +    conn = get(conn, "/api/pleroma/healthcheck") + +    assert conn.status in [200, 503] +  end  end diff --git a/test/web/twitter_api/views/activity_view_test.exs b/test/web/twitter_api/views/activity_view_test.exs index 6f0786b1c..d84ab7420 100644 --- a/test/web/twitter_api/views/activity_view_test.exs +++ b/test/web/twitter_api/views/activity_view_test.exs @@ -6,13 +6,13 @@ defmodule Pleroma.Web.TwitterAPI.ActivityViewTest do    use Pleroma.DataCase    alias Pleroma.Activity +  alias Pleroma.Object    alias Pleroma.Repo    alias Pleroma.User    alias Pleroma.Web.ActivityPub.ActivityPub    alias Pleroma.Web.CommonAPI    alias Pleroma.Web.CommonAPI.Utils    alias Pleroma.Web.TwitterAPI.ActivityView -  alias Pleroma.Web.TwitterAPI.TwitterAPI    alias Pleroma.Web.TwitterAPI.UserView    import Pleroma.Factory @@ -82,7 +82,7 @@ defmodule Pleroma.Web.TwitterAPI.ActivityViewTest do      result = ActivityView.render("activity.json", activity: activity)      assert result["statusnet_html"] == -             "<a class=\"hashtag\" data-tag=\"bike\" href=\"http://localhost:4001/tag/bike\">#Bike</a> log - Commute Tuesday<br /><a href=\"https://pla.bike/posts/20181211/\">https://pla.bike/posts/20181211/</a><br /><a class=\"hashtag\" data-tag=\"cycling\" href=\"http://localhost:4001/tag/cycling\">#cycling</a> <a class=\"hashtag\" data-tag=\"chscycling\" href=\"http://localhost:4001/tag/chscycling\">#CHScycling</a> <a class=\"hashtag\" data-tag=\"commute\" href=\"http://localhost:4001/tag/commute\">#commute</a><br />MVIMG_20181211_054020.jpg" +             "<a class=\"hashtag\" data-tag=\"bike\" href=\"http://localhost:4001/tag/bike\" rel=\"tag\">#Bike</a> log - Commute Tuesday<br /><a href=\"https://pla.bike/posts/20181211/\">https://pla.bike/posts/20181211/</a><br /><a class=\"hashtag\" data-tag=\"cycling\" href=\"http://localhost:4001/tag/cycling\" rel=\"tag\">#cycling</a> <a class=\"hashtag\" data-tag=\"chscycling\" href=\"http://localhost:4001/tag/chscycling\" rel=\"tag\">#CHScycling</a> <a class=\"hashtag\" data-tag=\"commute\" href=\"http://localhost:4001/tag/commute\" rel=\"tag\">#commute</a><br />MVIMG_20181211_054020.jpg"      assert result["text"] ==               "#Bike log - Commute Tuesday\nhttps://pla.bike/posts/20181211/\n#cycling #CHScycling #commute\nMVIMG_20181211_054020.jpg" @@ -91,16 +91,16 @@ defmodule Pleroma.Web.TwitterAPI.ActivityViewTest do    test "a create activity with a summary containing emoji" do      {:ok, activity} =        CommonAPI.post(insert(:user), %{ -        "spoiler_text" => ":woollysocks: meow", +        "spoiler_text" => ":firefox: meow",          "status" => "."        })      result = ActivityView.render("activity.json", activity: activity) -    expected = ":woollysocks: meow" +    expected = ":firefox: meow"      expected_html = -      "<img height=\"32px\" width=\"32px\" alt=\"woollysocks\" title=\"woollysocks\" src=\"http://localhost:4001/finmoji/128px/woollysocks-128.png\" /> meow" +      "<img height=\"32px\" width=\"32px\" alt=\"firefox\" title=\"firefox\" src=\"http://localhost:4001/emoji/Firefox.gif\" /> meow"      assert result["summary"] == expected      assert result["summary_html"] == expected_html @@ -126,10 +126,11 @@ defmodule Pleroma.Web.TwitterAPI.ActivityViewTest do      other_user = insert(:user, %{nickname: "shp"})      {:ok, activity} = CommonAPI.post(user, %{"status" => "Hey @shp!", "visibility" => "direct"}) +    object = Object.normalize(activity.data["object"])      result = ActivityView.render("activity.json", activity: activity) -    convo_id = TwitterAPI.context_to_conversation_id(activity.data["object"]["context"]) +    convo_id = Utils.context_to_conversation_id(object.data["context"])      expected = %{        "activity_type" => "post", @@ -137,8 +138,8 @@ defmodule Pleroma.Web.TwitterAPI.ActivityViewTest do        "attentions" => [          UserView.render("show.json", %{user: other_user})        ], -      "created_at" => activity.data["object"]["published"] |> Utils.date_to_asctime(), -      "external_url" => activity.data["object"]["id"], +      "created_at" => object.data["published"] |> Utils.date_to_asctime(), +      "external_url" => object.data["id"],        "fave_num" => 0,        "favorited" => false,        "id" => activity.id, @@ -162,7 +163,7 @@ defmodule Pleroma.Web.TwitterAPI.ActivityViewTest do          }\">@<span>shp</span></a></span>!",        "tags" => [],        "text" => "Hey @shp!", -      "uri" => activity.data["object"]["id"], +      "uri" => object.data["id"],        "user" => UserView.render("show.json", %{user: user}),        "visibility" => "direct",        "card" => nil, @@ -176,13 +177,14 @@ defmodule Pleroma.Web.TwitterAPI.ActivityViewTest do      user = insert(:user)      other_user = insert(:user, %{nickname: "shp"})      {:ok, activity} = CommonAPI.post(user, %{"status" => "Hey @shp!"}) +    object = Object.normalize(activity.data["object"]) -    convo_id = TwitterAPI.context_to_conversation_id(activity.data["object"]["context"]) +    convo_id = Utils.context_to_conversation_id(object.data["context"])      mocks = [        { -        TwitterAPI, -        [], +        Utils, +        [:passthrough],          [context_to_conversation_id: fn _ -> false end]        },        { @@ -197,7 +199,7 @@ defmodule Pleroma.Web.TwitterAPI.ActivityViewTest do        assert result["statusnet_conversation_id"] == convo_id        assert result["user"] -      refute called(TwitterAPI.context_to_conversation_id(:_)) +      refute called(Utils.context_to_conversation_id(:_))        refute called(User.get_cached_by_ap_id(user.ap_id))        refute called(User.get_cached_by_ap_id(other_user.ap_id))      end @@ -278,11 +280,11 @@ defmodule Pleroma.Web.TwitterAPI.ActivityViewTest do      other_user = insert(:user, %{nickname: "shp"})      {:ok, activity} = CommonAPI.post(user, %{"status" => "Hey @shp!"}) -    {:ok, announce, _object} = CommonAPI.repeat(activity.id, other_user) +    {:ok, announce, object} = CommonAPI.repeat(activity.id, other_user) -    convo_id = TwitterAPI.context_to_conversation_id(activity.data["object"]["context"]) +    convo_id = Utils.context_to_conversation_id(object.data["context"]) -    activity = Repo.get(Activity, activity.id) +    activity = Activity.get_by_id(activity.id)      result = ActivityView.render("activity.json", activity: announce) @@ -358,7 +360,7 @@ defmodule Pleroma.Web.TwitterAPI.ActivityViewTest do    test "a peertube video" do      {:ok, object} = -      ActivityPub.fetch_object_from_id( +      Pleroma.Object.Fetcher.fetch_object_from_id(          "https://peertube.moe/videos/watch/df5f464b-be8d-46fb-ad81-2d4c2d1630e3"        ) diff --git a/test/web/twitter_api/views/user_view_test.exs b/test/web/twitter_api/views/user_view_test.exs index 4e7f94795..c99dbddeb 100644 --- a/test/web/twitter_api/views/user_view_test.exs +++ b/test/web/twitter_api/views/user_view_test.exs @@ -89,29 +89,34 @@ defmodule Pleroma.Web.TwitterAPI.UserViewTest do        "following" => false,        "follows_you" => false,        "statusnet_blocking" => false, -      "rights" => %{ -        "delete_others_notice" => false, -        "admin" => false -      },        "statusnet_profile_url" => user.ap_id,        "cover_photo" => banner,        "background_image" => nil,        "is_local" => true,        "locked" => false, -      "default_scope" => "public", -      "no_rich_text" => false,        "hide_follows" => false,        "hide_followers" => false,        "fields" => [],        "pleroma" => %{          "confirmation_pending" => false,          "tags" => [] -      } +      }, +      "rights" => %{"admin" => false, "delete_others_notice" => false}, +      "role" => "member"      }      assert represented == UserView.render("show.json", %{user: user})    end +  test "User exposes settings for themselves and only for themselves", %{user: user} do +    as_user = UserView.render("show.json", %{user: user, for: user}) +    assert as_user["default_scope"] == user.info.default_scope +    assert as_user["no_rich_text"] == user.info.no_rich_text +    as_stranger = UserView.render("show.json", %{user: user}) +    refute as_stranger["default_scope"] +    refute as_stranger["no_rich_text"] +  end +    test "A user for a given other follower", %{user: user} do      follower = insert(:user, %{following: [User.ap_followers(user)]})      {:ok, user} = User.update_follower_count(user) @@ -137,24 +142,20 @@ defmodule Pleroma.Web.TwitterAPI.UserViewTest do        "following" => true,        "follows_you" => false,        "statusnet_blocking" => false, -      "rights" => %{ -        "delete_others_notice" => false, -        "admin" => false -      },        "statusnet_profile_url" => user.ap_id,        "cover_photo" => banner,        "background_image" => nil,        "is_local" => true,        "locked" => false, -      "default_scope" => "public", -      "no_rich_text" => false,        "hide_follows" => false,        "hide_followers" => false,        "fields" => [],        "pleroma" => %{          "confirmation_pending" => false,          "tags" => [] -      } +      }, +      "rights" => %{"admin" => false, "delete_others_notice" => false}, +      "role" => "member"      }      assert represented == UserView.render("show.json", %{user: user, for: follower}) @@ -186,24 +187,20 @@ defmodule Pleroma.Web.TwitterAPI.UserViewTest do        "following" => false,        "follows_you" => true,        "statusnet_blocking" => false, -      "rights" => %{ -        "delete_others_notice" => false, -        "admin" => false -      },        "statusnet_profile_url" => follower.ap_id,        "cover_photo" => banner,        "background_image" => nil,        "is_local" => true,        "locked" => false, -      "default_scope" => "public", -      "no_rich_text" => false,        "hide_follows" => false,        "hide_followers" => false,        "fields" => [],        "pleroma" => %{          "confirmation_pending" => false,          "tags" => [] -      } +      }, +      "rights" => %{"admin" => false, "delete_others_notice" => false}, +      "role" => "member"      }      assert represented == UserView.render("show.json", %{user: follower, for: user}) @@ -272,27 +269,23 @@ defmodule Pleroma.Web.TwitterAPI.UserViewTest do        "following" => false,        "follows_you" => false,        "statusnet_blocking" => true, -      "rights" => %{ -        "delete_others_notice" => false, -        "admin" => false -      },        "statusnet_profile_url" => user.ap_id,        "cover_photo" => banner,        "background_image" => nil,        "is_local" => true,        "locked" => false, -      "default_scope" => "public", -      "no_rich_text" => false,        "hide_follows" => false,        "hide_followers" => false,        "fields" => [],        "pleroma" => %{          "confirmation_pending" => false,          "tags" => [] -      } +      }, +      "rights" => %{"admin" => false, "delete_others_notice" => false}, +      "role" => "member"      } -    blocker = Repo.get(User, blocker.id) +    blocker = User.get_cached_by_id(blocker.id)      assert represented == UserView.render("show.json", %{user: user, for: blocker})    end  | 
