From: lain Date: Sun, 17 May 2020 10:14:49 +0000 (+0200) Subject: Merge branch 'develop' of git.pleroma.social:pleroma/pleroma into remake-remodel-dms X-Git-Url: https://git.squeep.com/?a=commitdiff_plain;h=9c171097653abce49b9847fff66bc39b35719a1c;hp=-c;p=akkoma Merge branch 'develop' of git.pleroma.social:pleroma/pleroma into remake-remodel-dms --- 9c171097653abce49b9847fff66bc39b35719a1c diff --combined lib/pleroma/web/common_api/common_api.ex index 7008cea44,7c94f16b6..ce5dad448 --- a/lib/pleroma/web/common_api/common_api.ex +++ b/lib/pleroma/web/common_api/common_api.ex @@@ -7,7 -7,6 +7,7 @@@ defmodule Pleroma.Web.CommonAPI d alias Pleroma.ActivityExpiration alias Pleroma.Conversation.Participation alias Pleroma.FollowingRelationship + alias Pleroma.Formatter alias Pleroma.Notification alias Pleroma.Object alias Pleroma.ThreadMute @@@ -25,50 -24,22 +25,61 @@@ require Pleroma.Constants require Logger + def post_chat_message(%User{} = user, %User{} = recipient, content, opts \\ []) do + with maybe_attachment <- opts[:media_id] && Object.get_by_id(opts[:media_id]), + :ok <- validate_chat_content_length(content, !!maybe_attachment), + {_, {:ok, chat_message_data, _meta}} <- + {:build_object, + Builder.chat_message( + user, + recipient.ap_id, + content |> format_chat_content, + attachment: maybe_attachment + )}, + {_, {:ok, create_activity_data, _meta}} <- + {:build_create_activity, Builder.create(user, chat_message_data, [recipient.ap_id])}, + {_, {:ok, %Activity{} = activity, _meta}} <- + {:common_pipeline, + Pipeline.common_pipeline(create_activity_data, + local: true + )} do + {:ok, activity} + end + end + + defp format_chat_content(nil), do: nil + + defp format_chat_content(content) do + content |> Formatter.html_escape("text/plain") + end + + defp validate_chat_content_length(_, true), do: :ok + defp validate_chat_content_length(nil, false), do: {:error, :no_content} + + defp validate_chat_content_length(content, _) do + if String.length(content) <= Pleroma.Config.get([:instance, :chat_limit]) do + :ok + else + {:error, :content_too_long} + end + end + def unblock(blocker, blocked) do - with %Activity{} = block <- Utils.fetch_latest_block(blocker, blocked), + with {_, %Activity{} = block} <- {:fetch_block, Utils.fetch_latest_block(blocker, blocked)}, {:ok, unblock_data, _} <- Builder.undo(blocker, block), {:ok, unblock, _} <- Pipeline.common_pipeline(unblock_data, local: true) do {:ok, unblock} + else + {:fetch_block, nil} -> + if User.blocks?(blocker, blocked) do + User.unblock(blocker, blocked) + {:ok, :no_activity} + else + {:error, :not_blocking} + end + + e -> + e end end diff --combined lib/pleroma/web/mastodon_api/views/account_view.ex index 19fbf0902,45fffaad2..8ff9f39fd --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@@ -15,13 -15,12 +15,12 @@@ defmodule Pleroma.Web.MastodonAPI.Accou def render("index.json", %{users: users} = opts) do reading_user = opts[:for] - # Note: :skip_relationships option is currently intentionally not supported for accounts relationships_opt = cond do Map.has_key?(opts, :relationships) -> opts[:relationships] - is_nil(reading_user) -> + is_nil(reading_user) || !opts[:embed_relationships] -> UserRelationship.view_relationships_option(nil, []) true -> @@@ -193,14 -192,14 +192,14 @@@ end) relationship = - if opts[:skip_relationships] do - %{} - else + if opts[:embed_relationships] do render("relationship.json", %{ user: opts[:for], target: user, relationships: opts[:relationships] }) + else + %{} end %{ @@@ -234,7 -233,6 +233,7 @@@ # Pleroma extension pleroma: %{ + ap_id: user.ap_id, confirmation_pending: user.confirmation_pending, tags: user.tags, hide_followers_count: user.hide_followers_count, diff --combined lib/pleroma/web/mastodon_api/views/notification_view.ex index 2a9951831,c46ddcf55..07d55a3e9 --- a/lib/pleroma/web/mastodon_api/views/notification_view.ex +++ b/lib/pleroma/web/mastodon_api/views/notification_view.ex @@@ -7,14 -7,12 +7,14 @@@ defmodule Pleroma.Web.MastodonAPI.Notif alias Pleroma.Activity alias Pleroma.Notification + alias Pleroma.Object alias Pleroma.User alias Pleroma.UserRelationship alias Pleroma.Web.CommonAPI alias Pleroma.Web.MastodonAPI.AccountView alias Pleroma.Web.MastodonAPI.NotificationView alias Pleroma.Web.MastodonAPI.StatusView + alias Pleroma.Web.PleromaAPI.ChatMessageView def render("index.json", %{notifications: notifications, for: reading_user} = opts) do activities = Enum.map(notifications, & &1.activity) @@@ -53,9 -51,7 +53,7 @@@ |> Enum.filter(& &1) |> Kernel.++(move_activities_targets) - UserRelationship.view_relationships_option(reading_user, actors, - source_mutes_only: opts[:skip_relationships] - ) + UserRelationship.view_relationships_option(reading_user, actors, subset: :source_mutes) end opts = @@@ -83,31 -79,15 +81,29 @@@ end end - mastodon_type = Activity.mastodon_notification_type(activity) + # This returns the notification type by activity, but both chats and statuses + # are in "Create" activities. + mastodon_type = + case Activity.mastodon_notification_type(activity) do + "mention" -> + object = Object.normalize(activity) + + case object do + %{data: %{"type" => "ChatMessage"}} -> "pleroma:chat_mention" + _ -> "mention" + end + + type -> + type + end - render_opts = %{ - relationships: opts[:relationships], - skip_relationships: opts[:skip_relationships] - } + # Note: :relationships contain user mutes (needed for :muted flag in :status) + status_render_opts = %{relationships: opts[:relationships]} with %{id: _} = account <- AccountView.render( "show.json", - Map.merge(render_opts, %{user: actor, for: reading_user}) + %{user: actor, for: reading_user} ) do response = %{ id: to_string(notification.id), @@@ -121,26 -101,22 +117,25 @@@ case mastodon_type do "mention" -> - put_status(response, activity, reading_user, render_opts) + put_status(response, activity, reading_user, status_render_opts) "favourite" -> - put_status(response, parent_activity_fn.(), reading_user, render_opts) + put_status(response, parent_activity_fn.(), reading_user, status_render_opts) "reblog" -> - put_status(response, parent_activity_fn.(), reading_user, render_opts) + put_status(response, parent_activity_fn.(), reading_user, status_render_opts) "move" -> - # Note: :skip_relationships option being applied to _account_ rendering (here) - put_target(response, activity, reading_user, render_opts) + put_target(response, activity, reading_user, %{}) "pleroma:emoji_reaction" -> response - |> put_status(parent_activity_fn.(), reading_user, render_opts) + |> put_status(parent_activity_fn.(), reading_user, status_render_opts) |> put_emoji(activity) + "pleroma:chat_mention" -> - put_chat_message(response, activity, reading_user, render_opts) ++ put_chat_message(response, activity, reading_user, status_render_opts) + type when type in ["follow", "follow_request"] -> response @@@ -156,16 -132,6 +151,16 @@@ Map.put(response, :emoji, activity.data["content"]) end + defp put_chat_message(response, activity, reading_user, opts) do + object = Object.normalize(activity) + author = User.get_cached_by_ap_id(object.data["actor"]) + chat = Pleroma.Chat.get(reading_user.id, author.ap_id) + render_opts = Map.merge(opts, %{object: object, for: reading_user, chat: chat}) + chat_message_render = ChatMessageView.render("show.json", render_opts) + + Map.put(response, :chat_message, chat_message_render) + end + defp put_status(response, activity, reading_user, opts) do status_render_opts = Map.merge(opts, %{activity: activity, for: reading_user}) status_render = StatusView.render("show.json", status_render_opts) diff --combined lib/pleroma/web/router.ex index 0e4f45869,d77a61361..c6e816405 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@@ -302,18 -302,6 +302,18 @@@ defmodule Pleroma.Web.Router d end scope "/api/v1/pleroma", Pleroma.Web.PleromaAPI do + scope [] do + pipe_through(:authenticated_api) + + post("/chats/by-account-id/:id", ChatController, :create) + get("/chats", ChatController, :index) + get("/chats/:id", ChatController, :show) + get("/chats/:id/messages", ChatController, :messages) + post("/chats/:id/messages", ChatController, :post_chat_message) + delete("/chats/:id/messages/:message_id", ChatController, :delete_message) + post("/chats/:id/read", ChatController, :mark_as_read) + end + scope [] do pipe_through(:authenticated_api) @@@ -415,6 -403,7 +415,7 @@@ post("/markers", MarkerController, :upsert) post("/media", MediaController, :create) + get("/media/:id", MediaController, :show) put("/media/:id", MediaController, :update) get("/notifications", NotificationController, :index) @@@ -509,6 -498,8 +510,8 @@@ scope "/api/v2", Pleroma.Web.MastodonAPI do pipe_through(:api) get("/search", SearchController, :search2) + + post("/media", MediaController, :create2) end scope "/api", Pleroma.Web do diff --combined test/web/common_api/common_api_test.exs index 46ffd2888,fd8299013..353969885 --- a/test/web/common_api/common_api_test.exs +++ b/test/web/common_api/common_api_test.exs @@@ -5,7 -5,6 +5,7 @@@ defmodule Pleroma.Web.CommonAPITest do use Pleroma.DataCase alias Pleroma.Activity + alias Pleroma.Chat alias Pleroma.Conversation.Participation alias Pleroma.Object alias Pleroma.User @@@ -24,80 -23,18 +24,92 @@@ setup do: clear_config([:instance, :limit]) setup do: clear_config([:instance, :max_pinned_statuses]) + describe "posting chat messages" do + setup do: clear_config([:instance, :chat_limit]) + + test "it posts a chat message without content but with an attachment" do + author = insert(:user) + recipient = insert(:user) + + file = %Plug.Upload{ + content_type: "image/jpg", + path: Path.absname("test/fixtures/image.jpg"), + filename: "an_image.jpg" + } + + {:ok, upload} = ActivityPub.upload(file, actor: author.ap_id) + + {:ok, activity} = + CommonAPI.post_chat_message( + author, + recipient, + nil, + media_id: upload.id + ) + + assert activity + end + + test "it posts a chat message" do + author = insert(:user) + recipient = insert(:user) + + {:ok, activity} = + CommonAPI.post_chat_message( + author, + recipient, + "a test message :firefox:" + ) + + assert activity.data["type"] == "Create" + assert activity.local + object = Object.normalize(activity) + + assert object.data["type"] == "ChatMessage" + assert object.data["to"] == [recipient.ap_id] + + assert object.data["content"] == + "a test message <script>alert('uuu')</script> :firefox:" + + assert object.data["emoji"] == %{ + "firefox" => "http://localhost:4001/emoji/Firefox.gif" + } + + assert Chat.get(author.id, recipient.ap_id) + assert Chat.get(recipient.id, author.ap_id) + + assert :ok == Pleroma.Web.Federator.perform(:publish, activity) + end + + test "it reject messages over the local limit" do + Pleroma.Config.put([:instance, :chat_limit], 2) + + author = insert(:user) + recipient = insert(:user) + + {:error, message} = + CommonAPI.post_chat_message( + author, + recipient, + "123" + ) + + assert message == :content_too_long + end + end + + describe "unblocking" do + test "it works even without an existing block activity" do + blocked = insert(:user) + blocker = insert(:user) + User.block(blocker, blocked) + + assert User.blocks?(blocker, blocked) + assert {:ok, :no_activity} == CommonAPI.unblock(blocker, blocked) + refute User.blocks?(blocker, blocked) + end + end + describe "deletion" do test "it works with pruned objects" do user = insert(:user) diff --combined test/web/mastodon_api/views/account_view_test.exs index 035b1f6ac,487ec26c2..d5d7236a0 --- a/test/web/mastodon_api/views/account_view_test.exs +++ b/test/web/mastodon_api/views/account_view_test.exs @@@ -72,7 -72,6 +72,7 @@@ defmodule Pleroma.Web.MastodonAPI.Accou fields: [] }, pleroma: %{ + ap_id: user.ap_id, background_image: "https://example.com/images/asuka_hospital.png", confirmation_pending: false, tags: [], @@@ -149,7 -148,6 +149,7 @@@ fields: [] }, pleroma: %{ + ap_id: user.ap_id, background_image: nil, confirmation_pending: false, tags: [], @@@ -304,83 -302,6 +304,6 @@@ end end - test "represent an embedded relationship" do - user = - insert(:user, %{ - follower_count: 0, - note_count: 5, - actor_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, _user_relationship} = 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: %{ - actor_type: "Service", - discoverable: false - }, - fields: [] - }, - pleroma: %{ - ap_id: user.ap_id, - 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: refresh_record(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, pleroma_settings_store: %{fe: "test"}) diff --combined test/web/mastodon_api/views/notification_view_test.exs index f3d269daf,9839e48fc..8db6a2379 --- a/test/web/mastodon_api/views/notification_view_test.exs +++ b/test/web/mastodon_api/views/notification_view_test.exs @@@ -6,9 -6,7 +6,9 @@@ defmodule Pleroma.Web.MastodonAPI.Notif use Pleroma.DataCase alias Pleroma.Activity + alias Pleroma.Chat alias Pleroma.Notification + alias Pleroma.Object alias Pleroma.Repo alias Pleroma.User alias Pleroma.Web.CommonAPI @@@ -16,7 -14,6 +16,7 @@@ alias Pleroma.Web.MastodonAPI.AccountView alias Pleroma.Web.MastodonAPI.NotificationView alias Pleroma.Web.MastodonAPI.StatusView + alias Pleroma.Web.PleromaAPI.ChatMessageView import Pleroma.Factory defp test_notifications_rendering(notifications, user, expected_result) do @@@ -34,29 -31,6 +34,29 @@@ assert expected_result == result end + test "ChatMessage notification" do + user = insert(:user) + recipient = insert(:user) + {:ok, activity} = CommonAPI.post_chat_message(user, recipient, "what's up my dude") + + {:ok, [notification]} = Notification.create_notifications(activity) + + object = Object.normalize(activity) + chat = Chat.get(recipient.id, user.ap_id) + + expected = %{ + id: to_string(notification.id), + pleroma: %{is_seen: false}, + type: "pleroma:chat_mention", + account: AccountView.render("show.json", %{user: user, for: recipient}), + chat_message: + ChatMessageView.render("show.json", %{object: object, for: recipient, chat: chat}), + created_at: Utils.to_masto_date(notification.inserted_at) + } + + test_notifications_rendering([notification], recipient, [expected]) + end + test "Mention notification" do user = insert(:user) mentioned_user = insert(:user) @@@ -68,7 -42,11 +68,11 @@@ id: to_string(notification.id), pleroma: %{is_seen: false}, type: "mention", - account: AccountView.render("show.json", %{user: user, for: mentioned_user}), + 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) }