From 63477d07adb614413a382a87f06af2bc2495b432 Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Tue, 12 May 2020 06:44:33 +0300 Subject: unsubscribes of friends when user deactivated --- lib/mix/tasks/pleroma/user.ex | 14 ++------------ lib/pleroma/user.ex | 20 +++++++++++++++----- 2 files changed, 17 insertions(+), 17 deletions(-) (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/user.ex b/lib/mix/tasks/pleroma/user.ex index da140ac86..93ecb4631 100644 --- a/lib/mix/tasks/pleroma/user.ex +++ b/lib/mix/tasks/pleroma/user.ex @@ -150,22 +150,12 @@ defmodule Mix.Tasks.Pleroma.User do with %User{} = user <- User.get_cached_by_nickname(nickname) do shell_info("Deactivating #{user.nickname}") User.deactivate(user) - - user - |> User.get_friends() - |> Enum.each(fn friend -> - user = User.get_cached_by_id(user.id) - - shell_info("Unsubscribing #{friend.nickname} from #{user.nickname}") - User.unfollow(user, friend) - end) - :timer.sleep(500) user = User.get_cached_by_id(user.id) - if Enum.empty?(User.get_friends(user)) do - shell_info("Successfully unsubscribed all followers from #{user.nickname}") + if Enum.empty?(Enum.filter(User.get_friends(user), & &1.local)) do + shell_info("Successfully unsubscribed all local followers from #{user.nickname}") end else _ -> diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index a86cc3202..1c456b27c 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -750,7 +750,19 @@ defmodule Pleroma.User do {:error, "Not subscribed!"} end + @spec unfollow(User.t(), User.t()) :: {:ok, User.t(), Activity.t()} | {:error, String.t()} def unfollow(%User{} = follower, %User{} = followed) do + case do_unfollow(follower, followed) do + {:ok, follower, followed} -> + {:ok, follower, Utils.fetch_latest_follow(follower, followed)} + + error -> + error + end + end + + @spec do_unfollow(User.t(), User.t()) :: {:ok, User.t(), User.t()} | {:error, String.t()} + defp do_unfollow(%User{} = follower, %User{} = followed) do case get_follow_state(follower, followed) do state when state in [:follow_pending, :follow_accept] -> FollowingRelationship.unfollow(follower, followed) @@ -761,7 +773,7 @@ defmodule Pleroma.User do |> update_following_count() |> set_cache() - {:ok, follower, Utils.fetch_latest_follow(follower, followed)} + {:ok, follower, followed} nil -> {:error, "Not subscribed!"} @@ -1401,15 +1413,13 @@ defmodule Pleroma.User do user |> get_followers() |> Enum.filter(& &1.local) - |> Enum.each(fn follower -> - follower |> update_following_count() |> set_cache() - end) + |> Enum.each(&set_cache(update_following_count(&1))) # Only update local user counts, remote will be update during the next pull. user |> get_friends() |> Enum.filter(& &1.local) - |> Enum.each(&update_follower_count/1) + |> Enum.each(&do_unfollow(user, &1)) {:ok, user} end -- cgit v1.2.3 From e688d4ee69dfbda0f8fd3a5544720a566b3946c5 Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Tue, 14 Apr 2020 18:59:04 +0200 Subject: MRF.StealEmojiPolicy: New Policy Inspired by https://git.pleroma.social/moonman/emoji-stealer-mrf/-/blob/master/steal_emoji_policy.ex --- .../web/activity_pub/mrf/steal_emoji_policy.ex | 97 ++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 lib/pleroma/web/activity_pub/mrf/steal_emoji_policy.ex (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/mrf/steal_emoji_policy.ex b/lib/pleroma/web/activity_pub/mrf/steal_emoji_policy.ex new file mode 100644 index 000000000..2858af9eb --- /dev/null +++ b/lib/pleroma/web/activity_pub/mrf/steal_emoji_policy.ex @@ -0,0 +1,97 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ActivityPub.MRF.StealEmojiPolicy do + require Logger + + alias Pleroma.Config + + @moduledoc "Detect new emojis by their shortcode and steals them" + @behaviour Pleroma.Web.ActivityPub.MRF + + defp remote_host?(host), do: host != Config.get([Pleroma.Web.Endpoint, :url, :host]) + + defp accept_host?(host), do: host in Config.get([:mrf_steal_emoji, :hosts], []) + + defp steal_emoji({shortcode, url}) do + url = Pleroma.Web.MediaProxy.url(url) + {:ok, response} = Pleroma.HTTP.get(url) + size_limit = Config.get([:mrf_steal_emoji, :size_limit], 50_000) + + if byte_size(response.body) <= size_limit do + emoji_dir_path = + Config.get( + [:mrf_steal_emoji, :path], + Path.join(Config.get([:instance, :static_dir]), "emoji/stolen") + ) + + extension = + url + |> URI.parse() + |> Map.get(:path) + |> Path.basename() + |> Path.extname() + + file_path = Path.join([emoji_dir_path, shortcode <> (extension || ".png")]) + + try do + :ok = File.write(file_path, response.body) + + shortcode + rescue + e -> + Logger.warn("MRF.StealEmojiPolicy: Failed to write to #{file_path}: #{inspect(e)}") + nil + end + else + Logger.debug( + "MRF.StealEmojiPolicy: :#{shortcode}: at #{url} (#{byte_size(response.body)} B) over size limit (#{ + size_limit + } B)" + ) + + nil + end + rescue + e -> + Logger.warn("MRF.StealEmojiPolicy: Failed to fetch #{url}: #{inspect(e)}") + nil + end + + @impl true + def filter(%{"object" => %{"emoji" => foreign_emojis, "actor" => actor}} = message) do + host = URI.parse(actor).host + + if remote_host?(host) and accept_host?(host) do + installed_emoji = Pleroma.Emoji.get_all() |> Enum.map(fn {k, _} -> k end) + + new_emojis = + foreign_emojis + |> Enum.filter(fn {shortcode, _url} -> shortcode not in installed_emoji end) + |> Enum.filter(fn {shortcode, _url} -> + reject_emoji? = + Config.get([:mrf_steal_emoji, :rejected_shortcodes], []) + |> Enum.find(false, fn regex -> String.match?(shortcode, regex) end) + + !reject_emoji? + end) + |> Enum.map(&steal_emoji(&1)) + |> Enum.filter(& &1) + + if !Enum.empty?(new_emojis) do + Logger.info("Stole new emojis: #{inspect(new_emojis)}") + Pleroma.Emoji.reload() + end + end + + {:ok, message} + end + + def filter(message), do: {:ok, message} + + @impl true + def describe do + {:ok, %{}} + end +end -- cgit v1.2.3 From 490a3a34b63fa10e9151e9a385920c10615a1a3c Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Tue, 19 May 2020 21:52:26 +0400 Subject: Add OpenAPI spec for PleromaAPI.PleromaAPIController --- .../api_spec/operations/notification_operation.ex | 2 +- .../web/api_spec/operations/pleroma_operation.ex | 223 +++++++++++++++++++++ .../controllers/pleroma_api_controller.ex | 28 +-- 3 files changed, 239 insertions(+), 14 deletions(-) create mode 100644 lib/pleroma/web/api_spec/operations/pleroma_operation.ex (limited to 'lib') diff --git a/lib/pleroma/web/api_spec/operations/notification_operation.ex b/lib/pleroma/web/api_spec/operations/notification_operation.ex index 64adc5319..46e72f8bf 100644 --- a/lib/pleroma/web/api_spec/operations/notification_operation.ex +++ b/lib/pleroma/web/api_spec/operations/notification_operation.ex @@ -145,7 +145,7 @@ defmodule Pleroma.Web.ApiSpec.NotificationOperation do } end - defp notification do + def notification do %Schema{ title: "Notification", description: "Response schema for a notification", diff --git a/lib/pleroma/web/api_spec/operations/pleroma_operation.ex b/lib/pleroma/web/api_spec/operations/pleroma_operation.ex new file mode 100644 index 000000000..c6df5c854 --- /dev/null +++ b/lib/pleroma/web/api_spec/operations/pleroma_operation.ex @@ -0,0 +1,223 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ApiSpec.PleromaOperation do + alias OpenApiSpex.Operation + alias OpenApiSpex.Schema + alias Pleroma.Web.ApiSpec.Schemas.Account + alias Pleroma.Web.ApiSpec.Schemas.ApiError + alias Pleroma.Web.ApiSpec.Schemas.FlakeID + alias Pleroma.Web.ApiSpec.Schemas.Status + alias Pleroma.Web.ApiSpec.Schemas.Conversation + alias Pleroma.Web.ApiSpec.StatusOperation + alias Pleroma.Web.ApiSpec.NotificationOperation + + import Pleroma.Web.ApiSpec.Helpers + + def open_api_operation(action) do + operation = String.to_existing_atom("#{action}_operation") + apply(__MODULE__, operation, []) + end + + def emoji_reactions_by_operation do + %Operation{ + tags: ["Emoji Reactions"], + summary: + "Get an object of emoji to account mappings with accounts that reacted to the post", + parameters: [ + Operation.parameter(:id, :path, FlakeID, "Status ID", required: true), + Operation.parameter(:emoji, :path, :string, "Filter by a single unicode emoji", + required: false + ) + ], + security: [%{"oAuth" => ["read:statuses"]}], + operationId: "PleromaController.emoji_reactions_by", + responses: %{ + 200 => array_of_reactions_response() + } + } + end + + def react_with_emoji_operation do + %Operation{ + tags: ["Emoji Reactions"], + summary: "React to a post with a unicode emoji", + parameters: [ + Operation.parameter(:id, :path, FlakeID, "Status ID", required: true), + Operation.parameter(:emoji, :path, :string, "A single character unicode emoji", + required: true + ) + ], + security: [%{"oAuth" => ["write:statuses"]}], + operationId: "PleromaController.react_with_emoji", + responses: %{ + 200 => Operation.response("Status", "application/json", Status) + } + } + end + + def unreact_with_emoji_operation do + %Operation{ + tags: ["Emoji Reactions"], + summary: "Remove a reaction to a post with a unicode emoji", + parameters: [ + Operation.parameter(:id, :path, FlakeID, "Status ID", required: true), + Operation.parameter(:emoji, :path, :string, "A single character unicode emoji", + required: true + ) + ], + security: [%{"oAuth" => ["write:statuses"]}], + operationId: "PleromaController.unreact_with_emoji", + responses: %{ + 200 => Operation.response("Status", "application/json", Status) + } + } + end + + defp array_of_reactions_response do + Operation.response("Array of Emoji Reactions", "application/json", %Schema{ + type: :array, + items: emoji_reaction(), + example: [emoji_reaction().example] + }) + end + + defp emoji_reaction do + %Schema{ + title: "EmojiReaction", + type: :object, + properties: %{ + name: %Schema{type: :string, description: "Emoji"}, + count: %Schema{type: :integer, description: "Count of reactions with this emoji"}, + me: %Schema{type: :boolean, description: "Did I react with this emoji?"}, + accounts: %Schema{ + type: :array, + items: Account, + description: "Array of accounts reacted with this emoji" + } + }, + example: %{ + "name" => "😱", + "count" => 1, + "me" => false, + "accounts" => [Account.schema().example] + } + } + end + + def conversation_operation do + %Operation{ + tags: ["Conversations"], + summary: "The conversation with the given ID", + parameters: [ + Operation.parameter(:id, :path, :string, "Conversation ID", + example: "123", + required: true + ) + ], + security: [%{"oAuth" => ["read:statuses"]}], + operationId: "PleromaController.conversation", + responses: %{ + 200 => Operation.response("Conversation", "application/json", Conversation) + } + } + end + + def conversation_statuses_operation do + %Operation{ + tags: ["Conversations"], + summary: "Timeline for a given conversation", + parameters: [ + Operation.parameter(:id, :path, :string, "Conversation ID", + example: "123", + required: true + ) + | pagination_params() + ], + security: [%{"oAuth" => ["read:statuses"]}], + operationId: "PleromaController.conversation_statuses", + responses: %{ + 200 => + Operation.response( + "Array of Statuses", + "application/json", + StatusOperation.array_of_statuses() + ) + } + } + end + + def update_conversation_operation do + %Operation{ + tags: ["Conversations"], + summary: "Update a conversation. Used to change the set of recipients.", + parameters: [ + Operation.parameter(:id, :path, :string, "Conversation ID", + example: "123", + required: true + ), + Operation.parameter( + :recipients, + :query, + %Schema{type: :array, items: FlakeID}, + "A list of ids of users that should receive posts to this conversation. This will replace the current list of recipients, so submit the full list. The owner of owner of the conversation will always be part of the set of recipients, though.", + required: true + ) + ], + security: [%{"oAuth" => ["write:conversations"]}], + operationId: "PleromaController.update_conversation", + responses: %{ + 200 => Operation.response("Conversation", "application/json", Conversation) + } + } + end + + def mark_conversations_as_read_operation do + %Operation{ + tags: ["Conversations"], + summary: "Marks all user's conversations as read", + security: [%{"oAuth" => ["write:conversations"]}], + operationId: "PleromaController.mark_conversations_as_read", + responses: %{ + 200 => + Operation.response( + "Array of Conversations that were marked as read", + "application/json", + %Schema{ + type: :array, + items: Conversation, + example: [Conversation.schema().example] + } + ) + } + } + end + + def mark_notifications_as_read_operation do + %Operation{ + tags: ["Notifications"], + summary: "Mark notifications as read. Query parameters are mutually exclusive.", + parameters: [ + Operation.parameter(:id, :query, :string, "A single notification ID to read"), + Operation.parameter(:max_id, :query, :string, "Read all notifications up to this id") + ], + security: [%{"oAuth" => ["write:notifications"]}], + operationId: "PleromaController.mark_notifications_as_read", + responses: %{ + 200 => + Operation.response( + "A Notification or array of Motifications", + "application/json", + %Schema{ + anyOf: [ + %Schema{type: :array, items: NotificationOperation.notification()}, + NotificationOperation.notification() + ] + } + ), + 400 => Operation.response("Bad Request", "application/json", ApiError) + } + } + end +end diff --git a/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex b/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex index e834133b2..8220d13bc 100644 --- a/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex @@ -20,6 +20,8 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do alias Pleroma.Web.MastodonAPI.NotificationView alias Pleroma.Web.MastodonAPI.StatusView + plug(Pleroma.Web.ApiSpec.CastAndValidate) + plug( OAuthScopesPlug, %{scopes: ["read:statuses"]} @@ -49,14 +51,16 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do %{scopes: ["write:notifications"]} when action == :mark_notifications_as_read ) - def emoji_reactions_by(%{assigns: %{user: user}} = conn, %{"id" => activity_id} = params) do + defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.PleromaOperation + + def emoji_reactions_by(%{assigns: %{user: user}} = conn, %{id: activity_id} = params) do with %Activity{} = activity <- Activity.get_by_id_with_object(activity_id), %Object{data: %{"reactions" => emoji_reactions}} when is_list(emoji_reactions) <- Object.normalize(activity) do reactions = emoji_reactions |> Enum.map(fn [emoji, user_ap_ids] -> - if params["emoji"] && params["emoji"] != emoji do + if params[:emoji] && params[:emoji] != emoji do nil else users = @@ -79,7 +83,7 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do } end end) - |> Enum.filter(& &1) + |> Enum.reject(&is_nil/1) conn |> json(reactions) @@ -90,7 +94,7 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do end end - def react_with_emoji(%{assigns: %{user: user}} = conn, %{"id" => activity_id, "emoji" => emoji}) do + def react_with_emoji(%{assigns: %{user: user}} = conn, %{id: activity_id, emoji: emoji}) do with {:ok, _activity} <- CommonAPI.react_with_emoji(activity_id, user, emoji), activity <- Activity.get_by_id(activity_id) do conn @@ -99,10 +103,7 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do end end - def unreact_with_emoji(%{assigns: %{user: user}} = conn, %{ - "id" => activity_id, - "emoji" => emoji - }) do + def unreact_with_emoji(%{assigns: %{user: user}} = conn, %{id: activity_id, emoji: emoji}) do with {:ok, _activity} <- CommonAPI.unreact_with_emoji(activity_id, user, emoji), activity <- Activity.get_by_id(activity_id) do @@ -112,7 +113,7 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do end end - def conversation(%{assigns: %{user: user}} = conn, %{"id" => participation_id}) do + def conversation(%{assigns: %{user: user}} = conn, %{id: participation_id}) do with %Participation{} = participation <- Participation.get(participation_id), true <- user.id == participation.user_id do conn @@ -128,12 +129,13 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do def conversation_statuses( %{assigns: %{user: %{id: user_id} = user}} = conn, - %{"id" => participation_id} = params + %{id: participation_id} = params ) do with %Participation{user_id: ^user_id} = participation <- Participation.get(participation_id, preload: [:conversation]) do params = params + |> Map.new(fn {key, value} -> {to_string(key), value} end) |> Map.put("blocking_user", user) |> Map.put("muting_user", user) |> Map.put("user", user) @@ -162,7 +164,7 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do def update_conversation( %{assigns: %{user: user}} = conn, - %{"id" => participation_id, "recipients" => recipients} + %{id: participation_id, recipients: recipients} ) do with %Participation{} = participation <- Participation.get(participation_id), true <- user.id == participation.user_id, @@ -192,7 +194,7 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do end end - def mark_notifications_as_read(%{assigns: %{user: user}} = conn, %{"id" => notification_id}) do + def mark_notifications_as_read(%{assigns: %{user: user}} = conn, %{id: notification_id}) do with {:ok, notification} <- Notification.read_one(user, notification_id) do conn |> put_view(NotificationView) @@ -205,7 +207,7 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do end end - def mark_notifications_as_read(%{assigns: %{user: user}} = conn, %{"max_id" => max_id}) do + def mark_notifications_as_read(%{assigns: %{user: user}} = conn, %{max_id: max_id}) do with notifications <- Notification.set_read_up_to(user, max_id) do notifications = Enum.take(notifications, 80) -- cgit v1.2.3 From 9a5de0f4548cfe6b62265596bbe3cef2d639b978 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Tue, 19 May 2020 23:50:49 +0400 Subject: Move reaction actions to EmojiReactionController --- .../operations/emoji_reaction_operation.ex | 102 +++++++++++++++++++++ .../web/api_spec/operations/pleroma_operation.ex | 92 +------------------ .../controllers/emoji_reaction_controller.ex | 61 ++++++++++++ .../controllers/pleroma_api_controller.ex | 77 ---------------- .../web/pleroma_api/views/emoji_reaction_view.ex | 33 +++++++ lib/pleroma/web/router.ex | 8 +- 6 files changed, 202 insertions(+), 171 deletions(-) create mode 100644 lib/pleroma/web/api_spec/operations/emoji_reaction_operation.ex create mode 100644 lib/pleroma/web/pleroma_api/controllers/emoji_reaction_controller.ex create mode 100644 lib/pleroma/web/pleroma_api/views/emoji_reaction_view.ex (limited to 'lib') diff --git a/lib/pleroma/web/api_spec/operations/emoji_reaction_operation.ex b/lib/pleroma/web/api_spec/operations/emoji_reaction_operation.ex new file mode 100644 index 000000000..7c08fbaa7 --- /dev/null +++ b/lib/pleroma/web/api_spec/operations/emoji_reaction_operation.ex @@ -0,0 +1,102 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ApiSpec.EmojiReactionOperation do + alias OpenApiSpex.Operation + alias OpenApiSpex.Schema + alias Pleroma.Web.ApiSpec.Schemas.Account + alias Pleroma.Web.ApiSpec.Schemas.FlakeID + alias Pleroma.Web.ApiSpec.Schemas.Status + + def open_api_operation(action) do + operation = String.to_existing_atom("#{action}_operation") + apply(__MODULE__, operation, []) + end + + def index_operation do + %Operation{ + tags: ["Emoji Reactions"], + summary: + "Get an object of emoji to account mappings with accounts that reacted to the post", + parameters: [ + Operation.parameter(:id, :path, FlakeID, "Status ID", required: true), + Operation.parameter(:emoji, :path, :string, "Filter by a single unicode emoji", + required: false + ) + ], + security: [%{"oAuth" => ["read:statuses"]}], + operationId: "EmojiReactionController.index", + responses: %{ + 200 => array_of_reactions_response() + } + } + end + + def create_operation do + %Operation{ + tags: ["Emoji Reactions"], + summary: "React to a post with a unicode emoji", + parameters: [ + Operation.parameter(:id, :path, FlakeID, "Status ID", required: true), + Operation.parameter(:emoji, :path, :string, "A single character unicode emoji", + required: true + ) + ], + security: [%{"oAuth" => ["write:statuses"]}], + operationId: "EmojiReactionController.create", + responses: %{ + 200 => Operation.response("Status", "application/json", Status) + } + } + end + + def delete_operation do + %Operation{ + tags: ["Emoji Reactions"], + summary: "Remove a reaction to a post with a unicode emoji", + parameters: [ + Operation.parameter(:id, :path, FlakeID, "Status ID", required: true), + Operation.parameter(:emoji, :path, :string, "A single character unicode emoji", + required: true + ) + ], + security: [%{"oAuth" => ["write:statuses"]}], + operationId: "EmojiReactionController.delete", + responses: %{ + 200 => Operation.response("Status", "application/json", Status) + } + } + end + + defp array_of_reactions_response do + Operation.response("Array of Emoji Reactions", "application/json", %Schema{ + type: :array, + items: emoji_reaction(), + example: [emoji_reaction().example] + }) + end + + defp emoji_reaction do + %Schema{ + title: "EmojiReaction", + type: :object, + properties: %{ + name: %Schema{type: :string, description: "Emoji"}, + count: %Schema{type: :integer, description: "Count of reactions with this emoji"}, + me: %Schema{type: :boolean, description: "Did I react with this emoji?"}, + accounts: %Schema{ + type: :array, + items: Account, + description: "Array of accounts reacted with this emoji" + } + }, + example: %{ + "name" => "😱", + "count" => 1, + "me" => false, + "accounts" => [Account.schema().example] + } + } + end +end diff --git a/lib/pleroma/web/api_spec/operations/pleroma_operation.ex b/lib/pleroma/web/api_spec/operations/pleroma_operation.ex index c6df5c854..7e46ba553 100644 --- a/lib/pleroma/web/api_spec/operations/pleroma_operation.ex +++ b/lib/pleroma/web/api_spec/operations/pleroma_operation.ex @@ -5,13 +5,11 @@ defmodule Pleroma.Web.ApiSpec.PleromaOperation do alias OpenApiSpex.Operation alias OpenApiSpex.Schema - alias Pleroma.Web.ApiSpec.Schemas.Account + alias Pleroma.Web.ApiSpec.NotificationOperation alias Pleroma.Web.ApiSpec.Schemas.ApiError - alias Pleroma.Web.ApiSpec.Schemas.FlakeID - alias Pleroma.Web.ApiSpec.Schemas.Status alias Pleroma.Web.ApiSpec.Schemas.Conversation + alias Pleroma.Web.ApiSpec.Schemas.FlakeID alias Pleroma.Web.ApiSpec.StatusOperation - alias Pleroma.Web.ApiSpec.NotificationOperation import Pleroma.Web.ApiSpec.Helpers @@ -20,92 +18,6 @@ defmodule Pleroma.Web.ApiSpec.PleromaOperation do apply(__MODULE__, operation, []) end - def emoji_reactions_by_operation do - %Operation{ - tags: ["Emoji Reactions"], - summary: - "Get an object of emoji to account mappings with accounts that reacted to the post", - parameters: [ - Operation.parameter(:id, :path, FlakeID, "Status ID", required: true), - Operation.parameter(:emoji, :path, :string, "Filter by a single unicode emoji", - required: false - ) - ], - security: [%{"oAuth" => ["read:statuses"]}], - operationId: "PleromaController.emoji_reactions_by", - responses: %{ - 200 => array_of_reactions_response() - } - } - end - - def react_with_emoji_operation do - %Operation{ - tags: ["Emoji Reactions"], - summary: "React to a post with a unicode emoji", - parameters: [ - Operation.parameter(:id, :path, FlakeID, "Status ID", required: true), - Operation.parameter(:emoji, :path, :string, "A single character unicode emoji", - required: true - ) - ], - security: [%{"oAuth" => ["write:statuses"]}], - operationId: "PleromaController.react_with_emoji", - responses: %{ - 200 => Operation.response("Status", "application/json", Status) - } - } - end - - def unreact_with_emoji_operation do - %Operation{ - tags: ["Emoji Reactions"], - summary: "Remove a reaction to a post with a unicode emoji", - parameters: [ - Operation.parameter(:id, :path, FlakeID, "Status ID", required: true), - Operation.parameter(:emoji, :path, :string, "A single character unicode emoji", - required: true - ) - ], - security: [%{"oAuth" => ["write:statuses"]}], - operationId: "PleromaController.unreact_with_emoji", - responses: %{ - 200 => Operation.response("Status", "application/json", Status) - } - } - end - - defp array_of_reactions_response do - Operation.response("Array of Emoji Reactions", "application/json", %Schema{ - type: :array, - items: emoji_reaction(), - example: [emoji_reaction().example] - }) - end - - defp emoji_reaction do - %Schema{ - title: "EmojiReaction", - type: :object, - properties: %{ - name: %Schema{type: :string, description: "Emoji"}, - count: %Schema{type: :integer, description: "Count of reactions with this emoji"}, - me: %Schema{type: :boolean, description: "Did I react with this emoji?"}, - accounts: %Schema{ - type: :array, - items: Account, - description: "Array of accounts reacted with this emoji" - } - }, - example: %{ - "name" => "😱", - "count" => 1, - "me" => false, - "accounts" => [Account.schema().example] - } - } - end - def conversation_operation do %Operation{ tags: ["Conversations"], diff --git a/lib/pleroma/web/pleroma_api/controllers/emoji_reaction_controller.ex b/lib/pleroma/web/pleroma_api/controllers/emoji_reaction_controller.ex new file mode 100644 index 000000000..a002912f3 --- /dev/null +++ b/lib/pleroma/web/pleroma_api/controllers/emoji_reaction_controller.ex @@ -0,0 +1,61 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.PleromaAPI.EmojiReactionController do + use Pleroma.Web, :controller + + alias Pleroma.Activity + alias Pleroma.Object + alias Pleroma.Plugs.OAuthScopesPlug + alias Pleroma.Web.CommonAPI + alias Pleroma.Web.MastodonAPI.StatusView + + plug(Pleroma.Web.ApiSpec.CastAndValidate) + plug(OAuthScopesPlug, %{scopes: ["write:statuses"]} when action in [:create, :delete]) + + plug( + OAuthScopesPlug, + %{scopes: ["read:statuses"], fallback: :proceed_unauthenticated} + when action == :index + ) + + defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.EmojiReactionOperation + + def index(%{assigns: %{user: user}} = conn, %{id: activity_id} = params) do + with %Activity{} = activity <- Activity.get_by_id_with_object(activity_id), + %Object{data: %{"reactions" => reactions}} when is_list(reactions) <- + Object.normalize(activity) do + reactions = filter(reactions, params) + render(conn, "index.json", emoji_reactions: reactions, user: user) + else + _e -> json(conn, []) + end + end + + defp filter(reactions, %{emoji: emoji}) when is_binary(emoji) do + Enum.filter(reactions, fn [e, _] -> e == emoji end) + end + + defp filter(reactions, _), do: reactions + + def create(%{assigns: %{user: user}} = conn, %{id: activity_id, emoji: emoji}) do + with {:ok, _activity} <- CommonAPI.react_with_emoji(activity_id, user, emoji) do + activity = Activity.get_by_id(activity_id) + + conn + |> put_view(StatusView) + |> render("show.json", activity: activity, for: user, as: :activity) + end + end + + def delete(%{assigns: %{user: user}} = conn, %{id: activity_id, emoji: emoji}) do + with {:ok, _activity} <- CommonAPI.unreact_with_emoji(activity_id, user, emoji) do + activity = Activity.get_by_id(activity_id) + + conn + |> put_view(StatusView) + |> render("show.json", activity: activity, for: user, as: :activity) + end + end +end diff --git a/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex b/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex index 8220d13bc..61273f7ee 100644 --- a/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex @@ -7,15 +7,10 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2] - alias Pleroma.Activity alias Pleroma.Conversation.Participation alias Pleroma.Notification - alias Pleroma.Object alias Pleroma.Plugs.OAuthScopesPlug - alias Pleroma.User alias Pleroma.Web.ActivityPub.ActivityPub - alias Pleroma.Web.CommonAPI - alias Pleroma.Web.MastodonAPI.AccountView alias Pleroma.Web.MastodonAPI.ConversationView alias Pleroma.Web.MastodonAPI.NotificationView alias Pleroma.Web.MastodonAPI.StatusView @@ -28,18 +23,6 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do when action in [:conversation, :conversation_statuses] ) - plug( - OAuthScopesPlug, - %{scopes: ["read:statuses"], fallback: :proceed_unauthenticated} - when action == :emoji_reactions_by - ) - - plug( - OAuthScopesPlug, - %{scopes: ["write:statuses"]} - when action in [:react_with_emoji, :unreact_with_emoji] - ) - plug( OAuthScopesPlug, %{scopes: ["write:conversations"]} @@ -53,66 +36,6 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.PleromaOperation - def emoji_reactions_by(%{assigns: %{user: user}} = conn, %{id: activity_id} = params) do - with %Activity{} = activity <- Activity.get_by_id_with_object(activity_id), - %Object{data: %{"reactions" => emoji_reactions}} when is_list(emoji_reactions) <- - Object.normalize(activity) do - reactions = - emoji_reactions - |> Enum.map(fn [emoji, user_ap_ids] -> - if params[:emoji] && params[:emoji] != emoji do - nil - else - users = - Enum.map(user_ap_ids, &User.get_cached_by_ap_id/1) - |> Enum.filter(fn - %{deactivated: false} -> true - _ -> false - end) - - %{ - name: emoji, - count: length(users), - accounts: - AccountView.render("index.json", %{ - users: users, - for: user, - as: :user - }), - me: !!(user && user.ap_id in user_ap_ids) - } - end - end) - |> Enum.reject(&is_nil/1) - - conn - |> json(reactions) - else - _e -> - conn - |> json([]) - end - end - - def react_with_emoji(%{assigns: %{user: user}} = conn, %{id: activity_id, emoji: emoji}) do - with {:ok, _activity} <- CommonAPI.react_with_emoji(activity_id, user, emoji), - activity <- Activity.get_by_id(activity_id) do - conn - |> put_view(StatusView) - |> render("show.json", %{activity: activity, for: user, as: :activity}) - end - end - - def unreact_with_emoji(%{assigns: %{user: user}} = conn, %{id: activity_id, emoji: emoji}) do - with {:ok, _activity} <- - CommonAPI.unreact_with_emoji(activity_id, user, emoji), - activity <- Activity.get_by_id(activity_id) do - conn - |> put_view(StatusView) - |> render("show.json", %{activity: activity, for: user, as: :activity}) - end - end - def conversation(%{assigns: %{user: user}} = conn, %{id: participation_id}) do with %Participation{} = participation <- Participation.get(participation_id), true <- user.id == participation.user_id do diff --git a/lib/pleroma/web/pleroma_api/views/emoji_reaction_view.ex b/lib/pleroma/web/pleroma_api/views/emoji_reaction_view.ex new file mode 100644 index 000000000..84d2d303d --- /dev/null +++ b/lib/pleroma/web/pleroma_api/views/emoji_reaction_view.ex @@ -0,0 +1,33 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.PleromaAPI.EmojiReactionView do + use Pleroma.Web, :view + + alias Pleroma.Web.MastodonAPI.AccountView + + def render("index.json", %{emoji_reactions: emoji_reactions} = opts) do + render_many(emoji_reactions, __MODULE__, "show.json", opts) + end + + def render("show.json", %{emoji_reaction: [emoji, user_ap_ids], user: user}) do + users = fetch_users(user_ap_ids) + + %{ + name: emoji, + count: length(users), + accounts: render(AccountView, "index.json", users: users, for: user, as: :user), + me: !!(user && user.ap_id in user_ap_ids) + } + end + + defp fetch_users(user_ap_ids) do + user_ap_ids + |> Enum.map(&Pleroma.User.get_cached_by_ap_id/1) + |> Enum.filter(fn + %{deactivated: false} -> true + _ -> false + end) + end +end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 369c54cf4..12381511e 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -297,8 +297,8 @@ defmodule Pleroma.Web.Router do scope "/api/v1/pleroma", Pleroma.Web.PleromaAPI do pipe_through(:api) - get("/statuses/:id/reactions/:emoji", PleromaAPIController, :emoji_reactions_by) - get("/statuses/:id/reactions", PleromaAPIController, :emoji_reactions_by) + get("/statuses/:id/reactions/:emoji", EmojiReactionController, :index) + get("/statuses/:id/reactions", EmojiReactionController, :index) end scope "/api/v1/pleroma", Pleroma.Web.PleromaAPI do @@ -314,8 +314,8 @@ defmodule Pleroma.Web.Router do pipe_through(:authenticated_api) patch("/conversations/:id", PleromaAPIController, :update_conversation) - put("/statuses/:id/reactions/:emoji", PleromaAPIController, :react_with_emoji) - delete("/statuses/:id/reactions/:emoji", PleromaAPIController, :unreact_with_emoji) + put("/statuses/:id/reactions/:emoji", EmojiReactionController, :create) + delete("/statuses/:id/reactions/:emoji", EmojiReactionController, :delete) post("/notifications/read", PleromaAPIController, :mark_notifications_as_read) patch("/accounts/update_avatar", AccountController, :update_avatar) -- cgit v1.2.3 From f3fc8b22b1dca8d432d066417e2bb9b62a3f1520 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Wed, 20 May 2020 15:00:11 +0400 Subject: Move conversation actions to PleromaAPI.ConversationController --- .../operations/pleroma_conversation_operation.ex | 106 +++++++++++++++++++++ .../web/api_spec/operations/pleroma_operation.ex | 93 ------------------ .../controllers/conversation_controller.ex | 95 ++++++++++++++++++ .../controllers/pleroma_api_controller.ex | 99 ------------------- lib/pleroma/web/router.ex | 12 +-- 5 files changed, 205 insertions(+), 200 deletions(-) create mode 100644 lib/pleroma/web/api_spec/operations/pleroma_conversation_operation.ex create mode 100644 lib/pleroma/web/pleroma_api/controllers/conversation_controller.ex (limited to 'lib') diff --git a/lib/pleroma/web/api_spec/operations/pleroma_conversation_operation.ex b/lib/pleroma/web/api_spec/operations/pleroma_conversation_operation.ex new file mode 100644 index 000000000..e885eab20 --- /dev/null +++ b/lib/pleroma/web/api_spec/operations/pleroma_conversation_operation.ex @@ -0,0 +1,106 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ApiSpec.PleromaConversationOperation do + alias OpenApiSpex.Operation + alias OpenApiSpex.Schema + alias Pleroma.Web.ApiSpec.Schemas.Conversation + alias Pleroma.Web.ApiSpec.Schemas.FlakeID + alias Pleroma.Web.ApiSpec.StatusOperation + + import Pleroma.Web.ApiSpec.Helpers + + def open_api_operation(action) do + operation = String.to_existing_atom("#{action}_operation") + apply(__MODULE__, operation, []) + end + + def show_operation do + %Operation{ + tags: ["Conversations"], + summary: "The conversation with the given ID", + parameters: [ + Operation.parameter(:id, :path, :string, "Conversation ID", + example: "123", + required: true + ) + ], + security: [%{"oAuth" => ["read:statuses"]}], + operationId: "PleromaAPI.ConversationController.show", + responses: %{ + 200 => Operation.response("Conversation", "application/json", Conversation) + } + } + end + + def statuses_operation do + %Operation{ + tags: ["Conversations"], + summary: "Timeline for a given conversation", + parameters: [ + Operation.parameter(:id, :path, :string, "Conversation ID", + example: "123", + required: true + ) + | pagination_params() + ], + security: [%{"oAuth" => ["read:statuses"]}], + operationId: "PleromaAPI.ConversationController.statuses", + responses: %{ + 200 => + Operation.response( + "Array of Statuses", + "application/json", + StatusOperation.array_of_statuses() + ) + } + } + end + + def update_operation do + %Operation{ + tags: ["Conversations"], + summary: "Update a conversation. Used to change the set of recipients.", + parameters: [ + Operation.parameter(:id, :path, :string, "Conversation ID", + example: "123", + required: true + ), + Operation.parameter( + :recipients, + :query, + %Schema{type: :array, items: FlakeID}, + "A list of ids of users that should receive posts to this conversation. This will replace the current list of recipients, so submit the full list. The owner of owner of the conversation will always be part of the set of recipients, though.", + required: true + ) + ], + security: [%{"oAuth" => ["write:conversations"]}], + operationId: "PleromaAPI.ConversationController.update", + responses: %{ + 200 => Operation.response("Conversation", "application/json", Conversation) + } + } + end + + def mark_as_read_operation do + %Operation{ + tags: ["Conversations"], + summary: "Marks all user's conversations as read", + security: [%{"oAuth" => ["write:conversations"]}], + operationId: "PleromaAPI.ConversationController.mark_as_read", + responses: %{ + 200 => + Operation.response( + "Array of Conversations that were marked as read", + "application/json", + %Schema{ + type: :array, + items: Conversation, + example: [Conversation.schema().example] + } + ) + } + } + end +end diff --git a/lib/pleroma/web/api_spec/operations/pleroma_operation.ex b/lib/pleroma/web/api_spec/operations/pleroma_operation.ex index 7e46ba553..d28451933 100644 --- a/lib/pleroma/web/api_spec/operations/pleroma_operation.ex +++ b/lib/pleroma/web/api_spec/operations/pleroma_operation.ex @@ -7,105 +7,12 @@ defmodule Pleroma.Web.ApiSpec.PleromaOperation do alias OpenApiSpex.Schema alias Pleroma.Web.ApiSpec.NotificationOperation alias Pleroma.Web.ApiSpec.Schemas.ApiError - alias Pleroma.Web.ApiSpec.Schemas.Conversation - alias Pleroma.Web.ApiSpec.Schemas.FlakeID - alias Pleroma.Web.ApiSpec.StatusOperation - - import Pleroma.Web.ApiSpec.Helpers def open_api_operation(action) do operation = String.to_existing_atom("#{action}_operation") apply(__MODULE__, operation, []) end - def conversation_operation do - %Operation{ - tags: ["Conversations"], - summary: "The conversation with the given ID", - parameters: [ - Operation.parameter(:id, :path, :string, "Conversation ID", - example: "123", - required: true - ) - ], - security: [%{"oAuth" => ["read:statuses"]}], - operationId: "PleromaController.conversation", - responses: %{ - 200 => Operation.response("Conversation", "application/json", Conversation) - } - } - end - - def conversation_statuses_operation do - %Operation{ - tags: ["Conversations"], - summary: "Timeline for a given conversation", - parameters: [ - Operation.parameter(:id, :path, :string, "Conversation ID", - example: "123", - required: true - ) - | pagination_params() - ], - security: [%{"oAuth" => ["read:statuses"]}], - operationId: "PleromaController.conversation_statuses", - responses: %{ - 200 => - Operation.response( - "Array of Statuses", - "application/json", - StatusOperation.array_of_statuses() - ) - } - } - end - - def update_conversation_operation do - %Operation{ - tags: ["Conversations"], - summary: "Update a conversation. Used to change the set of recipients.", - parameters: [ - Operation.parameter(:id, :path, :string, "Conversation ID", - example: "123", - required: true - ), - Operation.parameter( - :recipients, - :query, - %Schema{type: :array, items: FlakeID}, - "A list of ids of users that should receive posts to this conversation. This will replace the current list of recipients, so submit the full list. The owner of owner of the conversation will always be part of the set of recipients, though.", - required: true - ) - ], - security: [%{"oAuth" => ["write:conversations"]}], - operationId: "PleromaController.update_conversation", - responses: %{ - 200 => Operation.response("Conversation", "application/json", Conversation) - } - } - end - - def mark_conversations_as_read_operation do - %Operation{ - tags: ["Conversations"], - summary: "Marks all user's conversations as read", - security: [%{"oAuth" => ["write:conversations"]}], - operationId: "PleromaController.mark_conversations_as_read", - responses: %{ - 200 => - Operation.response( - "Array of Conversations that were marked as read", - "application/json", - %Schema{ - type: :array, - items: Conversation, - example: [Conversation.schema().example] - } - ) - } - } - end - def mark_notifications_as_read_operation do %Operation{ tags: ["Notifications"], diff --git a/lib/pleroma/web/pleroma_api/controllers/conversation_controller.ex b/lib/pleroma/web/pleroma_api/controllers/conversation_controller.ex new file mode 100644 index 000000000..21d5eb8d5 --- /dev/null +++ b/lib/pleroma/web/pleroma_api/controllers/conversation_controller.ex @@ -0,0 +1,95 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.PleromaAPI.ConversationController do + use Pleroma.Web, :controller + + import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2] + + alias Pleroma.Conversation.Participation + alias Pleroma.Plugs.OAuthScopesPlug + alias Pleroma.Web.ActivityPub.ActivityPub + alias Pleroma.Web.MastodonAPI.StatusView + + plug(Pleroma.Web.ApiSpec.CastAndValidate) + plug(:put_view, Pleroma.Web.MastodonAPI.ConversationView) + plug(OAuthScopesPlug, %{scopes: ["read:statuses"]} when action in [:show, :statuses]) + + plug( + OAuthScopesPlug, + %{scopes: ["write:conversations"]} when action in [:update, :mark_as_read] + ) + + defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.PleromaConversationOperation + + def show(%{assigns: %{user: %{id: user_id} = user}} = conn, %{id: participation_id}) do + with %Participation{user_id: ^user_id} = participation <- Participation.get(participation_id) do + render(conn, "participation.json", participation: participation, for: user) + else + _error -> + conn + |> put_status(:not_found) + |> json(%{"error" => "Unknown conversation id"}) + end + end + + def statuses( + %{assigns: %{user: %{id: user_id} = user}} = conn, + %{id: participation_id} = params + ) do + with %Participation{user_id: ^user_id} = participation <- + Participation.get(participation_id, preload: [:conversation]) do + params = + params + |> Map.new(fn {key, value} -> {to_string(key), value} end) + |> Map.put("blocking_user", user) + |> Map.put("muting_user", user) + |> Map.put("user", user) + + activities = + participation.conversation.ap_id + |> ActivityPub.fetch_activities_for_context_query(params) + |> Pleroma.Pagination.fetch_paginated(Map.put(params, "total", false)) + |> Enum.reverse() + + conn + |> add_link_headers(activities) + |> put_view(StatusView) + |> render("index.json", activities: activities, for: user, as: :activity) + else + _error -> + conn + |> put_status(:not_found) + |> json(%{"error" => "Unknown conversation id"}) + end + end + + def update( + %{assigns: %{user: %{id: user_id} = user}} = conn, + %{id: participation_id, recipients: recipients} + ) do + with %Participation{user_id: ^user_id} = participation <- Participation.get(participation_id), + {:ok, participation} <- Participation.set_recipients(participation, recipients) do + render(conn, "participation.json", participation: participation, for: user) + else + {:error, message} -> + conn + |> put_status(:bad_request) + |> json(%{"error" => message}) + + _error -> + conn + |> put_status(:not_found) + |> json(%{"error" => "Unknown conversation id"}) + end + end + + def mark_as_read(%{assigns: %{user: user}} = conn, _params) do + with {:ok, _, participations} <- Participation.mark_all_as_read(user) do + conn + |> add_link_headers(participations) + |> render("participations.json", participations: participations, for: user) + end + end +end diff --git a/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex b/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex index 61273f7ee..a58665abe 100644 --- a/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex @@ -5,30 +5,12 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do use Pleroma.Web, :controller - import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2] - - alias Pleroma.Conversation.Participation alias Pleroma.Notification alias Pleroma.Plugs.OAuthScopesPlug - alias Pleroma.Web.ActivityPub.ActivityPub - alias Pleroma.Web.MastodonAPI.ConversationView alias Pleroma.Web.MastodonAPI.NotificationView - alias Pleroma.Web.MastodonAPI.StatusView plug(Pleroma.Web.ApiSpec.CastAndValidate) - plug( - OAuthScopesPlug, - %{scopes: ["read:statuses"]} - when action in [:conversation, :conversation_statuses] - ) - - plug( - OAuthScopesPlug, - %{scopes: ["write:conversations"]} - when action in [:update_conversation, :mark_conversations_as_read] - ) - plug( OAuthScopesPlug, %{scopes: ["write:notifications"]} when action == :mark_notifications_as_read @@ -36,87 +18,6 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.PleromaOperation - def conversation(%{assigns: %{user: user}} = conn, %{id: participation_id}) do - with %Participation{} = participation <- Participation.get(participation_id), - true <- user.id == participation.user_id do - conn - |> put_view(ConversationView) - |> render("participation.json", %{participation: participation, for: user}) - else - _error -> - conn - |> put_status(404) - |> json(%{"error" => "Unknown conversation id"}) - end - end - - def conversation_statuses( - %{assigns: %{user: %{id: user_id} = user}} = conn, - %{id: participation_id} = params - ) do - with %Participation{user_id: ^user_id} = participation <- - Participation.get(participation_id, preload: [:conversation]) do - params = - params - |> Map.new(fn {key, value} -> {to_string(key), value} end) - |> Map.put("blocking_user", user) - |> Map.put("muting_user", user) - |> Map.put("user", user) - - activities = - participation.conversation.ap_id - |> ActivityPub.fetch_activities_for_context_query(params) - |> Pleroma.Pagination.fetch_paginated(Map.put(params, "total", false)) - |> Enum.reverse() - - conn - |> add_link_headers(activities) - |> put_view(StatusView) - |> render("index.json", - activities: activities, - for: user, - as: :activity - ) - else - _error -> - conn - |> put_status(404) - |> json(%{"error" => "Unknown conversation id"}) - end - end - - def update_conversation( - %{assigns: %{user: user}} = conn, - %{id: participation_id, recipients: recipients} - ) do - with %Participation{} = participation <- Participation.get(participation_id), - true <- user.id == participation.user_id, - {:ok, participation} <- Participation.set_recipients(participation, recipients) do - conn - |> put_view(ConversationView) - |> render("participation.json", %{participation: participation, for: user}) - else - {:error, message} -> - conn - |> put_status(:bad_request) - |> json(%{"error" => message}) - - _error -> - conn - |> put_status(404) - |> json(%{"error" => "Unknown conversation id"}) - end - end - - def mark_conversations_as_read(%{assigns: %{user: user}} = conn, _params) do - with {:ok, _, participations} <- Participation.mark_all_as_read(user) do - conn - |> add_link_headers(participations) - |> put_view(ConversationView) - |> render("participations.json", participations: participations, for: user) - end - end - def mark_notifications_as_read(%{assigns: %{user: user}} = conn, %{id: notification_id}) do with {:ok, notification} <- Notification.read_one(user, notification_id) do conn diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 12381511e..78da4a871 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -305,15 +305,11 @@ defmodule Pleroma.Web.Router do scope [] do pipe_through(:authenticated_api) - get("/conversations/:id/statuses", PleromaAPIController, :conversation_statuses) - get("/conversations/:id", PleromaAPIController, :conversation) - post("/conversations/read", PleromaAPIController, :mark_conversations_as_read) - end - - scope [] do - pipe_through(:authenticated_api) + get("/conversations/:id/statuses", ConversationController, :statuses) + get("/conversations/:id", ConversationController, :show) + post("/conversations/read", ConversationController, :mark_as_read) + patch("/conversations/:id", ConversationController, :update) - patch("/conversations/:id", PleromaAPIController, :update_conversation) put("/statuses/:id/reactions/:emoji", EmojiReactionController, :create) delete("/statuses/:id/reactions/:emoji", EmojiReactionController, :delete) post("/notifications/read", PleromaAPIController, :mark_notifications_as_read) -- cgit v1.2.3 From 5ba6e1c322c0937849eca53fc816f348659fb34c Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Wed, 20 May 2020 15:14:11 +0400 Subject: Move notification actions to PleromaAPI.NotificationController --- .../operations/pleroma_notification_operation.ex | 42 ++++++++++++++++++++ .../web/api_spec/operations/pleroma_operation.ex | 42 -------------------- .../controllers/notification_controller.ex | 36 +++++++++++++++++ .../controllers/pleroma_api_controller.ex | 46 ---------------------- lib/pleroma/web/router.ex | 2 +- 5 files changed, 79 insertions(+), 89 deletions(-) create mode 100644 lib/pleroma/web/api_spec/operations/pleroma_notification_operation.ex delete mode 100644 lib/pleroma/web/api_spec/operations/pleroma_operation.ex create mode 100644 lib/pleroma/web/pleroma_api/controllers/notification_controller.ex delete mode 100644 lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex (limited to 'lib') diff --git a/lib/pleroma/web/api_spec/operations/pleroma_notification_operation.ex b/lib/pleroma/web/api_spec/operations/pleroma_notification_operation.ex new file mode 100644 index 000000000..636c39a15 --- /dev/null +++ b/lib/pleroma/web/api_spec/operations/pleroma_notification_operation.ex @@ -0,0 +1,42 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ApiSpec.PleromaNotificationOperation do + alias OpenApiSpex.Operation + alias OpenApiSpex.Schema + alias Pleroma.Web.ApiSpec.NotificationOperation + alias Pleroma.Web.ApiSpec.Schemas.ApiError + + def open_api_operation(action) do + operation = String.to_existing_atom("#{action}_operation") + apply(__MODULE__, operation, []) + end + + def mark_as_read_operation do + %Operation{ + tags: ["Notifications"], + summary: "Mark notifications as read. Query parameters are mutually exclusive.", + parameters: [ + Operation.parameter(:id, :query, :string, "A single notification ID to read"), + Operation.parameter(:max_id, :query, :string, "Read all notifications up to this id") + ], + security: [%{"oAuth" => ["write:notifications"]}], + operationId: "PleromaAPI.NotificationController.mark_as_read", + responses: %{ + 200 => + Operation.response( + "A Notification or array of Motifications", + "application/json", + %Schema{ + anyOf: [ + %Schema{type: :array, items: NotificationOperation.notification()}, + NotificationOperation.notification() + ] + } + ), + 400 => Operation.response("Bad Request", "application/json", ApiError) + } + } + end +end diff --git a/lib/pleroma/web/api_spec/operations/pleroma_operation.ex b/lib/pleroma/web/api_spec/operations/pleroma_operation.ex deleted file mode 100644 index d28451933..000000000 --- a/lib/pleroma/web/api_spec/operations/pleroma_operation.ex +++ /dev/null @@ -1,42 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.ApiSpec.PleromaOperation do - alias OpenApiSpex.Operation - alias OpenApiSpex.Schema - alias Pleroma.Web.ApiSpec.NotificationOperation - alias Pleroma.Web.ApiSpec.Schemas.ApiError - - def open_api_operation(action) do - operation = String.to_existing_atom("#{action}_operation") - apply(__MODULE__, operation, []) - end - - def mark_notifications_as_read_operation do - %Operation{ - tags: ["Notifications"], - summary: "Mark notifications as read. Query parameters are mutually exclusive.", - parameters: [ - Operation.parameter(:id, :query, :string, "A single notification ID to read"), - Operation.parameter(:max_id, :query, :string, "Read all notifications up to this id") - ], - security: [%{"oAuth" => ["write:notifications"]}], - operationId: "PleromaController.mark_notifications_as_read", - responses: %{ - 200 => - Operation.response( - "A Notification or array of Motifications", - "application/json", - %Schema{ - anyOf: [ - %Schema{type: :array, items: NotificationOperation.notification()}, - NotificationOperation.notification() - ] - } - ), - 400 => Operation.response("Bad Request", "application/json", ApiError) - } - } - end -end diff --git a/lib/pleroma/web/pleroma_api/controllers/notification_controller.ex b/lib/pleroma/web/pleroma_api/controllers/notification_controller.ex new file mode 100644 index 000000000..0b2f678c5 --- /dev/null +++ b/lib/pleroma/web/pleroma_api/controllers/notification_controller.ex @@ -0,0 +1,36 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.PleromaAPI.NotificationController do + use Pleroma.Web, :controller + + alias Pleroma.Notification + alias Pleroma.Plugs.OAuthScopesPlug + + plug(Pleroma.Web.ApiSpec.CastAndValidate) + plug(OAuthScopesPlug, %{scopes: ["write:notifications"]} when action == :mark_as_read) + plug(:put_view, Pleroma.Web.MastodonAPI.NotificationView) + + defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.PleromaNotificationOperation + + def mark_as_read(%{assigns: %{user: user}} = conn, %{id: notification_id}) do + with {:ok, notification} <- Notification.read_one(user, notification_id) do + render(conn, "show.json", notification: notification, for: user) + else + {:error, message} -> + conn + |> put_status(:bad_request) + |> json(%{"error" => message}) + end + end + + def mark_as_read(%{assigns: %{user: user}} = conn, %{max_id: max_id}) do + notifications = + user + |> Notification.set_read_up_to(max_id) + |> Enum.take(80) + + render(conn, "index.json", notifications: notifications, for: user) + end +end diff --git a/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex b/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex deleted file mode 100644 index a58665abe..000000000 --- a/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex +++ /dev/null @@ -1,46 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do - use Pleroma.Web, :controller - - alias Pleroma.Notification - alias Pleroma.Plugs.OAuthScopesPlug - alias Pleroma.Web.MastodonAPI.NotificationView - - plug(Pleroma.Web.ApiSpec.CastAndValidate) - - plug( - OAuthScopesPlug, - %{scopes: ["write:notifications"]} when action == :mark_notifications_as_read - ) - - defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.PleromaOperation - - def mark_notifications_as_read(%{assigns: %{user: user}} = conn, %{id: notification_id}) do - with {:ok, notification} <- Notification.read_one(user, notification_id) do - conn - |> put_view(NotificationView) - |> render("show.json", %{notification: notification, for: user}) - else - {:error, message} -> - conn - |> put_status(:bad_request) - |> json(%{"error" => message}) - end - end - - def mark_notifications_as_read(%{assigns: %{user: user}} = conn, %{max_id: max_id}) do - with notifications <- Notification.set_read_up_to(user, max_id) do - notifications = Enum.take(notifications, 80) - - conn - |> put_view(NotificationView) - |> render("index.json", - notifications: notifications, - for: user - ) - end - end -end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 78da4a871..0e29e5645 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -312,7 +312,7 @@ defmodule Pleroma.Web.Router do put("/statuses/:id/reactions/:emoji", EmojiReactionController, :create) delete("/statuses/:id/reactions/:emoji", EmojiReactionController, :delete) - post("/notifications/read", PleromaAPIController, :mark_notifications_as_read) + post("/notifications/read", NotificationController, :mark_as_read) patch("/accounts/update_avatar", AccountController, :update_avatar) patch("/accounts/update_banner", AccountController, :update_banner) -- cgit v1.2.3 From 9bc5e18adeef2c68c5fae2435ed01555f1b29c93 Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Thu, 21 May 2020 08:06:57 +0300 Subject: rename mix task: `pleroma.user unsubscribe` -> `pleroma.user deactivate` --- lib/mix/tasks/pleroma/user.ex | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/user.ex b/lib/mix/tasks/pleroma/user.ex index 93ecb4631..3635c02bc 100644 --- a/lib/mix/tasks/pleroma/user.ex +++ b/lib/mix/tasks/pleroma/user.ex @@ -144,7 +144,7 @@ defmodule Mix.Tasks.Pleroma.User do end end - def run(["unsubscribe", nickname]) do + def run(["deactivate", nickname]) do start_pleroma() with %User{} = user <- User.get_cached_by_nickname(nickname) do @@ -163,7 +163,7 @@ defmodule Mix.Tasks.Pleroma.User do end end - def run(["unsubscribe_all_from_instance", instance]) do + def run(["deactivate_all_from_instance", instance]) do start_pleroma() Pleroma.User.Query.build(%{nickname: "@#{instance}"}) @@ -171,7 +171,7 @@ defmodule Mix.Tasks.Pleroma.User do |> Stream.each(fn users -> users |> Enum.each(fn user -> - run(["unsubscribe", user.nickname]) + run(["deactivate", user.nickname]) end) end) |> Stream.run() -- cgit v1.2.3