diff options
author | kPherox <admin@mail.kr-kp.com> | 2019-10-01 01:39:22 +0900 |
---|---|---|
committer | kPherox <admin@mail.kr-kp.com> | 2019-10-01 01:40:33 +0900 |
commit | a0f101ee806af06bcd4271cd8d57d11ff85ea11a (patch) | |
tree | 2cd3c5d1a645be1395c57ec5616f31afb4b68da7 /test/web/mastodon_api/views | |
parent | 8ca4f145a51e92c9f3a6c374ceddfac22ea300d9 (diff) | |
parent | 7c9b023a918c84b60ae6547289a083c671a3659b (diff) | |
download | pleroma-a0f101ee806af06bcd4271cd8d57d11ff85ea11a.tar.gz pleroma-a0f101ee806af06bcd4271cd8d57d11ff85ea11a.zip |
Merge remote-tracking branch 'upstream/develop' into fix-prameter-name-of-accounts-update-credentials
Diffstat (limited to 'test/web/mastodon_api/views')
-rw-r--r-- | test/web/mastodon_api/views/account_view_test.exs | 497 | ||||
-rw-r--r-- | test/web/mastodon_api/views/conversation_view_test.exs | 34 | ||||
-rw-r--r-- | test/web/mastodon_api/views/list_view_test.exs | 32 | ||||
-rw-r--r-- | test/web/mastodon_api/views/notification_view_test.exs | 104 | ||||
-rw-r--r-- | test/web/mastodon_api/views/push_subscription_view_test.exs | 23 | ||||
-rw-r--r-- | test/web/mastodon_api/views/scheduled_activity_view_test.exs | 68 | ||||
-rw-r--r-- | test/web/mastodon_api/views/status_view_test.exs | 620 |
7 files changed, 1378 insertions, 0 deletions
diff --git a/test/web/mastodon_api/views/account_view_test.exs b/test/web/mastodon_api/views/account_view_test.exs new file mode 100644 index 000000000..62b2ab7e3 --- /dev/null +++ b/test/web/mastodon_api/views/account_view_test.exs @@ -0,0 +1,497 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.AccountViewTest do + use Pleroma.DataCase + import Pleroma.Factory + alias Pleroma.User + alias Pleroma.Web.CommonAPI + alias Pleroma.Web.MastodonAPI.AccountView + + test "Represent a user account" do + source_data = %{ + "tag" => [ + %{ + "type" => "Emoji", + "icon" => %{"url" => "/file.png"}, + "name" => ":karjalanpiirakka:" + } + ] + } + + background_image = %{ + "url" => [%{"href" => "https://example.com/images/asuka_hospital.png"}] + } + + user = + insert(:user, %{ + info: %{ + note_count: 5, + follower_count: 3, + source_data: source_data, + background: background_image + }, + nickname: "shp@shitposter.club", + name: ":karjalanpiirakka: shp", + bio: "<script src=\"invalid-html\"></script><span>valid html</span>", + inserted_at: ~N[2017-08-15 15:47:06.597036] + }) + + expected = %{ + id: to_string(user.id), + username: "shp", + acct: user.nickname, + display_name: user.name, + locked: false, + created_at: "2017-08-15T15:47:06.000Z", + followers_count: 3, + following_count: 0, + statuses_count: 5, + note: "<span>valid html</span>", + url: user.ap_id, + avatar: "http://localhost:4001/images/avi.png", + avatar_static: "http://localhost:4001/images/avi.png", + header: "http://localhost:4001/images/banner.png", + header_static: "http://localhost:4001/images/banner.png", + emojis: [ + %{ + "static_url" => "/file.png", + "url" => "/file.png", + "shortcode" => "karjalanpiirakka", + "visible_in_picker" => false + } + ], + fields: [], + bot: false, + source: %{ + note: "valid html", + sensitive: false, + pleroma: %{ + discoverable: false + }, + fields: [] + }, + pleroma: %{ + background_image: "https://example.com/images/asuka_hospital.png", + confirmation_pending: false, + tags: [], + is_admin: false, + is_moderator: false, + hide_favorites: true, + hide_followers: false, + hide_follows: false, + hide_followers_count: false, + hide_follows_count: false, + relationship: %{}, + skip_thread_containment: false + } + } + + assert expected == AccountView.render("show.json", %{user: user}) + end + + test "Represent the user account for the account owner" do + user = insert(:user) + + notification_settings = %{ + "followers" => true, + "follows" => true, + "non_follows" => true, + "non_followers" => true + } + + privacy = user.info.default_scope + + assert %{ + pleroma: %{notification_settings: ^notification_settings}, + source: %{privacy: ^privacy} + } = AccountView.render("show.json", %{user: user, for: user}) + end + + test "Represent a Service(bot) account" do + user = + insert(:user, %{ + info: %{note_count: 5, follower_count: 3, source_data: %{"type" => "Service"}}, + nickname: "shp@shitposter.club", + inserted_at: ~N[2017-08-15 15:47:06.597036] + }) + + expected = %{ + id: to_string(user.id), + username: "shp", + acct: user.nickname, + display_name: user.name, + locked: false, + created_at: "2017-08-15T15:47:06.000Z", + followers_count: 3, + following_count: 0, + statuses_count: 5, + note: user.bio, + url: user.ap_id, + avatar: "http://localhost:4001/images/avi.png", + avatar_static: "http://localhost:4001/images/avi.png", + header: "http://localhost:4001/images/banner.png", + header_static: "http://localhost:4001/images/banner.png", + emojis: [], + fields: [], + bot: true, + source: %{ + note: user.bio, + sensitive: false, + pleroma: %{ + discoverable: false + }, + fields: [] + }, + pleroma: %{ + background_image: nil, + confirmation_pending: false, + tags: [], + is_admin: false, + is_moderator: false, + hide_favorites: true, + hide_followers: false, + hide_follows: false, + hide_followers_count: false, + hide_follows_count: false, + relationship: %{}, + skip_thread_containment: false + } + } + + assert expected == AccountView.render("show.json", %{user: user}) + end + + test "Represent a deactivated user for an admin" do + admin = insert(:user, %{info: %{is_admin: true}}) + deactivated_user = insert(:user, %{info: %{deactivated: true}}) + represented = AccountView.render("show.json", %{user: deactivated_user, for: admin}) + assert represented[:pleroma][:deactivated] == true + end + + test "Represent a smaller mention" do + user = insert(:user) + + expected = %{ + id: to_string(user.id), + acct: user.nickname, + username: user.nickname, + url: user.ap_id + } + + assert expected == AccountView.render("mention.json", %{user: user}) + end + + describe "relationship" do + test "represent a relationship for the following and followed user" do + user = insert(:user) + other_user = insert(:user) + + {:ok, user} = User.follow(user, other_user) + {:ok, other_user} = User.follow(other_user, user) + {:ok, other_user} = User.subscribe(user, other_user) + {:ok, user} = User.mute(user, other_user, true) + {:ok, user} = CommonAPI.hide_reblogs(user, other_user) + + expected = %{ + id: to_string(other_user.id), + following: true, + followed_by: true, + blocking: false, + blocked_by: false, + muting: true, + muting_notifications: true, + subscribing: true, + requested: false, + domain_blocking: false, + showing_reblogs: false, + endorsed: false + } + + assert expected == + AccountView.render("relationship.json", %{user: user, target: other_user}) + end + + test "represent a relationship for the blocking and blocked user" do + user = insert(:user) + other_user = insert(:user) + + {:ok, user} = User.follow(user, other_user) + {:ok, other_user} = User.subscribe(user, other_user) + {:ok, user} = User.block(user, other_user) + {:ok, other_user} = User.block(other_user, user) + + expected = %{ + id: to_string(other_user.id), + following: false, + followed_by: false, + blocking: true, + blocked_by: true, + muting: false, + muting_notifications: false, + subscribing: false, + requested: false, + domain_blocking: false, + showing_reblogs: true, + endorsed: false + } + + assert expected == + AccountView.render("relationship.json", %{user: user, target: other_user}) + end + + test "represent a relationship for the user blocking a domain" do + user = insert(:user) + other_user = insert(:user, ap_id: "https://bad.site/users/other_user") + + {:ok, user} = User.block_domain(user, "bad.site") + + assert %{domain_blocking: true, blocking: false} = + AccountView.render("relationship.json", %{user: user, target: other_user}) + end + + test "represent a relationship for the user with a pending follow request" do + user = insert(:user) + other_user = insert(:user, %{info: %User.Info{locked: true}}) + + {:ok, user, other_user, _} = CommonAPI.follow(user, other_user) + user = User.get_cached_by_id(user.id) + other_user = User.get_cached_by_id(other_user.id) + + expected = %{ + id: to_string(other_user.id), + following: false, + followed_by: false, + blocking: false, + blocked_by: false, + muting: false, + muting_notifications: false, + subscribing: false, + requested: true, + domain_blocking: false, + showing_reblogs: true, + endorsed: false + } + + assert expected == + AccountView.render("relationship.json", %{user: user, target: other_user}) + end + end + + test "represent an embedded relationship" do + user = + insert(:user, %{ + 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), + username: "shp", + acct: user.nickname, + display_name: user.name, + locked: false, + created_at: "2017-08-15T15:47:06.000Z", + followers_count: 1, + following_count: 0, + statuses_count: 5, + note: user.bio, + url: user.ap_id, + avatar: "http://localhost:4001/images/avi.png", + avatar_static: "http://localhost:4001/images/avi.png", + header: "http://localhost:4001/images/banner.png", + header_static: "http://localhost:4001/images/banner.png", + emojis: [], + fields: [], + bot: true, + source: %{ + note: user.bio, + sensitive: false, + pleroma: %{ + discoverable: false + }, + fields: [] + }, + pleroma: %{ + background_image: nil, + confirmation_pending: false, + tags: [], + is_admin: false, + is_moderator: false, + hide_favorites: true, + hide_followers: false, + hide_follows: false, + hide_followers_count: false, + hide_follows_count: false, + relationship: %{ + id: to_string(user.id), + following: false, + followed_by: false, + blocking: true, + blocked_by: false, + subscribing: false, + muting: false, + muting_notifications: false, + requested: false, + domain_blocking: false, + showing_reblogs: true, + endorsed: false + }, + skip_thread_containment: false + } + } + + assert expected == AccountView.render("show.json", %{user: user, for: other_user}) + end + + test "returns the settings store if the requesting user is the represented user and it's requested specifically" do + user = insert(:user, %{info: %User.Info{pleroma_settings_store: %{fe: "test"}}}) + + result = + AccountView.render("show.json", %{user: user, for: user, with_pleroma_settings: true}) + + assert result.pleroma.settings_store == %{:fe => "test"} + + result = AccountView.render("show.json", %{user: user, with_pleroma_settings: true}) + assert result.pleroma[:settings_store] == nil + + result = AccountView.render("show.json", %{user: user, for: user}) + assert result.pleroma[:settings_store] == nil + end + + test "sanitizes display names" do + user = insert(:user, name: "<marquee> username </marquee>") + result = AccountView.render("show.json", %{user: user}) + refute result.display_name == "<marquee> username </marquee>" + end + + describe "hiding follows/following" do + test "shows when follows/followers stats are hidden and sets follow/follower count to 0" do + info = %{ + hide_followers: true, + hide_followers_count: true, + hide_follows: true, + hide_follows_count: true + } + + user = insert(:user, info: info) + + other_user = insert(:user) + {:ok, user, other_user, _activity} = CommonAPI.follow(user, other_user) + {:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user) + + assert %{ + followers_count: 0, + following_count: 0, + pleroma: %{hide_follows_count: true, hide_followers_count: true} + } = AccountView.render("show.json", %{user: user}) + end + + test "shows when follows/followers are hidden" do + user = insert(:user, info: %{hide_followers: true, hide_follows: true}) + other_user = insert(:user) + {:ok, user, other_user, _activity} = CommonAPI.follow(user, other_user) + {:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user) + + assert %{ + followers_count: 1, + following_count: 1, + pleroma: %{hide_follows: true, hide_followers: true} + } = AccountView.render("show.json", %{user: user}) + end + + test "shows actual follower/following count to the account owner" do + user = insert(:user, info: %{hide_followers: true, hide_follows: true}) + other_user = insert(:user) + {:ok, user, other_user, _activity} = CommonAPI.follow(user, other_user) + {:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user) + + assert %{ + followers_count: 1, + following_count: 1 + } = AccountView.render("show.json", %{user: user, for: user}) + end + end + + describe "follow requests counter" do + test "shows zero when no follow requests are pending" do + user = insert(:user) + + assert %{follow_requests_count: 0} = + AccountView.render("show.json", %{user: user, for: user}) + + other_user = insert(:user) + {:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user) + + assert %{follow_requests_count: 0} = + AccountView.render("show.json", %{user: user, for: user}) + end + + test "shows non-zero when follow requests are pending" do + user = insert(:user, %{info: %{locked: true}}) + + assert %{locked: true} = AccountView.render("show.json", %{user: user, for: user}) + + other_user = insert(:user) + {:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user) + + assert %{locked: true, follow_requests_count: 1} = + AccountView.render("show.json", %{user: user, for: user}) + end + + test "decreases when accepting a follow request" do + user = insert(:user, %{info: %{locked: true}}) + + assert %{locked: true} = AccountView.render("show.json", %{user: user, for: user}) + + other_user = insert(:user) + {:ok, other_user, user, _activity} = CommonAPI.follow(other_user, user) + + assert %{locked: true, follow_requests_count: 1} = + AccountView.render("show.json", %{user: user, for: user}) + + {:ok, _other_user} = CommonAPI.accept_follow_request(other_user, user) + + assert %{locked: true, follow_requests_count: 0} = + AccountView.render("show.json", %{user: user, for: user}) + end + + test "decreases when rejecting a follow request" do + user = insert(:user, %{info: %{locked: true}}) + + assert %{locked: true} = AccountView.render("show.json", %{user: user, for: user}) + + other_user = insert(:user) + {:ok, other_user, user, _activity} = CommonAPI.follow(other_user, user) + + assert %{locked: true, follow_requests_count: 1} = + AccountView.render("show.json", %{user: user, for: user}) + + {:ok, _other_user} = CommonAPI.reject_follow_request(other_user, user) + + assert %{locked: true, follow_requests_count: 0} = + AccountView.render("show.json", %{user: user, for: user}) + end + + test "shows non-zero when historical unapproved requests are present" do + user = insert(:user, %{info: %{locked: true}}) + + assert %{locked: true} = AccountView.render("show.json", %{user: user, for: user}) + + other_user = insert(:user) + {:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user) + + {:ok, user} = User.update_info(user, &User.Info.user_upgrade(&1, %{locked: false})) + + assert %{locked: false, follow_requests_count: 1} = + AccountView.render("show.json", %{user: user, for: user}) + end + end +end diff --git a/test/web/mastodon_api/views/conversation_view_test.exs b/test/web/mastodon_api/views/conversation_view_test.exs new file mode 100644 index 000000000..a2a880705 --- /dev/null +++ b/test/web/mastodon_api/views/conversation_view_test.exs @@ -0,0 +1,34 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.ConversationViewTest do + use Pleroma.DataCase + + alias Pleroma.Conversation.Participation + alias Pleroma.Web.CommonAPI + alias Pleroma.Web.MastodonAPI.ConversationView + + import Pleroma.Factory + + test "represents a Mastodon Conversation entity" do + user = insert(:user) + other_user = insert(:user) + + {:ok, activity} = + CommonAPI.post(user, %{"status" => "hey @#{other_user.nickname}", "visibility" => "direct"}) + + [participation] = Participation.for_user_with_last_activity_id(user) + + assert participation + + conversation = + ConversationView.render("participation.json", %{participation: participation, for: user}) + + assert conversation.id == participation.id |> to_string() + assert conversation.last_status.id == activity.id + + assert [account] = conversation.accounts + assert account.id == other_user.id + end +end diff --git a/test/web/mastodon_api/views/list_view_test.exs b/test/web/mastodon_api/views/list_view_test.exs new file mode 100644 index 000000000..59e896a7c --- /dev/null +++ b/test/web/mastodon_api/views/list_view_test.exs @@ -0,0 +1,32 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.ListViewTest do + use Pleroma.DataCase + import Pleroma.Factory + alias Pleroma.Web.MastodonAPI.ListView + + test "show" do + user = insert(:user) + title = "mortal enemies" + {:ok, list} = Pleroma.List.create(title, user) + + expected = %{ + id: to_string(list.id), + title: title + } + + assert expected == ListView.render("show.json", %{list: list}) + end + + test "index" do + user = insert(:user) + + {:ok, list} = Pleroma.List.create("my list", user) + {:ok, list2} = Pleroma.List.create("cofe", user) + + assert [%{id: _, title: "my list"}, %{id: _, title: "cofe"}] = + ListView.render("index.json", lists: [list, list2]) + end +end diff --git a/test/web/mastodon_api/views/notification_view_test.exs b/test/web/mastodon_api/views/notification_view_test.exs new file mode 100644 index 000000000..81ab82e2b --- /dev/null +++ b/test/web/mastodon_api/views/notification_view_test.exs @@ -0,0 +1,104 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.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("show.json", %{user: user, for: mentioned_user}), + status: StatusView.render("show.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("show.json", %{user: another_user, for: user}), + status: StatusView.render("show.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("show.json", %{user: another_user, for: user}), + status: StatusView.render("show.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("show.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/views/push_subscription_view_test.exs b/test/web/mastodon_api/views/push_subscription_view_test.exs new file mode 100644 index 000000000..4e4f5b7e6 --- /dev/null +++ b/test/web/mastodon_api/views/push_subscription_view_test.exs @@ -0,0 +1,23 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.PushSubscriptionViewTest do + use Pleroma.DataCase + import Pleroma.Factory + alias Pleroma.Web.MastodonAPI.PushSubscriptionView, as: View + alias Pleroma.Web.Push + + test "Represent a subscription" do + subscription = insert(:push_subscription, data: %{"alerts" => %{"mention" => true}}) + + expected = %{ + alerts: %{"mention" => true}, + endpoint: subscription.endpoint, + id: to_string(subscription.id), + server_key: Keyword.get(Push.vapid_config(), :public_key) + } + + assert expected == View.render("push_subscription.json", %{subscription: subscription}) + end +end diff --git a/test/web/mastodon_api/views/scheduled_activity_view_test.exs b/test/web/mastodon_api/views/scheduled_activity_view_test.exs new file mode 100644 index 000000000..6387e4555 --- /dev/null +++ b/test/web/mastodon_api/views/scheduled_activity_view_test.exs @@ -0,0 +1,68 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.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/views/status_view_test.exs b/test/web/mastodon_api/views/status_view_test.exs new file mode 100644 index 000000000..8df23d0a8 --- /dev/null +++ b/test/web/mastodon_api/views/status_view_test.exs @@ -0,0 +1,620 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.StatusViewTest do + use Pleroma.DataCase + + alias Pleroma.Activity + alias Pleroma.Bookmark + alias Pleroma.Object + alias Pleroma.Repo + alias Pleroma.User + alias Pleroma.Web.CommonAPI + alias Pleroma.Web.CommonAPI.Utils + alias Pleroma.Web.MastodonAPI.AccountView + alias Pleroma.Web.MastodonAPI.StatusView + alias Pleroma.Web.OStatus + import Pleroma.Factory + import Tesla.Mock + + setup do + mock(fn env -> apply(HttpRequestMock, :request, [env]) end) + :ok + end + + test "returns the direct conversation id when given the `with_conversation_id` option" do + user = insert(:user) + + {:ok, activity} = CommonAPI.post(user, %{"status" => "Hey @shp!", "visibility" => "direct"}) + + status = + StatusView.render("show.json", + activity: activity, + with_direct_conversation_id: true, + for: user + ) + + assert status[:pleroma][:direct_conversation_id] + end + + test "returns a temporary ap_id based user for activities missing db users" do + user = insert(:user) + + {:ok, activity} = CommonAPI.post(user, %{"status" => "Hey @shp!", "visibility" => "direct"}) + + Repo.delete(user) + Cachex.clear(:user_cache) + + %{account: ms_user} = StatusView.render("show.json", activity: activity) + + assert ms_user.acct == "erroruser@example.com" + end + + test "tries to get a user by nickname if fetching by ap_id doesn't work" do + user = insert(:user) + + {:ok, activity} = CommonAPI.post(user, %{"status" => "Hey @shp!", "visibility" => "direct"}) + + {:ok, user} = + user + |> Ecto.Changeset.change(%{ap_id: "#{user.ap_id}/extension/#{user.nickname}"}) + |> Repo.update() + + Cachex.clear(:user_cache) + + result = StatusView.render("show.json", activity: activity) + + assert result[:account][:id] == to_string(user.id) + end + + test "a note with null content" do + note = insert(:note_activity) + note_object = Object.normalize(note) + + data = + note_object.data + |> Map.put("content", nil) + + Object.change(note_object, %{data: data}) + |> Object.update_and_set_cache() + + User.get_cached_by_ap_id(note.data["actor"]) + + status = StatusView.render("show.json", %{activity: note}) + + assert status.content == "" + end + + test "a note activity" do + note = insert(:note_activity) + object_data = Object.normalize(note).data + user = User.get_cached_by_ap_id(note.data["actor"]) + + convo_id = Utils.context_to_conversation_id(object_data["context"]) + + status = StatusView.render("show.json", %{activity: note}) + + created_at = + (object_data["published"] || "") + |> String.replace(~r/\.\d+Z/, ".000Z") + + expected = %{ + id: to_string(note.id), + uri: object_data["id"], + url: Pleroma.Web.Router.Helpers.o_status_url(Pleroma.Web.Endpoint, :notice, note), + account: AccountView.render("show.json", %{user: user}), + in_reply_to_id: nil, + in_reply_to_account_id: nil, + card: nil, + reblog: nil, + content: HtmlSanitizeEx.basic_html(object_data["content"]), + created_at: created_at, + reblogs_count: 0, + replies_count: 0, + favourites_count: 0, + reblogged: false, + bookmarked: false, + favourited: false, + muted: false, + pinned: false, + sensitive: false, + poll: nil, + spoiler_text: HtmlSanitizeEx.basic_html(object_data["summary"]), + visibility: "public", + media_attachments: [], + mentions: [], + tags: [ + %{ + name: "#{object_data["tag"]}", + url: "/tag/#{object_data["tag"]}" + } + ], + application: %{ + name: "Web", + website: nil + }, + language: nil, + emojis: [ + %{ + shortcode: "2hu", + url: "corndog.png", + static_url: "corndog.png", + visible_in_picker: false + } + ], + pleroma: %{ + local: true, + conversation_id: convo_id, + in_reply_to_account_acct: nil, + content: %{"text/plain" => HtmlSanitizeEx.strip_tags(object_data["content"])}, + spoiler_text: %{"text/plain" => HtmlSanitizeEx.strip_tags(object_data["summary"])}, + expires_at: nil, + direct_conversation_id: nil, + thread_muted: false + } + } + + assert status == expected + end + + test "tells if the message is muted for some reason" do + user = insert(:user) + other_user = insert(:user) + + {:ok, user} = User.mute(user, other_user) + + {:ok, activity} = CommonAPI.post(other_user, %{"status" => "test"}) + status = StatusView.render("show.json", %{activity: activity}) + + assert status.muted == false + + status = StatusView.render("show.json", %{activity: activity, for: user}) + + assert status.muted == true + end + + test "tells if the message is thread muted" do + user = insert(:user) + other_user = insert(:user) + + {:ok, user} = User.mute(user, other_user) + + {:ok, activity} = CommonAPI.post(other_user, %{"status" => "test"}) + status = StatusView.render("show.json", %{activity: activity, for: user}) + + assert status.pleroma.thread_muted == false + + {:ok, activity} = CommonAPI.add_mute(user, activity) + + status = StatusView.render("show.json", %{activity: activity, for: user}) + + assert status.pleroma.thread_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("show.json", %{activity: activity}) + + assert status.bookmarked == false + + status = StatusView.render("show.json", %{activity: activity, for: user}) + + assert status.bookmarked == false + + {:ok, _bookmark} = Bookmark.create(user.id, activity.id) + + activity = Activity.get_by_id_with_object(activity.id) + + status = StatusView.render("show.json", %{activity: activity, for: user}) + + assert status.bookmarked == true + end + + test "a reply" do + note = insert(:note_activity) + user = insert(:user) + + {:ok, activity} = + CommonAPI.post(user, %{"status" => "he", "in_reply_to_status_id" => note.id}) + + status = StatusView.render("show.json", %{activity: activity}) + + assert status.in_reply_to_id == to_string(note.id) + + [status] = StatusView.render("index.json", %{activities: [activity], as: :activity}) + + assert status.in_reply_to_id == to_string(note.id) + end + + test "contains mentions" do + incoming = File.read!("test/fixtures/incoming_reply_mastodon.xml") + # a user with this ap id might be in the cache. + recipient = "https://pleroma.soykaf.com/users/lain" + user = insert(:user, %{ap_id: recipient}) + + {:ok, [activity]} = OStatus.handle_incoming(incoming) + + status = StatusView.render("show.json", %{activity: activity}) + + assert status.mentions == + Enum.map([user], fn u -> AccountView.render("mention.json", %{user: u}) end) + end + + test "create mentions from the 'to' field" do + %User{ap_id: recipient_ap_id} = insert(:user) + cc = insert_pair(:user) |> Enum.map(& &1.ap_id) + + object = + insert(:note, %{ + data: %{ + "to" => [recipient_ap_id], + "cc" => cc + } + }) + + activity = + insert(:note_activity, %{ + note: object, + recipients: [recipient_ap_id | cc] + }) + + assert length(activity.recipients) == 3 + + %{mentions: [mention] = mentions} = StatusView.render("show.json", %{activity: activity}) + + assert length(mentions) == 1 + assert mention.url == recipient_ap_id + end + + test "create mentions from the 'tag' field" do + recipient = insert(:user) + cc = insert_pair(:user) |> Enum.map(& &1.ap_id) + + object = + insert(:note, %{ + data: %{ + "cc" => cc, + "tag" => [ + %{ + "href" => recipient.ap_id, + "name" => recipient.nickname, + "type" => "Mention" + }, + %{ + "href" => "https://example.com/search?tag=test", + "name" => "#test", + "type" => "Hashtag" + } + ] + } + }) + + activity = + insert(:note_activity, %{ + note: object, + recipients: [recipient.ap_id | cc] + }) + + assert length(activity.recipients) == 3 + + %{mentions: [mention] = mentions} = StatusView.render("show.json", %{activity: activity}) + + assert length(mentions) == 1 + assert mention.url == recipient.ap_id + end + + test "attachments" do + object = %{ + "type" => "Image", + "url" => [ + %{ + "mediaType" => "image/png", + "href" => "someurl" + } + ], + "uuid" => 6 + } + + expected = %{ + id: "1638338801", + type: "image", + url: "someurl", + remote_url: "someurl", + preview_url: "someurl", + text_url: "someurl", + description: nil, + pleroma: %{mime_type: "image/png"} + } + + assert expected == StatusView.render("attachment.json", %{attachment: object}) + + # If theres a "id", use that instead of the generated one + object = Map.put(object, "id", 2) + assert %{id: "2"} = StatusView.render("attachment.json", %{attachment: object}) + end + + test "put the url advertised in the Activity in to the url attribute" do + id = "https://wedistribute.org/wp-json/pterotype/v1/object/85810" + [activity] = Activity.search(nil, id) + + status = StatusView.render("show.json", %{activity: activity}) + + assert status.uri == id + assert status.url == "https://wedistribute.org/2019/07/mastodon-drops-ostatus/" + end + + test "a reblog" do + user = insert(:user) + activity = insert(:note_activity) + + {:ok, reblog, _} = CommonAPI.repeat(activity.id, user) + + represented = StatusView.render("show.json", %{for: user, activity: reblog}) + + assert represented[:id] == to_string(reblog.id) + assert represented[:reblog][:id] == to_string(activity.id) + assert represented[:emojis] == [] + end + + test "a peertube video" do + user = insert(:user) + + {:ok, object} = + Pleroma.Object.Fetcher.fetch_object_from_id( + "https://peertube.moe/videos/watch/df5f464b-be8d-46fb-ad81-2d4c2d1630e3" + ) + + %Activity{} = activity = Activity.get_create_by_object_ap_id(object.data["id"]) + + represented = StatusView.render("show.json", %{for: user, activity: activity}) + + assert represented[:id] == to_string(activity.id) + assert length(represented[:media_attachments]) == 1 + end + + describe "build_tags/1" do + test "it returns a a dictionary tags" do + object_tags = [ + "fediverse", + "mastodon", + "nextcloud", + %{ + "href" => "https://kawen.space/users/lain", + "name" => "@lain@kawen.space", + "type" => "Mention" + } + ] + + assert StatusView.build_tags(object_tags) == [ + %{name: "fediverse", url: "/tag/fediverse"}, + %{name: "mastodon", url: "/tag/mastodon"}, + %{name: "nextcloud", url: "/tag/nextcloud"} + ] + end + end + + describe "rich media cards" do + test "a rich media card without a site name renders correctly" do + page_url = "http://example.com" + + card = %{ + url: page_url, + image: page_url <> "/example.jpg", + title: "Example website" + } + + %{provider_name: "example.com"} = + StatusView.render("card.json", %{page_url: page_url, rich_media: card}) + end + + test "a rich media card without a site name or image renders correctly" do + page_url = "http://example.com" + + card = %{ + url: page_url, + title: "Example website" + } + + %{provider_name: "example.com"} = + StatusView.render("card.json", %{page_url: page_url, rich_media: card}) + end + + test "a rich media card without an image renders correctly" do + page_url = "http://example.com" + + card = %{ + url: page_url, + site_name: "Example site name", + title: "Example website" + } + + %{provider_name: "Example site name"} = + StatusView.render("card.json", %{page_url: page_url, rich_media: card}) + end + + test "a rich media card with all relevant data renders correctly" do + page_url = "http://example.com" + + card = %{ + url: page_url, + site_name: "Example site name", + title: "Example website", + image: page_url <> "/example.jpg", + description: "Example description" + } + + %{provider_name: "Example site name"} = + StatusView.render("card.json", %{page_url: page_url, rich_media: card}) + end + end + + describe "poll view" do + test "renders a poll" do + user = insert(:user) + + {:ok, activity} = + CommonAPI.post(user, %{ + "status" => "Is Tenshi eating a corndog cute?", + "poll" => %{ + "options" => ["absolutely!", "sure", "yes", "why are you even asking?"], + "expires_in" => 20 + } + }) + + object = Object.normalize(activity) + + expected = %{ + emojis: [], + expired: false, + id: to_string(object.id), + multiple: false, + options: [ + %{title: "absolutely!", votes_count: 0}, + %{title: "sure", votes_count: 0}, + %{title: "yes", votes_count: 0}, + %{title: "why are you even asking?", votes_count: 0} + ], + voted: false, + votes_count: 0 + } + + result = StatusView.render("poll.json", %{object: object}) + expires_at = result.expires_at + result = Map.delete(result, :expires_at) + + assert result == expected + + expires_at = NaiveDateTime.from_iso8601!(expires_at) + assert NaiveDateTime.diff(expires_at, NaiveDateTime.utc_now()) in 15..20 + end + + test "detects if it is multiple choice" do + user = insert(:user) + + {:ok, activity} = + CommonAPI.post(user, %{ + "status" => "Which Mastodon developer is your favourite?", + "poll" => %{ + "options" => ["Gargron", "Eugen"], + "expires_in" => 20, + "multiple" => true + } + }) + + object = Object.normalize(activity) + + assert %{multiple: true} = StatusView.render("poll.json", %{object: object}) + end + + test "detects emoji" do + user = insert(:user) + + {:ok, activity} = + CommonAPI.post(user, %{ + "status" => "What's with the smug face?", + "poll" => %{ + "options" => [":blank: sip", ":blank::blank: sip", ":blank::blank::blank: sip"], + "expires_in" => 20 + } + }) + + object = Object.normalize(activity) + + assert %{emojis: [%{shortcode: "blank"}]} = + StatusView.render("poll.json", %{object: object}) + end + + test "detects vote status" do + user = insert(:user) + other_user = insert(:user) + + {:ok, activity} = + CommonAPI.post(user, %{ + "status" => "Which input devices do you use?", + "poll" => %{ + "options" => ["mouse", "trackball", "trackpoint"], + "multiple" => true, + "expires_in" => 20 + } + }) + + object = Object.normalize(activity) + + {:ok, _, object} = CommonAPI.vote(other_user, object, [1, 2]) + + result = StatusView.render("poll.json", %{object: object, for: other_user}) + + assert result[:voted] == true + assert Enum.at(result[:options], 1)[:votes_count] == 1 + assert Enum.at(result[:options], 2)[:votes_count] == 1 + end + + test "does not crash on polls with no end date" do + object = Object.normalize("https://skippers-bin.com/notes/7x9tmrp97i") + result = StatusView.render("poll.json", %{object: object}) + + assert result[:expires_at] == nil + assert result[:expired] == false + end + end + + test "embeds a relationship in the account" do + user = insert(:user) + other_user = insert(:user) + + {:ok, activity} = + CommonAPI.post(user, %{ + "status" => "drink more water" + }) + + result = StatusView.render("show.json", %{activity: activity, for: other_user}) + + assert result[:account][:pleroma][:relationship] == + AccountView.render("relationship.json", %{user: other_user, target: user}) + end + + test "embeds a relationship in the account in reposts" do + user = insert(:user) + other_user = insert(:user) + + {:ok, activity} = + CommonAPI.post(user, %{ + "status" => "˙˙ɐʎns" + }) + + {:ok, activity, _object} = CommonAPI.repeat(activity.id, other_user) + + result = StatusView.render("show.json", %{activity: activity, for: user}) + + assert result[:account][:pleroma][:relationship] == + AccountView.render("relationship.json", %{user: user, target: other_user}) + + assert result[:reblog][:account][:pleroma][:relationship] == + AccountView.render("relationship.json", %{user: user, target: user}) + end + + test "visibility/list" do + user = insert(:user) + + {:ok, list} = Pleroma.List.create("foo", user) + + {:ok, activity} = + CommonAPI.post(user, %{"status" => "foobar", "visibility" => "list:#{list.id}"}) + + status = StatusView.render("show.json", activity: activity) + + assert status.visibility == "list" + end + + test "successfully renders a Listen activity (pleroma extension)" do + listen_activity = insert(:listen) + + status = StatusView.render("listen.json", activity: listen_activity) + + assert status.length == listen_activity.data["object"]["length"] + assert status.title == listen_activity.data["object"]["title"] + end +end |