From 6e1ec4c5da6da4bd301080a8c35f8483d89e095f Mon Sep 17 00:00:00 2001 From: lain Date: Mon, 26 Aug 2019 16:29:51 -0500 Subject: ActivityPub: Basic EmojiReactions. --- lib/pleroma/web/activity_pub/activity_pub.ex | 10 ++++++++++ lib/pleroma/web/activity_pub/utils.ex | 10 ++++++++++ 2 files changed, 20 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 172c952d4..a6088a012 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -312,6 +312,16 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do end end + def react_with_emoji(user, object, emoji, options \\ []) do + with local <- Keyword.get(options, :local, true), + activity_id <- Keyword.get(options, :activity_id, nil), + is_emoji?(emoji), + reaction_data <- make_emoji_reaction_data(user, object, emoji, activity_id), + {:ok, activity} <- insert(reaction_data, local) do + {:ok, activity, object} + end + end + # TODO: This is weird, maybe we shouldn't check here if we can make the activity. def like( %User{ap_id: ap_id} = user, diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index 1c3058658..d57830da3 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -296,6 +296,16 @@ defmodule Pleroma.Web.ActivityPub.Utils do Repo.all(query) end + def is_emoji?(emoji) do + String.length(emoji) == 1 + end + + def make_emoji_reaction_data(user, object, emoji, activity_id) do + make_like_data(user, object, activity_id) + |> Map.put("type", "EmojiReaction") + |> Map.put("content", emoji) + end + def make_like_data( %User{ap_id: ap_id} = actor, %{data: %{"actor" => object_actor_id, "id" => id}} = object, -- cgit v1.2.3 From a0b21c89284304bea90f2774f17d5b2b7b3c1359 Mon Sep 17 00:00:00 2001 From: lain Date: Mon, 26 Aug 2019 16:47:31 -0500 Subject: Transmogrifier: Handle incoming emoji reactions. --- lib/pleroma/web/activity_pub/transmogrifier.ex | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index 36340a3a1..9132df8cb 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -572,6 +572,27 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do end end + def handle_incoming( + %{ + "type" => "EmojiReaction", + "object" => object_id, + "actor" => _actor, + "id" => id, + "content" => emoji + } = data, + _options + ) do + with actor <- Containment.get_actor(data), + {:ok, %User{} = actor} <- User.get_or_fetch_by_ap_id(actor), + {:ok, object} <- get_obj_helper(object_id), + {:ok, activity, _object} <- + ActivityPub.react_with_emoji(actor, object, emoji, activity_id: id, local: false) do + {:ok, activity} + else + _e -> :error + end + end + def handle_incoming( %{"type" => "Announce", "object" => object_id, "actor" => _actor, "id" => id} = data, _options -- cgit v1.2.3 From b770ed1d9940230d4bd97113abdc220ca7d8eb1a Mon Sep 17 00:00:00 2001 From: lain Date: Tue, 27 Aug 2019 17:56:28 -0500 Subject: CommonAPI: Support emoji reactions. --- lib/pleroma/web/common_api/common_api.ex | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex index 5faddc9f4..3e1aa4818 100644 --- a/lib/pleroma/web/common_api/common_api.ex +++ b/lib/pleroma/web/common_api/common_api.ex @@ -123,6 +123,16 @@ defmodule Pleroma.Web.CommonAPI do end end + def react_with_emoji(id, user, emoji) do + with %Activity{} = activity <- Activity.get_by_id(id), + object <- Object.normalize(activity) do + ActivityPub.react_with_emoji(user, object, emoji) + else + _ -> + {:error, dgettext("errors", "Could not add reaction emoji")} + end + end + def vote(user, object, choices) do with "Question" <- object.data["type"], {:author, false} <- {:author, object.data["actor"] == user.ap_id}, -- cgit v1.2.3 From 9bc12b88b3b4b90ee1b55ebf49a13665a751ef1a Mon Sep 17 00:00:00 2001 From: lain Date: Tue, 3 Sep 2019 16:50:04 -0500 Subject: ActivityPub: Save emoji reactions in object. --- lib/pleroma/web/activity_pub/activity_pub.ex | 3 ++- lib/pleroma/web/activity_pub/utils.ex | 27 ++++++++++++++++++++++++++- 2 files changed, 28 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 532db17c4..6cd168427 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -317,7 +317,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do activity_id <- Keyword.get(options, :activity_id, nil), is_emoji?(emoji), reaction_data <- make_emoji_reaction_data(user, object, emoji, activity_id), - {:ok, activity} <- insert(reaction_data, local) do + {:ok, activity} <- insert(reaction_data, local), + {:ok, object} <- add_emoji_reaction_to_object(activity, object) do {:ok, activity, object} end end diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index 32e22d8d7..1e6a67deb 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -321,10 +321,21 @@ defmodule Pleroma.Web.ActivityPub.Utils do @spec update_element_in_object(String.t(), list(any), Object.t()) :: {:ok, Object.t()} | {:error, Ecto.Changeset.t()} def update_element_in_object(property, element, object) do + length = + if is_map(element) do + element + |> Map.values() + |> List.flatten() + |> length() + else + element + |> length() + end + data = Map.merge( object.data, - %{"#{property}_count" => length(element), "#{property}s" => element} + %{"#{property}_count" => length, "#{property}s" => element} ) object @@ -332,6 +343,20 @@ defmodule Pleroma.Web.ActivityPub.Utils do |> Object.update_and_set_cache() end + @spec add_emoji_reaction_to_object(Activity.t(), Object.t()) :: + {:ok, Object.t()} | {:error, Ecto.Changeset.t()} + + def add_emoji_reaction_to_object( + %Activity{data: %{"content" => emoji, "actor" => actor}}, + object + ) do + reactions = object.data["reactions"] || %{} + emoji_actors = reactions[emoji] || [] + new_emoji_actors = [actor | emoji_actors] |> Enum.uniq() + new_reactions = Map.put(reactions, emoji, new_emoji_actors) + update_element_in_object("reaction", new_reactions, object) + end + @spec add_like_to_object(Activity.t(), Object.t()) :: {:ok, Object.t()} | {:error, Ecto.Changeset.t()} def add_like_to_object(%Activity{data: %{"actor" => actor}}, object) do -- cgit v1.2.3 From 99ea990a16a417cd316b3464ef380746171ecb55 Mon Sep 17 00:00:00 2001 From: lain Date: Wed, 4 Sep 2019 12:20:35 -0500 Subject: PleromaAPIController: Add emoji reactions. --- lib/pleroma/web/pleroma_api/pleroma_api_controller.ex | 11 +++++++++++ lib/pleroma/web/router.ex | 1 + 2 files changed, 12 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/web/pleroma_api/pleroma_api_controller.ex b/lib/pleroma/web/pleroma_api/pleroma_api_controller.ex index b6d2bf86b..740ea4747 100644 --- a/lib/pleroma/web/pleroma_api/pleroma_api_controller.ex +++ b/lib/pleroma/web/pleroma_api/pleroma_api_controller.ex @@ -7,11 +7,22 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do import Pleroma.Web.ControllerHelper, only: [add_link_headers: 7] + alias Pleroma.Activity alias Pleroma.Conversation.Participation alias Pleroma.Web.ActivityPub.ActivityPub + alias Pleroma.Web.CommonAPI alias Pleroma.Web.MastodonAPI.ConversationView alias Pleroma.Web.MastodonAPI.StatusView + def react_with_emoji(%{assigns: %{user: user}} = conn, %{"id" => activity_id, "emoji" => emoji}) do + with {:ok, _activity, _object} <- CommonAPI.react_with_emoji(activity_id, user, emoji), + activity = Activity.get_by_id(activity_id) do + conn + |> put_view(StatusView) + |> render("status.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/router.ex b/lib/pleroma/web/router.ex index 969dc66fd..6cca54211 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -277,6 +277,7 @@ defmodule Pleroma.Web.Router do scope [] do pipe_through(:oauth_write) patch("/conversations/:id", PleromaAPIController, :update_conversation) + post("/statuses/:id/react_with_emoji", PleromaAPIController, :react_with_emoji) end end -- cgit v1.2.3 From 05e9776517498370ab8f7b7afa0408f6ee979844 Mon Sep 17 00:00:00 2001 From: lain Date: Thu, 12 Sep 2019 18:48:25 +0200 Subject: PleromaAPIController: Add endpoint to fetch emoji reactions. --- .../web/pleroma_api/pleroma_api_controller.ex | 28 ++++++++++++++++++++++ lib/pleroma/web/router.ex | 6 +++++ 2 files changed, 34 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/web/pleroma_api/pleroma_api_controller.ex b/lib/pleroma/web/pleroma_api/pleroma_api_controller.ex index 740ea4747..bb090d37f 100644 --- a/lib/pleroma/web/pleroma_api/pleroma_api_controller.ex +++ b/lib/pleroma/web/pleroma_api/pleroma_api_controller.ex @@ -8,12 +8,40 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do import Pleroma.Web.ControllerHelper, only: [add_link_headers: 7] alias Pleroma.Activity + alias Pleroma.Object + alias Pleroma.User alias Pleroma.Conversation.Participation alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.CommonAPI + alias Pleroma.Web.MastodonAPI.AccountView alias Pleroma.Web.MastodonAPI.ConversationView alias Pleroma.Web.MastodonAPI.StatusView + def emoji_reactions_by(%{assigns: %{user: user}} = conn, %{"id" => activity_id}) do + with %Activity{} = activity <- Activity.get_by_id_with_object(activity_id), + %Object{data: %{"reactions" => emoji_reactions}} <- Object.normalize(activity) do + reactions = + Enum.reduce(emoji_reactions, %{}, fn {emoji, users}, res -> + users = + users + |> Enum.map(&User.get_cached_by_ap_id/1) + + res + |> Map.put( + emoji, + AccountView.render("accounts.json", %{users: users, for: user, as: :user}) + ) + end) + + 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, _object} <- CommonAPI.react_with_emoji(activity_id, user, emoji), activity = Activity.get_by_id(activity_id) do diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 6cca54211..ec6179420 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -265,6 +265,12 @@ defmodule Pleroma.Web.Router do end end + scope "/api/v1/pleroma", Pleroma.Web.PleromaAPI do + pipe_through(:api) + + get("/statuses/:id/emoji_reactions_by", PleromaAPIController, :emoji_reactions_by) + end + scope "/api/v1/pleroma", Pleroma.Web.PleromaAPI do pipe_through(:authenticated_api) -- cgit v1.2.3 From 8d4b661ecb549ba554815ca55a29ec5872c68380 Mon Sep 17 00:00:00 2001 From: lain Date: Thu, 12 Sep 2019 18:59:13 +0200 Subject: Transmogrifier: Strip internal emoji reaction fields. --- lib/pleroma/web/activity_pub/transmogrifier.ex | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index 9132df8cb..0b9cc4499 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -995,9 +995,11 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do |> Map.put("attachment", attachments) end - defp strip_internal_fields(object) do + def strip_internal_fields(object) do object |> Map.drop([ + "reactions", + "reaction_count", "likes", "like_count", "announcements", -- cgit v1.2.3 From a697f0d79148358da828d24ebfe12bbb9bb33b34 Mon Sep 17 00:00:00 2001 From: lain Date: Fri, 13 Sep 2019 02:11:02 +0200 Subject: Emoji: Add function to detect if a character is an emoji --- lib/pleroma/emoji-data.txt | 769 +++++++++++++++++++++++++++++++++++++++++++++ lib/pleroma/emoji.ex | 25 ++ 2 files changed, 794 insertions(+) create mode 100644 lib/pleroma/emoji-data.txt (limited to 'lib') diff --git a/lib/pleroma/emoji-data.txt b/lib/pleroma/emoji-data.txt new file mode 100644 index 000000000..2fb5c3ff6 --- /dev/null +++ b/lib/pleroma/emoji-data.txt @@ -0,0 +1,769 @@ +# emoji-data.txt +# Date: 2019-01-15, 12:10:05 GMT +# © 2019 Unicode®, Inc. +# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. +# For terms of use, see http://www.unicode.org/terms_of_use.html +# +# Emoji Data for UTS #51 +# Version: 12.0 +# +# For documentation and usage, see http://www.unicode.org/reports/tr51 +# +# Format: +# ; # +# Note: there is no guarantee as to the structure of whitespace or comments +# +# Characters and sequences are listed in code point order. Users should be shown a more natural order. +# See the CLDR collation order for Emoji. + + +# ================================================ + +# All omitted code points have Emoji=No +# @missing: 0000..10FFFF ; Emoji ; No + +0023 ; Emoji # 1.1 [1] (#️) number sign +002A ; Emoji # 1.1 [1] (*️) asterisk +0030..0039 ; Emoji # 1.1 [10] (0️..9️) digit zero..digit nine +00A9 ; Emoji # 1.1 [1] (©️) copyright +00AE ; Emoji # 1.1 [1] (®️) registered +203C ; Emoji # 1.1 [1] (‼️) double exclamation mark +2049 ; Emoji # 3.0 [1] (⁉️) exclamation question mark +2122 ; Emoji # 1.1 [1] (™️) trade mark +2139 ; Emoji # 3.0 [1] (ℹ️) information +2194..2199 ; Emoji # 1.1 [6] (↔️..↙️) left-right arrow..down-left arrow +21A9..21AA ; Emoji # 1.1 [2] (↩️..↪️) right arrow curving left..left arrow curving right +231A..231B ; Emoji # 1.1 [2] (⌚..⌛) watch..hourglass done +2328 ; Emoji # 1.1 [1] (⌨️) keyboard +23CF ; Emoji # 4.0 [1] (⏏️) eject button +23E9..23F3 ; Emoji # 6.0 [11] (⏩..⏳) fast-forward button..hourglass not done +23F8..23FA ; Emoji # 7.0 [3] (⏸️..⏺️) pause button..record button +24C2 ; Emoji # 1.1 [1] (Ⓜ️) circled M +25AA..25AB ; Emoji # 1.1 [2] (▪️..▫️) black small square..white small square +25B6 ; Emoji # 1.1 [1] (▶️) play button +25C0 ; Emoji # 1.1 [1] (◀️) reverse button +25FB..25FE ; Emoji # 3.2 [4] (◻️..◾) white medium square..black medium-small square +2600..2604 ; Emoji # 1.1 [5] (☀️..☄️) sun..comet +260E ; Emoji # 1.1 [1] (☎️) telephone +2611 ; Emoji # 1.1 [1] (☑️) check box with check +2614..2615 ; Emoji # 4.0 [2] (☔..☕) umbrella with rain drops..hot beverage +2618 ; Emoji # 4.1 [1] (☘️) shamrock +261D ; Emoji # 1.1 [1] (☝️) index pointing up +2620 ; Emoji # 1.1 [1] (☠️) skull and crossbones +2622..2623 ; Emoji # 1.1 [2] (☢️..☣️) radioactive..biohazard +2626 ; Emoji # 1.1 [1] (☦️) orthodox cross +262A ; Emoji # 1.1 [1] (☪️) star and crescent +262E..262F ; Emoji # 1.1 [2] (☮️..☯️) peace symbol..yin yang +2638..263A ; Emoji # 1.1 [3] (☸️..☺️) wheel of dharma..smiling face +2640 ; Emoji # 1.1 [1] (♀️) female sign +2642 ; Emoji # 1.1 [1] (♂️) male sign +2648..2653 ; Emoji # 1.1 [12] (♈..♓) Aries..Pisces +265F..2660 ; Emoji # 1.1 [2] (♟️..♠️) chess pawn..spade suit +2663 ; Emoji # 1.1 [1] (♣️) club suit +2665..2666 ; Emoji # 1.1 [2] (♥️..♦️) heart suit..diamond suit +2668 ; Emoji # 1.1 [1] (♨️) hot springs +267B ; Emoji # 3.2 [1] (♻️) recycling symbol +267E..267F ; Emoji # 4.1 [2] (♾️..♿) infinity..wheelchair symbol +2692..2697 ; Emoji # 4.1 [6] (⚒️..⚗️) hammer and pick..alembic +2699 ; Emoji # 4.1 [1] (⚙️) gear +269B..269C ; Emoji # 4.1 [2] (⚛️..⚜️) atom symbol..fleur-de-lis +26A0..26A1 ; Emoji # 4.0 [2] (⚠️..⚡) warning..high voltage +26AA..26AB ; Emoji # 4.1 [2] (⚪..⚫) white circle..black circle +26B0..26B1 ; Emoji # 4.1 [2] (⚰️..⚱️) coffin..funeral urn +26BD..26BE ; Emoji # 5.2 [2] (⚽..⚾) soccer ball..baseball +26C4..26C5 ; Emoji # 5.2 [2] (⛄..⛅) snowman without snow..sun behind cloud +26C8 ; Emoji # 5.2 [1] (⛈️) cloud with lightning and rain +26CE ; Emoji # 6.0 [1] (⛎) Ophiuchus +26CF ; Emoji # 5.2 [1] (⛏️) pick +26D1 ; Emoji # 5.2 [1] (⛑️) rescue worker’s helmet +26D3..26D4 ; Emoji # 5.2 [2] (⛓️..⛔) chains..no entry +26E9..26EA ; Emoji # 5.2 [2] (⛩️..⛪) shinto shrine..church +26F0..26F5 ; Emoji # 5.2 [6] (⛰️..⛵) mountain..sailboat +26F7..26FA ; Emoji # 5.2 [4] (⛷️..⛺) skier..tent +26FD ; Emoji # 5.2 [1] (⛽) fuel pump +2702 ; Emoji # 1.1 [1] (✂️) scissors +2705 ; Emoji # 6.0 [1] (✅) check mark button +2708..2709 ; Emoji # 1.1 [2] (✈️..✉️) airplane..envelope +270A..270B ; Emoji # 6.0 [2] (✊..✋) raised fist..raised hand +270C..270D ; Emoji # 1.1 [2] (✌️..✍️) victory hand..writing hand +270F ; Emoji # 1.1 [1] (✏️) pencil +2712 ; Emoji # 1.1 [1] (✒️) black nib +2714 ; Emoji # 1.1 [1] (✔️) check mark +2716 ; Emoji # 1.1 [1] (✖️) multiplication sign +271D ; Emoji # 1.1 [1] (✝️) latin cross +2721 ; Emoji # 1.1 [1] (✡️) star of David +2728 ; Emoji # 6.0 [1] (✨) sparkles +2733..2734 ; Emoji # 1.1 [2] (✳️..✴️) eight-spoked asterisk..eight-pointed star +2744 ; Emoji # 1.1 [1] (❄️) snowflake +2747 ; Emoji # 1.1 [1] (❇️) sparkle +274C ; Emoji # 6.0 [1] (❌) cross mark +274E ; Emoji # 6.0 [1] (❎) cross mark button +2753..2755 ; Emoji # 6.0 [3] (❓..❕) question mark..white exclamation mark +2757 ; Emoji # 5.2 [1] (❗) exclamation mark +2763..2764 ; Emoji # 1.1 [2] (❣️..❤️) heart exclamation..red heart +2795..2797 ; Emoji # 6.0 [3] (➕..➗) plus sign..division sign +27A1 ; Emoji # 1.1 [1] (➡️) right arrow +27B0 ; Emoji # 6.0 [1] (➰) curly loop +27BF ; Emoji # 6.0 [1] (➿) double curly loop +2934..2935 ; Emoji # 3.2 [2] (⤴️..⤵️) right arrow curving up..right arrow curving down +2B05..2B07 ; Emoji # 4.0 [3] (⬅️..⬇️) left arrow..down arrow +2B1B..2B1C ; Emoji # 5.1 [2] (⬛..⬜) black large square..white large square +2B50 ; Emoji # 5.1 [1] (⭐) star +2B55 ; Emoji # 5.2 [1] (⭕) hollow red circle +3030 ; Emoji # 1.1 [1] (〰️) wavy dash +303D ; Emoji # 3.2 [1] (〽️) part alternation mark +3297 ; Emoji # 1.1 [1] (㊗️) Japanese “congratulations” button +3299 ; Emoji # 1.1 [1] (㊙️) Japanese “secret” button +1F004 ; Emoji # 5.1 [1] (🀄) mahjong red dragon +1F0CF ; Emoji # 6.0 [1] (🃏) joker +1F170..1F171 ; Emoji # 6.0 [2] (🅰️..🅱️) A button (blood type)..B button (blood type) +1F17E ; Emoji # 6.0 [1] (🅾️) O button (blood type) +1F17F ; Emoji # 5.2 [1] (🅿️) P button +1F18E ; Emoji # 6.0 [1] (🆎) AB button (blood type) +1F191..1F19A ; Emoji # 6.0 [10] (🆑..🆚) CL button..VS button +1F1E6..1F1FF ; Emoji # 6.0 [26] (🇦..🇿) regional indicator symbol letter a..regional indicator symbol letter z +1F201..1F202 ; Emoji # 6.0 [2] (🈁..🈂️) Japanese “here” button..Japanese “service charge” button +1F21A ; Emoji # 5.2 [1] (🈚) Japanese “free of charge” button +1F22F ; Emoji # 5.2 [1] (🈯) Japanese “reserved” button +1F232..1F23A ; Emoji # 6.0 [9] (🈲..🈺) Japanese “prohibited” button..Japanese “open for business” button +1F250..1F251 ; Emoji # 6.0 [2] (🉐..🉑) Japanese “bargain” button..Japanese “acceptable” button +1F300..1F320 ; Emoji # 6.0 [33] (🌀..🌠) cyclone..shooting star +1F321 ; Emoji # 7.0 [1] (🌡️) thermometer +1F324..1F32C ; Emoji # 7.0 [9] (🌤️..🌬️) sun behind small cloud..wind face +1F32D..1F32F ; Emoji # 8.0 [3] (🌭..🌯) hot dog..burrito +1F330..1F335 ; Emoji # 6.0 [6] (🌰..🌵) chestnut..cactus +1F336 ; Emoji # 7.0 [1] (🌶️) hot pepper +1F337..1F37C ; Emoji # 6.0 [70] (🌷..🍼) tulip..baby bottle +1F37D ; Emoji # 7.0 [1] (🍽️) fork and knife with plate +1F37E..1F37F ; Emoji # 8.0 [2] (🍾..🍿) bottle with popping cork..popcorn +1F380..1F393 ; Emoji # 6.0 [20] (🎀..🎓) ribbon..graduation cap +1F396..1F397 ; Emoji # 7.0 [2] (🎖️..🎗️) military medal..reminder ribbon +1F399..1F39B ; Emoji # 7.0 [3] (🎙️..🎛️) studio microphone..control knobs +1F39E..1F39F ; Emoji # 7.0 [2] (🎞️..🎟️) film frames..admission tickets +1F3A0..1F3C4 ; Emoji # 6.0 [37] (🎠..🏄) carousel horse..person surfing +1F3C5 ; Emoji # 7.0 [1] (🏅) sports medal +1F3C6..1F3CA ; Emoji # 6.0 [5] (🏆..🏊) trophy..person swimming +1F3CB..1F3CE ; Emoji # 7.0 [4] (🏋️..🏎️) person lifting weights..racing car +1F3CF..1F3D3 ; Emoji # 8.0 [5] (🏏..🏓) cricket game..ping pong +1F3D4..1F3DF ; Emoji # 7.0 [12] (🏔️..🏟️) snow-capped mountain..stadium +1F3E0..1F3F0 ; Emoji # 6.0 [17] (🏠..🏰) house..castle +1F3F3..1F3F5 ; Emoji # 7.0 [3] (🏳️..🏵️) white flag..rosette +1F3F7 ; Emoji # 7.0 [1] (🏷️) label +1F3F8..1F3FF ; Emoji # 8.0 [8] (🏸..🏿) badminton..dark skin tone +1F400..1F43E ; Emoji # 6.0 [63] (🐀..🐾) rat..paw prints +1F43F ; Emoji # 7.0 [1] (🐿️) chipmunk +1F440 ; Emoji # 6.0 [1] (👀) eyes +1F441 ; Emoji # 7.0 [1] (👁️) eye +1F442..1F4F7 ; Emoji # 6.0[182] (👂..📷) ear..camera +1F4F8 ; Emoji # 7.0 [1] (📸) camera with flash +1F4F9..1F4FC ; Emoji # 6.0 [4] (📹..📼) video camera..videocassette +1F4FD ; Emoji # 7.0 [1] (📽️) film projector +1F4FF ; Emoji # 8.0 [1] (📿) prayer beads +1F500..1F53D ; Emoji # 6.0 [62] (🔀..🔽) shuffle tracks button..downwards button +1F549..1F54A ; Emoji # 7.0 [2] (🕉️..🕊️) om..dove +1F54B..1F54E ; Emoji # 8.0 [4] (🕋..🕎) kaaba..menorah +1F550..1F567 ; Emoji # 6.0 [24] (🕐..🕧) one o’clock..twelve-thirty +1F56F..1F570 ; Emoji # 7.0 [2] (🕯️..🕰️) candle..mantelpiece clock +1F573..1F579 ; Emoji # 7.0 [7] (🕳️..🕹️) hole..joystick +1F57A ; Emoji # 9.0 [1] (🕺) man dancing +1F587 ; Emoji # 7.0 [1] (🖇️) linked paperclips +1F58A..1F58D ; Emoji # 7.0 [4] (🖊️..🖍️) pen..crayon +1F590 ; Emoji # 7.0 [1] (🖐️) hand with fingers splayed +1F595..1F596 ; Emoji # 7.0 [2] (🖕..🖖) middle finger..vulcan salute +1F5A4 ; Emoji # 9.0 [1] (🖤) black heart +1F5A5 ; Emoji # 7.0 [1] (🖥️) desktop computer +1F5A8 ; Emoji # 7.0 [1] (🖨️) printer +1F5B1..1F5B2 ; Emoji # 7.0 [2] (🖱️..🖲️) computer mouse..trackball +1F5BC ; Emoji # 7.0 [1] (🖼️) framed picture +1F5C2..1F5C4 ; Emoji # 7.0 [3] (🗂️..🗄️) card index dividers..file cabinet +1F5D1..1F5D3 ; Emoji # 7.0 [3] (🗑️..🗓️) wastebasket..spiral calendar +1F5DC..1F5DE ; Emoji # 7.0 [3] (🗜️..🗞️) clamp..rolled-up newspaper +1F5E1 ; Emoji # 7.0 [1] (🗡️) dagger +1F5E3 ; Emoji # 7.0 [1] (🗣️) speaking head +1F5E8 ; Emoji # 7.0 [1] (🗨️) left speech bubble +1F5EF ; Emoji # 7.0 [1] (🗯️) right anger bubble +1F5F3 ; Emoji # 7.0 [1] (🗳️) ballot box with ballot +1F5FA ; Emoji # 7.0 [1] (🗺️) world map +1F5FB..1F5FF ; Emoji # 6.0 [5] (🗻..🗿) mount fuji..moai +1F600 ; Emoji # 6.1 [1] (😀) grinning face +1F601..1F610 ; Emoji # 6.0 [16] (😁..😐) beaming face with smiling eyes..neutral face +1F611 ; Emoji # 6.1 [1] (😑) expressionless face +1F612..1F614 ; Emoji # 6.0 [3] (😒..😔) unamused face..pensive face +1F615 ; Emoji # 6.1 [1] (😕) confused face +1F616 ; Emoji # 6.0 [1] (😖) confounded face +1F617 ; Emoji # 6.1 [1] (😗) kissing face +1F618 ; Emoji # 6.0 [1] (😘) face blowing a kiss +1F619 ; Emoji # 6.1 [1] (😙) kissing face with smiling eyes +1F61A ; Emoji # 6.0 [1] (😚) kissing face with closed eyes +1F61B ; Emoji # 6.1 [1] (😛) face with tongue +1F61C..1F61E ; Emoji # 6.0 [3] (😜..😞) winking face with tongue..disappointed face +1F61F ; Emoji # 6.1 [1] (😟) worried face +1F620..1F625 ; Emoji # 6.0 [6] (😠..😥) angry face..sad but relieved face +1F626..1F627 ; Emoji # 6.1 [2] (😦..😧) frowning face with open mouth..anguished face +1F628..1F62B ; Emoji # 6.0 [4] (😨..😫) fearful face..tired face +1F62C ; Emoji # 6.1 [1] (😬) grimacing face +1F62D ; Emoji # 6.0 [1] (😭) loudly crying face +1F62E..1F62F ; Emoji # 6.1 [2] (😮..😯) face with open mouth..hushed face +1F630..1F633 ; Emoji # 6.0 [4] (😰..😳) anxious face with sweat..flushed face +1F634 ; Emoji # 6.1 [1] (😴) sleeping face +1F635..1F640 ; Emoji # 6.0 [12] (😵..🙀) dizzy face..weary cat +1F641..1F642 ; Emoji # 7.0 [2] (🙁..🙂) slightly frowning face..slightly smiling face +1F643..1F644 ; Emoji # 8.0 [2] (🙃..🙄) upside-down face..face with rolling eyes +1F645..1F64F ; Emoji # 6.0 [11] (🙅..🙏) person gesturing NO..folded hands +1F680..1F6C5 ; Emoji # 6.0 [70] (🚀..🛅) rocket..left luggage +1F6CB..1F6CF ; Emoji # 7.0 [5] (🛋️..🛏️) couch and lamp..bed +1F6D0 ; Emoji # 8.0 [1] (🛐) place of worship +1F6D1..1F6D2 ; Emoji # 9.0 [2] (🛑..🛒) stop sign..shopping cart +1F6D5 ; Emoji # 12.0 [1] (🛕) hindu temple +1F6E0..1F6E5 ; Emoji # 7.0 [6] (🛠️..🛥️) hammer and wrench..motor boat +1F6E9 ; Emoji # 7.0 [1] (🛩️) small airplane +1F6EB..1F6EC ; Emoji # 7.0 [2] (🛫..🛬) airplane departure..airplane arrival +1F6F0 ; Emoji # 7.0 [1] (🛰️) satellite +1F6F3 ; Emoji # 7.0 [1] (🛳️) passenger ship +1F6F4..1F6F6 ; Emoji # 9.0 [3] (🛴..🛶) kick scooter..canoe +1F6F7..1F6F8 ; Emoji # 10.0 [2] (🛷..🛸) sled..flying saucer +1F6F9 ; Emoji # 11.0 [1] (🛹) skateboard +1F6FA ; Emoji # 12.0 [1] (🛺) auto rickshaw +1F7E0..1F7EB ; Emoji # 12.0 [12] (🟠..🟫) orange circle..brown square +1F90D..1F90F ; Emoji # 12.0 [3] (🤍..🤏) white heart..pinching hand +1F910..1F918 ; Emoji # 8.0 [9] (🤐..🤘) zipper-mouth face..sign of the horns +1F919..1F91E ; Emoji # 9.0 [6] (🤙..🤞) call me hand..crossed fingers +1F91F ; Emoji # 10.0 [1] (🤟) love-you gesture +1F920..1F927 ; Emoji # 9.0 [8] (🤠..🤧) cowboy hat face..sneezing face +1F928..1F92F ; Emoji # 10.0 [8] (🤨..🤯) face with raised eyebrow..exploding head +1F930 ; Emoji # 9.0 [1] (🤰) pregnant woman +1F931..1F932 ; Emoji # 10.0 [2] (🤱..🤲) breast-feeding..palms up together +1F933..1F93A ; Emoji # 9.0 [8] (🤳..🤺) selfie..person fencing +1F93C..1F93E ; Emoji # 9.0 [3] (🤼..🤾) people wrestling..person playing handball +1F93F ; Emoji # 12.0 [1] (🤿) diving mask +1F940..1F945 ; Emoji # 9.0 [6] (🥀..🥅) wilted flower..goal net +1F947..1F94B ; Emoji # 9.0 [5] (🥇..🥋) 1st place medal..martial arts uniform +1F94C ; Emoji # 10.0 [1] (🥌) curling stone +1F94D..1F94F ; Emoji # 11.0 [3] (🥍..🥏) lacrosse..flying disc +1F950..1F95E ; Emoji # 9.0 [15] (🥐..🥞) croissant..pancakes +1F95F..1F96B ; Emoji # 10.0 [13] (🥟..🥫) dumpling..canned food +1F96C..1F970 ; Emoji # 11.0 [5] (🥬..🥰) leafy green..smiling face with hearts +1F971 ; Emoji # 12.0 [1] (🥱) yawning face +1F973..1F976 ; Emoji # 11.0 [4] (🥳..🥶) partying face..cold face +1F97A ; Emoji # 11.0 [1] (🥺) pleading face +1F97B ; Emoji # 12.0 [1] (🥻) sari +1F97C..1F97F ; Emoji # 11.0 [4] (🥼..🥿) lab coat..flat shoe +1F980..1F984 ; Emoji # 8.0 [5] (🦀..🦄) crab..unicorn +1F985..1F991 ; Emoji # 9.0 [13] (🦅..🦑) eagle..squid +1F992..1F997 ; Emoji # 10.0 [6] (🦒..🦗) giraffe..cricket +1F998..1F9A2 ; Emoji # 11.0 [11] (🦘..🦢) kangaroo..swan +1F9A5..1F9AA ; Emoji # 12.0 [6] (🦥..🦪) sloth..oyster +1F9AE..1F9AF ; Emoji # 12.0 [2] (🦮..🦯) guide dog..probing cane +1F9B0..1F9B9 ; Emoji # 11.0 [10] (🦰..🦹) red hair..supervillain +1F9BA..1F9BF ; Emoji # 12.0 [6] (🦺..🦿) safety vest..mechanical leg +1F9C0 ; Emoji # 8.0 [1] (🧀) cheese wedge +1F9C1..1F9C2 ; Emoji # 11.0 [2] (🧁..🧂) cupcake..salt +1F9C3..1F9CA ; Emoji # 12.0 [8] (🧃..🧊) beverage box..ice cube +1F9CD..1F9CF ; Emoji # 12.0 [3] (🧍..🧏) person standing..deaf person +1F9D0..1F9E6 ; Emoji # 10.0 [23] (🧐..🧦) face with monocle..socks +1F9E7..1F9FF ; Emoji # 11.0 [25] (🧧..🧿) red envelope..nazar amulet +1FA70..1FA73 ; Emoji # 12.0 [4] (🩰..🩳) ballet shoes..shorts +1FA78..1FA7A ; Emoji # 12.0 [3] (🩸..🩺) drop of blood..stethoscope +1FA80..1FA82 ; Emoji # 12.0 [3] (🪀..🪂) yo-yo..parachute +1FA90..1FA95 ; Emoji # 12.0 [6] (🪐..🪕) ringed planet..banjo + +# Total elements: 1311 + +# ================================================ + +# All omitted code points have Emoji_Presentation=No +# @missing: 0000..10FFFF ; Emoji_Presentation ; No + +231A..231B ; Emoji_Presentation # 1.1 [2] (⌚..⌛) watch..hourglass done +23E9..23EC ; Emoji_Presentation # 6.0 [4] (⏩..⏬) fast-forward button..fast down button +23F0 ; Emoji_Presentation # 6.0 [1] (⏰) alarm clock +23F3 ; Emoji_Presentation # 6.0 [1] (⏳) hourglass not done +25FD..25FE ; Emoji_Presentation # 3.2 [2] (◽..◾) white medium-small square..black medium-small square +2614..2615 ; Emoji_Presentation # 4.0 [2] (☔..☕) umbrella with rain drops..hot beverage +2648..2653 ; Emoji_Presentation # 1.1 [12] (♈..♓) Aries..Pisces +267F ; Emoji_Presentation # 4.1 [1] (♿) wheelchair symbol +2693 ; Emoji_Presentation # 4.1 [1] (⚓) anchor +26A1 ; Emoji_Presentation # 4.0 [1] (⚡) high voltage +26AA..26AB ; Emoji_Presentation # 4.1 [2] (⚪..⚫) white circle..black circle +26BD..26BE ; Emoji_Presentation # 5.2 [2] (⚽..⚾) soccer ball..baseball +26C4..26C5 ; Emoji_Presentation # 5.2 [2] (⛄..⛅) snowman without snow..sun behind cloud +26CE ; Emoji_Presentation # 6.0 [1] (⛎) Ophiuchus +26D4 ; Emoji_Presentation # 5.2 [1] (⛔) no entry +26EA ; Emoji_Presentation # 5.2 [1] (⛪) church +26F2..26F3 ; Emoji_Presentation # 5.2 [2] (⛲..⛳) fountain..flag in hole +26F5 ; Emoji_Presentation # 5.2 [1] (⛵) sailboat +26FA ; Emoji_Presentation # 5.2 [1] (⛺) tent +26FD ; Emoji_Presentation # 5.2 [1] (⛽) fuel pump +2705 ; Emoji_Presentation # 6.0 [1] (✅) check mark button +270A..270B ; Emoji_Presentation # 6.0 [2] (✊..✋) raised fist..raised hand +2728 ; Emoji_Presentation # 6.0 [1] (✨) sparkles +274C ; Emoji_Presentation # 6.0 [1] (❌) cross mark +274E ; Emoji_Presentation # 6.0 [1] (❎) cross mark button +2753..2755 ; Emoji_Presentation # 6.0 [3] (❓..❕) question mark..white exclamation mark +2757 ; Emoji_Presentation # 5.2 [1] (❗) exclamation mark +2795..2797 ; Emoji_Presentation # 6.0 [3] (➕..➗) plus sign..division sign +27B0 ; Emoji_Presentation # 6.0 [1] (➰) curly loop +27BF ; Emoji_Presentation # 6.0 [1] (➿) double curly loop +2B1B..2B1C ; Emoji_Presentation # 5.1 [2] (⬛..⬜) black large square..white large square +2B50 ; Emoji_Presentation # 5.1 [1] (⭐) star +2B55 ; Emoji_Presentation # 5.2 [1] (⭕) hollow red circle +1F004 ; Emoji_Presentation # 5.1 [1] (🀄) mahjong red dragon +1F0CF ; Emoji_Presentation # 6.0 [1] (🃏) joker +1F18E ; Emoji_Presentation # 6.0 [1] (🆎) AB button (blood type) +1F191..1F19A ; Emoji_Presentation # 6.0 [10] (🆑..🆚) CL button..VS button +1F1E6..1F1FF ; Emoji_Presentation # 6.0 [26] (🇦..🇿) regional indicator symbol letter a..regional indicator symbol letter z +1F201 ; Emoji_Presentation # 6.0 [1] (🈁) Japanese “here” button +1F21A ; Emoji_Presentation # 5.2 [1] (🈚) Japanese “free of charge” button +1F22F ; Emoji_Presentation # 5.2 [1] (🈯) Japanese “reserved” button +1F232..1F236 ; Emoji_Presentation # 6.0 [5] (🈲..🈶) Japanese “prohibited” button..Japanese “not free of charge” button +1F238..1F23A ; Emoji_Presentation # 6.0 [3] (🈸..🈺) Japanese “application” button..Japanese “open for business” button +1F250..1F251 ; Emoji_Presentation # 6.0 [2] (🉐..🉑) Japanese “bargain” button..Japanese “acceptable” button +1F300..1F320 ; Emoji_Presentation # 6.0 [33] (🌀..🌠) cyclone..shooting star +1F32D..1F32F ; Emoji_Presentation # 8.0 [3] (🌭..🌯) hot dog..burrito +1F330..1F335 ; Emoji_Presentation # 6.0 [6] (🌰..🌵) chestnut..cactus +1F337..1F37C ; Emoji_Presentation # 6.0 [70] (🌷..🍼) tulip..baby bottle +1F37E..1F37F ; Emoji_Presentation # 8.0 [2] (🍾..🍿) bottle with popping cork..popcorn +1F380..1F393 ; Emoji_Presentation # 6.0 [20] (🎀..🎓) ribbon..graduation cap +1F3A0..1F3C4 ; Emoji_Presentation # 6.0 [37] (🎠..🏄) carousel horse..person surfing +1F3C5 ; Emoji_Presentation # 7.0 [1] (🏅) sports medal +1F3C6..1F3CA ; Emoji_Presentation # 6.0 [5] (🏆..🏊) trophy..person swimming +1F3CF..1F3D3 ; Emoji_Presentation # 8.0 [5] (🏏..🏓) cricket game..ping pong +1F3E0..1F3F0 ; Emoji_Presentation # 6.0 [17] (🏠..🏰) house..castle +1F3F4 ; Emoji_Presentation # 7.0 [1] (🏴) black flag +1F3F8..1F3FF ; Emoji_Presentation # 8.0 [8] (🏸..🏿) badminton..dark skin tone +1F400..1F43E ; Emoji_Presentation # 6.0 [63] (🐀..🐾) rat..paw prints +1F440 ; Emoji_Presentation # 6.0 [1] (👀) eyes +1F442..1F4F7 ; Emoji_Presentation # 6.0[182] (👂..📷) ear..camera +1F4F8 ; Emoji_Presentation # 7.0 [1] (📸) camera with flash +1F4F9..1F4FC ; Emoji_Presentation # 6.0 [4] (📹..📼) video camera..videocassette +1F4FF ; Emoji_Presentation # 8.0 [1] (📿) prayer beads +1F500..1F53D ; Emoji_Presentation # 6.0 [62] (🔀..🔽) shuffle tracks button..downwards button +1F54B..1F54E ; Emoji_Presentation # 8.0 [4] (🕋..🕎) kaaba..menorah +1F550..1F567 ; Emoji_Presentation # 6.0 [24] (🕐..🕧) one o’clock..twelve-thirty +1F57A ; Emoji_Presentation # 9.0 [1] (🕺) man dancing +1F595..1F596 ; Emoji_Presentation # 7.0 [2] (🖕..🖖) middle finger..vulcan salute +1F5A4 ; Emoji_Presentation # 9.0 [1] (🖤) black heart +1F5FB..1F5FF ; Emoji_Presentation # 6.0 [5] (🗻..🗿) mount fuji..moai +1F600 ; Emoji_Presentation # 6.1 [1] (😀) grinning face +1F601..1F610 ; Emoji_Presentation # 6.0 [16] (😁..😐) beaming face with smiling eyes..neutral face +1F611 ; Emoji_Presentation # 6.1 [1] (😑) expressionless face +1F612..1F614 ; Emoji_Presentation # 6.0 [3] (😒..😔) unamused face..pensive face +1F615 ; Emoji_Presentation # 6.1 [1] (😕) confused face +1F616 ; Emoji_Presentation # 6.0 [1] (😖) confounded face +1F617 ; Emoji_Presentation # 6.1 [1] (😗) kissing face +1F618 ; Emoji_Presentation # 6.0 [1] (😘) face blowing a kiss +1F619 ; Emoji_Presentation # 6.1 [1] (😙) kissing face with smiling eyes +1F61A ; Emoji_Presentation # 6.0 [1] (😚) kissing face with closed eyes +1F61B ; Emoji_Presentation # 6.1 [1] (😛) face with tongue +1F61C..1F61E ; Emoji_Presentation # 6.0 [3] (😜..😞) winking face with tongue..disappointed face +1F61F ; Emoji_Presentation # 6.1 [1] (😟) worried face +1F620..1F625 ; Emoji_Presentation # 6.0 [6] (😠..😥) angry face..sad but relieved face +1F626..1F627 ; Emoji_Presentation # 6.1 [2] (😦..😧) frowning face with open mouth..anguished face +1F628..1F62B ; Emoji_Presentation # 6.0 [4] (😨..😫) fearful face..tired face +1F62C ; Emoji_Presentation # 6.1 [1] (😬) grimacing face +1F62D ; Emoji_Presentation # 6.0 [1] (😭) loudly crying face +1F62E..1F62F ; Emoji_Presentation # 6.1 [2] (😮..😯) face with open mouth..hushed face +1F630..1F633 ; Emoji_Presentation # 6.0 [4] (😰..😳) anxious face with sweat..flushed face +1F634 ; Emoji_Presentation # 6.1 [1] (😴) sleeping face +1F635..1F640 ; Emoji_Presentation # 6.0 [12] (😵..🙀) dizzy face..weary cat +1F641..1F642 ; Emoji_Presentation # 7.0 [2] (🙁..🙂) slightly frowning face..slightly smiling face +1F643..1F644 ; Emoji_Presentation # 8.0 [2] (🙃..🙄) upside-down face..face with rolling eyes +1F645..1F64F ; Emoji_Presentation # 6.0 [11] (🙅..🙏) person gesturing NO..folded hands +1F680..1F6C5 ; Emoji_Presentation # 6.0 [70] (🚀..🛅) rocket..left luggage +1F6CC ; Emoji_Presentation # 7.0 [1] (🛌) person in bed +1F6D0 ; Emoji_Presentation # 8.0 [1] (🛐) place of worship +1F6D1..1F6D2 ; Emoji_Presentation # 9.0 [2] (🛑..🛒) stop sign..shopping cart +1F6D5 ; Emoji_Presentation # 12.0 [1] (🛕) hindu temple +1F6EB..1F6EC ; Emoji_Presentation # 7.0 [2] (🛫..🛬) airplane departure..airplane arrival +1F6F4..1F6F6 ; Emoji_Presentation # 9.0 [3] (🛴..🛶) kick scooter..canoe +1F6F7..1F6F8 ; Emoji_Presentation # 10.0 [2] (🛷..🛸) sled..flying saucer +1F6F9 ; Emoji_Presentation # 11.0 [1] (🛹) skateboard +1F6FA ; Emoji_Presentation # 12.0 [1] (🛺) auto rickshaw +1F7E0..1F7EB ; Emoji_Presentation # 12.0 [12] (🟠..🟫) orange circle..brown square +1F90D..1F90F ; Emoji_Presentation # 12.0 [3] (🤍..🤏) white heart..pinching hand +1F910..1F918 ; Emoji_Presentation # 8.0 [9] (🤐..🤘) zipper-mouth face..sign of the horns +1F919..1F91E ; Emoji_Presentation # 9.0 [6] (🤙..🤞) call me hand..crossed fingers +1F91F ; Emoji_Presentation # 10.0 [1] (🤟) love-you gesture +1F920..1F927 ; Emoji_Presentation # 9.0 [8] (🤠..🤧) cowboy hat face..sneezing face +1F928..1F92F ; Emoji_Presentation # 10.0 [8] (🤨..🤯) face with raised eyebrow..exploding head +1F930 ; Emoji_Presentation # 9.0 [1] (🤰) pregnant woman +1F931..1F932 ; Emoji_Presentation # 10.0 [2] (🤱..🤲) breast-feeding..palms up together +1F933..1F93A ; Emoji_Presentation # 9.0 [8] (🤳..🤺) selfie..person fencing +1F93C..1F93E ; Emoji_Presentation # 9.0 [3] (🤼..🤾) people wrestling..person playing handball +1F93F ; Emoji_Presentation # 12.0 [1] (🤿) diving mask +1F940..1F945 ; Emoji_Presentation # 9.0 [6] (🥀..🥅) wilted flower..goal net +1F947..1F94B ; Emoji_Presentation # 9.0 [5] (🥇..🥋) 1st place medal..martial arts uniform +1F94C ; Emoji_Presentation # 10.0 [1] (🥌) curling stone +1F94D..1F94F ; Emoji_Presentation # 11.0 [3] (🥍..🥏) lacrosse..flying disc +1F950..1F95E ; Emoji_Presentation # 9.0 [15] (🥐..🥞) croissant..pancakes +1F95F..1F96B ; Emoji_Presentation # 10.0 [13] (🥟..🥫) dumpling..canned food +1F96C..1F970 ; Emoji_Presentation # 11.0 [5] (🥬..🥰) leafy green..smiling face with hearts +1F971 ; Emoji_Presentation # 12.0 [1] (🥱) yawning face +1F973..1F976 ; Emoji_Presentation # 11.0 [4] (🥳..🥶) partying face..cold face +1F97A ; Emoji_Presentation # 11.0 [1] (🥺) pleading face +1F97B ; Emoji_Presentation # 12.0 [1] (🥻) sari +1F97C..1F97F ; Emoji_Presentation # 11.0 [4] (🥼..🥿) lab coat..flat shoe +1F980..1F984 ; Emoji_Presentation # 8.0 [5] (🦀..🦄) crab..unicorn +1F985..1F991 ; Emoji_Presentation # 9.0 [13] (🦅..🦑) eagle..squid +1F992..1F997 ; Emoji_Presentation # 10.0 [6] (🦒..🦗) giraffe..cricket +1F998..1F9A2 ; Emoji_Presentation # 11.0 [11] (🦘..🦢) kangaroo..swan +1F9A5..1F9AA ; Emoji_Presentation # 12.0 [6] (🦥..🦪) sloth..oyster +1F9AE..1F9AF ; Emoji_Presentation # 12.0 [2] (🦮..🦯) guide dog..probing cane +1F9B0..1F9B9 ; Emoji_Presentation # 11.0 [10] (🦰..🦹) red hair..supervillain +1F9BA..1F9BF ; Emoji_Presentation # 12.0 [6] (🦺..🦿) safety vest..mechanical leg +1F9C0 ; Emoji_Presentation # 8.0 [1] (🧀) cheese wedge +1F9C1..1F9C2 ; Emoji_Presentation # 11.0 [2] (🧁..🧂) cupcake..salt +1F9C3..1F9CA ; Emoji_Presentation # 12.0 [8] (🧃..🧊) beverage box..ice cube +1F9CD..1F9CF ; Emoji_Presentation # 12.0 [3] (🧍..🧏) person standing..deaf person +1F9D0..1F9E6 ; Emoji_Presentation # 10.0 [23] (🧐..🧦) face with monocle..socks +1F9E7..1F9FF ; Emoji_Presentation # 11.0 [25] (🧧..🧿) red envelope..nazar amulet +1FA70..1FA73 ; Emoji_Presentation # 12.0 [4] (🩰..🩳) ballet shoes..shorts +1FA78..1FA7A ; Emoji_Presentation # 12.0 [3] (🩸..🩺) drop of blood..stethoscope +1FA80..1FA82 ; Emoji_Presentation # 12.0 [3] (🪀..🪂) yo-yo..parachute +1FA90..1FA95 ; Emoji_Presentation # 12.0 [6] (🪐..🪕) ringed planet..banjo + +# Total elements: 1093 + +# ================================================ + +# All omitted code points have Emoji_Modifier=No +# @missing: 0000..10FFFF ; Emoji_Modifier ; No + +1F3FB..1F3FF ; Emoji_Modifier # 8.0 [5] (🏻..🏿) light skin tone..dark skin tone + +# Total elements: 5 + +# ================================================ + +# All omitted code points have Emoji_Modifier_Base=No +# @missing: 0000..10FFFF ; Emoji_Modifier_Base ; No + +261D ; Emoji_Modifier_Base # 1.1 [1] (☝️) index pointing up +26F9 ; Emoji_Modifier_Base # 5.2 [1] (⛹️) person bouncing ball +270A..270B ; Emoji_Modifier_Base # 6.0 [2] (✊..✋) raised fist..raised hand +270C..270D ; Emoji_Modifier_Base # 1.1 [2] (✌️..✍️) victory hand..writing hand +1F385 ; Emoji_Modifier_Base # 6.0 [1] (🎅) Santa Claus +1F3C2..1F3C4 ; Emoji_Modifier_Base # 6.0 [3] (🏂..🏄) snowboarder..person surfing +1F3C7 ; Emoji_Modifier_Base # 6.0 [1] (🏇) horse racing +1F3CA ; Emoji_Modifier_Base # 6.0 [1] (🏊) person swimming +1F3CB..1F3CC ; Emoji_Modifier_Base # 7.0 [2] (🏋️..🏌️) person lifting weights..person golfing +1F442..1F443 ; Emoji_Modifier_Base # 6.0 [2] (👂..👃) ear..nose +1F446..1F450 ; Emoji_Modifier_Base # 6.0 [11] (👆..👐) backhand index pointing up..open hands +1F466..1F478 ; Emoji_Modifier_Base # 6.0 [19] (👦..👸) boy..princess +1F47C ; Emoji_Modifier_Base # 6.0 [1] (👼) baby angel +1F481..1F483 ; Emoji_Modifier_Base # 6.0 [3] (💁..💃) person tipping hand..woman dancing +1F485..1F487 ; Emoji_Modifier_Base # 6.0 [3] (💅..💇) nail polish..person getting haircut +1F48F ; Emoji_Modifier_Base # 6.0 [1] (💏) kiss +1F491 ; Emoji_Modifier_Base # 6.0 [1] (💑) couple with heart +1F4AA ; Emoji_Modifier_Base # 6.0 [1] (💪) flexed biceps +1F574..1F575 ; Emoji_Modifier_Base # 7.0 [2] (🕴️..🕵️) man in suit levitating..detective +1F57A ; Emoji_Modifier_Base # 9.0 [1] (🕺) man dancing +1F590 ; Emoji_Modifier_Base # 7.0 [1] (🖐️) hand with fingers splayed +1F595..1F596 ; Emoji_Modifier_Base # 7.0 [2] (🖕..🖖) middle finger..vulcan salute +1F645..1F647 ; Emoji_Modifier_Base # 6.0 [3] (🙅..🙇) person gesturing NO..person bowing +1F64B..1F64F ; Emoji_Modifier_Base # 6.0 [5] (🙋..🙏) person raising hand..folded hands +1F6A3 ; Emoji_Modifier_Base # 6.0 [1] (🚣) person rowing boat +1F6B4..1F6B6 ; Emoji_Modifier_Base # 6.0 [3] (🚴..🚶) person biking..person walking +1F6C0 ; Emoji_Modifier_Base # 6.0 [1] (🛀) person taking bath +1F6CC ; Emoji_Modifier_Base # 7.0 [1] (🛌) person in bed +1F90F ; Emoji_Modifier_Base # 12.0 [1] (🤏) pinching hand +1F918 ; Emoji_Modifier_Base # 8.0 [1] (🤘) sign of the horns +1F919..1F91E ; Emoji_Modifier_Base # 9.0 [6] (🤙..🤞) call me hand..crossed fingers +1F91F ; Emoji_Modifier_Base # 10.0 [1] (🤟) love-you gesture +1F926 ; Emoji_Modifier_Base # 9.0 [1] (🤦) person facepalming +1F930 ; Emoji_Modifier_Base # 9.0 [1] (🤰) pregnant woman +1F931..1F932 ; Emoji_Modifier_Base # 10.0 [2] (🤱..🤲) breast-feeding..palms up together +1F933..1F939 ; Emoji_Modifier_Base # 9.0 [7] (🤳..🤹) selfie..person juggling +1F93C..1F93E ; Emoji_Modifier_Base # 9.0 [3] (🤼..🤾) people wrestling..person playing handball +1F9B5..1F9B6 ; Emoji_Modifier_Base # 11.0 [2] (🦵..🦶) leg..foot +1F9B8..1F9B9 ; Emoji_Modifier_Base # 11.0 [2] (🦸..🦹) superhero..supervillain +1F9BB ; Emoji_Modifier_Base # 12.0 [1] (🦻) ear with hearing aid +1F9CD..1F9CF ; Emoji_Modifier_Base # 12.0 [3] (🧍..🧏) person standing..deaf person +1F9D1..1F9DD ; Emoji_Modifier_Base # 10.0 [13] (🧑..🧝) person..elf + +# Total elements: 120 + +# ================================================ + +# All omitted code points have Emoji_Component=No +# @missing: 0000..10FFFF ; Emoji_Component ; No + +0023 ; Emoji_Component # 1.1 [1] (#️) number sign +002A ; Emoji_Component # 1.1 [1] (*️) asterisk +0030..0039 ; Emoji_Component # 1.1 [10] (0️..9️) digit zero..digit nine +200D ; Emoji_Component # 1.1 [1] (‍) zero width joiner +20E3 ; Emoji_Component # 3.0 [1] (⃣) combining enclosing keycap +FE0F ; Emoji_Component # 3.2 [1] () VARIATION SELECTOR-16 +1F1E6..1F1FF ; Emoji_Component # 6.0 [26] (🇦..🇿) regional indicator symbol letter a..regional indicator symbol letter z +1F3FB..1F3FF ; Emoji_Component # 8.0 [5] (🏻..🏿) light skin tone..dark skin tone +1F9B0..1F9B3 ; Emoji_Component # 11.0 [4] (🦰..🦳) red hair..white hair +E0020..E007F ; Emoji_Component # 3.1 [96] (󠀠..󠁿) tag space..cancel tag + +# Total elements: 146 + +# ================================================ + +# All omitted code points have Extended_Pictographic=No +# @missing: 0000..10FFFF ; Extended_Pictographic ; No + +00A9 ; Extended_Pictographic# 1.1 [1] (©️) copyright +00AE ; Extended_Pictographic# 1.1 [1] (®️) registered +203C ; Extended_Pictographic# 1.1 [1] (‼️) double exclamation mark +2049 ; Extended_Pictographic# 3.0 [1] (⁉️) exclamation question mark +2122 ; Extended_Pictographic# 1.1 [1] (™️) trade mark +2139 ; Extended_Pictographic# 3.0 [1] (ℹ️) information +2194..2199 ; Extended_Pictographic# 1.1 [6] (↔️..↙️) left-right arrow..down-left arrow +21A9..21AA ; Extended_Pictographic# 1.1 [2] (↩️..↪️) right arrow curving left..left arrow curving right +231A..231B ; Extended_Pictographic# 1.1 [2] (⌚..⌛) watch..hourglass done +2328 ; Extended_Pictographic# 1.1 [1] (⌨️) keyboard +2388 ; Extended_Pictographic# 3.0 [1] (⎈) HELM SYMBOL +23CF ; Extended_Pictographic# 4.0 [1] (⏏️) eject button +23E9..23F3 ; Extended_Pictographic# 6.0 [11] (⏩..⏳) fast-forward button..hourglass not done +23F8..23FA ; Extended_Pictographic# 7.0 [3] (⏸️..⏺️) pause button..record button +24C2 ; Extended_Pictographic# 1.1 [1] (Ⓜ️) circled M +25AA..25AB ; Extended_Pictographic# 1.1 [2] (▪️..▫️) black small square..white small square +25B6 ; Extended_Pictographic# 1.1 [1] (▶️) play button +25C0 ; Extended_Pictographic# 1.1 [1] (◀️) reverse button +25FB..25FE ; Extended_Pictographic# 3.2 [4] (◻️..◾) white medium square..black medium-small square +2600..2605 ; Extended_Pictographic# 1.1 [6] (☀️..★) sun..BLACK STAR +2607..2612 ; Extended_Pictographic# 1.1 [12] (☇..☒) LIGHTNING..BALLOT BOX WITH X +2614..2615 ; Extended_Pictographic# 4.0 [2] (☔..☕) umbrella with rain drops..hot beverage +2616..2617 ; Extended_Pictographic# 3.2 [2] (☖..☗) WHITE SHOGI PIECE..BLACK SHOGI PIECE +2618 ; Extended_Pictographic# 4.1 [1] (☘️) shamrock +2619 ; Extended_Pictographic# 3.0 [1] (☙) REVERSED ROTATED FLORAL HEART BULLET +261A..266F ; Extended_Pictographic# 1.1 [86] (☚..♯) BLACK LEFT POINTING INDEX..MUSIC SHARP SIGN +2670..2671 ; Extended_Pictographic# 3.0 [2] (♰..♱) WEST SYRIAC CROSS..EAST SYRIAC CROSS +2672..267D ; Extended_Pictographic# 3.2 [12] (♲..♽) UNIVERSAL RECYCLING SYMBOL..PARTIALLY-RECYCLED PAPER SYMBOL +267E..267F ; Extended_Pictographic# 4.1 [2] (♾️..♿) infinity..wheelchair symbol +2680..2685 ; Extended_Pictographic# 3.2 [6] (⚀..⚅) DIE FACE-1..DIE FACE-6 +2690..2691 ; Extended_Pictographic# 4.0 [2] (⚐..⚑) WHITE FLAG..BLACK FLAG +2692..269C ; Extended_Pictographic# 4.1 [11] (⚒️..⚜️) hammer and pick..fleur-de-lis +269D ; Extended_Pictographic# 5.1 [1] (⚝) OUTLINED WHITE STAR +269E..269F ; Extended_Pictographic# 5.2 [2] (⚞..⚟) THREE LINES CONVERGING RIGHT..THREE LINES CONVERGING LEFT +26A0..26A1 ; Extended_Pictographic# 4.0 [2] (⚠️..⚡) warning..high voltage +26A2..26B1 ; Extended_Pictographic# 4.1 [16] (⚢..⚱️) DOUBLED FEMALE SIGN..funeral urn +26B2 ; Extended_Pictographic# 5.0 [1] (⚲) NEUTER +26B3..26BC ; Extended_Pictographic# 5.1 [10] (⚳..⚼) CERES..SESQUIQUADRATE +26BD..26BF ; Extended_Pictographic# 5.2 [3] (⚽..⚿) soccer ball..SQUARED KEY +26C0..26C3 ; Extended_Pictographic# 5.1 [4] (⛀..⛃) WHITE DRAUGHTS MAN..BLACK DRAUGHTS KING +26C4..26CD ; Extended_Pictographic# 5.2 [10] (⛄..⛍) snowman without snow..DISABLED CAR +26CE ; Extended_Pictographic# 6.0 [1] (⛎) Ophiuchus +26CF..26E1 ; Extended_Pictographic# 5.2 [19] (⛏️..⛡) pick..RESTRICTED LEFT ENTRY-2 +26E2 ; Extended_Pictographic# 6.0 [1] (⛢) ASTRONOMICAL SYMBOL FOR URANUS +26E3 ; Extended_Pictographic# 5.2 [1] (⛣) HEAVY CIRCLE WITH STROKE AND TWO DOTS ABOVE +26E4..26E7 ; Extended_Pictographic# 6.0 [4] (⛤..⛧) PENTAGRAM..INVERTED PENTAGRAM +26E8..26FF ; Extended_Pictographic# 5.2 [24] (⛨..⛿) BLACK CROSS ON SHIELD..WHITE FLAG WITH HORIZONTAL MIDDLE BLACK STRIPE +2700 ; Extended_Pictographic# 7.0 [1] (✀) BLACK SAFETY SCISSORS +2701..2704 ; Extended_Pictographic# 1.1 [4] (✁..✄) UPPER BLADE SCISSORS..WHITE SCISSORS +2705 ; Extended_Pictographic# 6.0 [1] (✅) check mark button +2708..2709 ; Extended_Pictographic# 1.1 [2] (✈️..✉️) airplane..envelope +270A..270B ; Extended_Pictographic# 6.0 [2] (✊..✋) raised fist..raised hand +270C..2712 ; Extended_Pictographic# 1.1 [7] (✌️..✒️) victory hand..black nib +2714 ; Extended_Pictographic# 1.1 [1] (✔️) check mark +2716 ; Extended_Pictographic# 1.1 [1] (✖️) multiplication sign +271D ; Extended_Pictographic# 1.1 [1] (✝️) latin cross +2721 ; Extended_Pictographic# 1.1 [1] (✡️) star of David +2728 ; Extended_Pictographic# 6.0 [1] (✨) sparkles +2733..2734 ; Extended_Pictographic# 1.1 [2] (✳️..✴️) eight-spoked asterisk..eight-pointed star +2744 ; Extended_Pictographic# 1.1 [1] (❄️) snowflake +2747 ; Extended_Pictographic# 1.1 [1] (❇️) sparkle +274C ; Extended_Pictographic# 6.0 [1] (❌) cross mark +274E ; Extended_Pictographic# 6.0 [1] (❎) cross mark button +2753..2755 ; Extended_Pictographic# 6.0 [3] (❓..❕) question mark..white exclamation mark +2757 ; Extended_Pictographic# 5.2 [1] (❗) exclamation mark +2763..2767 ; Extended_Pictographic# 1.1 [5] (❣️..❧) heart exclamation..ROTATED FLORAL HEART BULLET +2795..2797 ; Extended_Pictographic# 6.0 [3] (➕..➗) plus sign..division sign +27A1 ; Extended_Pictographic# 1.1 [1] (➡️) right arrow +27B0 ; Extended_Pictographic# 6.0 [1] (➰) curly loop +27BF ; Extended_Pictographic# 6.0 [1] (➿) double curly loop +2934..2935 ; Extended_Pictographic# 3.2 [2] (⤴️..⤵️) right arrow curving up..right arrow curving down +2B05..2B07 ; Extended_Pictographic# 4.0 [3] (⬅️..⬇️) left arrow..down arrow +2B1B..2B1C ; Extended_Pictographic# 5.1 [2] (⬛..⬜) black large square..white large square +2B50 ; Extended_Pictographic# 5.1 [1] (⭐) star +2B55 ; Extended_Pictographic# 5.2 [1] (⭕) hollow red circle +3030 ; Extended_Pictographic# 1.1 [1] (〰️) wavy dash +303D ; Extended_Pictographic# 3.2 [1] (〽️) part alternation mark +3297 ; Extended_Pictographic# 1.1 [1] (㊗️) Japanese “congratulations” button +3299 ; Extended_Pictographic# 1.1 [1] (㊙️) Japanese “secret” button +1F000..1F02B ; Extended_Pictographic# 5.1 [44] (🀀..🀫) MAHJONG TILE EAST WIND..MAHJONG TILE BACK +1F02C..1F02F ; Extended_Pictographic# NA [4] (🀬..🀯) .. +1F030..1F093 ; Extended_Pictographic# 5.1[100] (🀰..🂓) DOMINO TILE HORIZONTAL BACK..DOMINO TILE VERTICAL-06-06 +1F094..1F09F ; Extended_Pictographic# NA [12] (🂔..🂟) .. +1F0A0..1F0AE ; Extended_Pictographic# 6.0 [15] (🂠..🂮) PLAYING CARD BACK..PLAYING CARD KING OF SPADES +1F0AF..1F0B0 ; Extended_Pictographic# NA [2] (🂯..🂰) .. +1F0B1..1F0BE ; Extended_Pictographic# 6.0 [14] (🂱..🂾) PLAYING CARD ACE OF HEARTS..PLAYING CARD KING OF HEARTS +1F0BF ; Extended_Pictographic# 7.0 [1] (🂿) PLAYING CARD RED JOKER +1F0C0 ; Extended_Pictographic# NA [1] (🃀) +1F0C1..1F0CF ; Extended_Pictographic# 6.0 [15] (🃁..🃏) PLAYING CARD ACE OF DIAMONDS..joker +1F0D0 ; Extended_Pictographic# NA [1] (🃐) +1F0D1..1F0DF ; Extended_Pictographic# 6.0 [15] (🃑..🃟) PLAYING CARD ACE OF CLUBS..PLAYING CARD WHITE JOKER +1F0E0..1F0F5 ; Extended_Pictographic# 7.0 [22] (🃠..🃵) PLAYING CARD FOOL..PLAYING CARD TRUMP-21 +1F0F6..1F0FF ; Extended_Pictographic# NA [10] (🃶..🃿) .. +1F10D..1F10F ; Extended_Pictographic# NA [3] (🄍..🄏) .. +1F12F ; Extended_Pictographic# 11.0 [1] (🄯) COPYLEFT SYMBOL +1F16C ; Extended_Pictographic# 12.0 [1] (🅬) RAISED MR SIGN +1F16D..1F16F ; Extended_Pictographic# NA [3] (🅭..🅯) .. +1F170..1F171 ; Extended_Pictographic# 6.0 [2] (🅰️..🅱️) A button (blood type)..B button (blood type) +1F17E ; Extended_Pictographic# 6.0 [1] (🅾️) O button (blood type) +1F17F ; Extended_Pictographic# 5.2 [1] (🅿️) P button +1F18E ; Extended_Pictographic# 6.0 [1] (🆎) AB button (blood type) +1F191..1F19A ; Extended_Pictographic# 6.0 [10] (🆑..🆚) CL button..VS button +1F1AD..1F1E5 ; Extended_Pictographic# NA [57] (🆭..🇥) .. +1F201..1F202 ; Extended_Pictographic# 6.0 [2] (🈁..🈂️) Japanese “here” button..Japanese “service charge” button +1F203..1F20F ; Extended_Pictographic# NA [13] (🈃..🈏) .. +1F21A ; Extended_Pictographic# 5.2 [1] (🈚) Japanese “free of charge” button +1F22F ; Extended_Pictographic# 5.2 [1] (🈯) Japanese “reserved” button +1F232..1F23A ; Extended_Pictographic# 6.0 [9] (🈲..🈺) Japanese “prohibited” button..Japanese “open for business” button +1F23C..1F23F ; Extended_Pictographic# NA [4] (🈼..🈿) .. +1F249..1F24F ; Extended_Pictographic# NA [7] (🉉..🉏) .. +1F250..1F251 ; Extended_Pictographic# 6.0 [2] (🉐..🉑) Japanese “bargain” button..Japanese “acceptable” button +1F252..1F25F ; Extended_Pictographic# NA [14] (🉒..🉟) .. +1F260..1F265 ; Extended_Pictographic# 10.0 [6] (🉠..🉥) ROUNDED SYMBOL FOR FU..ROUNDED SYMBOL FOR CAI +1F266..1F2FF ; Extended_Pictographic# NA[154] (🉦..🋿) .. +1F300..1F320 ; Extended_Pictographic# 6.0 [33] (🌀..🌠) cyclone..shooting star +1F321..1F32C ; Extended_Pictographic# 7.0 [12] (🌡️..🌬️) thermometer..wind face +1F32D..1F32F ; Extended_Pictographic# 8.0 [3] (🌭..🌯) hot dog..burrito +1F330..1F335 ; Extended_Pictographic# 6.0 [6] (🌰..🌵) chestnut..cactus +1F336 ; Extended_Pictographic# 7.0 [1] (🌶️) hot pepper +1F337..1F37C ; Extended_Pictographic# 6.0 [70] (🌷..🍼) tulip..baby bottle +1F37D ; Extended_Pictographic# 7.0 [1] (🍽️) fork and knife with plate +1F37E..1F37F ; Extended_Pictographic# 8.0 [2] (🍾..🍿) bottle with popping cork..popcorn +1F380..1F393 ; Extended_Pictographic# 6.0 [20] (🎀..🎓) ribbon..graduation cap +1F394..1F39F ; Extended_Pictographic# 7.0 [12] (🎔..🎟️) HEART WITH TIP ON THE LEFT..admission tickets +1F3A0..1F3C4 ; Extended_Pictographic# 6.0 [37] (🎠..🏄) carousel horse..person surfing +1F3C5 ; Extended_Pictographic# 7.0 [1] (🏅) sports medal +1F3C6..1F3CA ; Extended_Pictographic# 6.0 [5] (🏆..🏊) trophy..person swimming +1F3CB..1F3CE ; Extended_Pictographic# 7.0 [4] (🏋️..🏎️) person lifting weights..racing car +1F3CF..1F3D3 ; Extended_Pictographic# 8.0 [5] (🏏..🏓) cricket game..ping pong +1F3D4..1F3DF ; Extended_Pictographic# 7.0 [12] (🏔️..🏟️) snow-capped mountain..stadium +1F3E0..1F3F0 ; Extended_Pictographic# 6.0 [17] (🏠..🏰) house..castle +1F3F1..1F3F7 ; Extended_Pictographic# 7.0 [7] (🏱..🏷️) WHITE PENNANT..label +1F3F8..1F3FA ; Extended_Pictographic# 8.0 [3] (🏸..🏺) badminton..amphora +1F400..1F43E ; Extended_Pictographic# 6.0 [63] (🐀..🐾) rat..paw prints +1F43F ; Extended_Pictographic# 7.0 [1] (🐿️) chipmunk +1F440 ; Extended_Pictographic# 6.0 [1] (👀) eyes +1F441 ; Extended_Pictographic# 7.0 [1] (👁️) eye +1F442..1F4F7 ; Extended_Pictographic# 6.0[182] (👂..📷) ear..camera +1F4F8 ; Extended_Pictographic# 7.0 [1] (📸) camera with flash +1F4F9..1F4FC ; Extended_Pictographic# 6.0 [4] (📹..📼) video camera..videocassette +1F4FD..1F4FE ; Extended_Pictographic# 7.0 [2] (📽️..📾) film projector..PORTABLE STEREO +1F4FF ; Extended_Pictographic# 8.0 [1] (📿) prayer beads +1F500..1F53D ; Extended_Pictographic# 6.0 [62] (🔀..🔽) shuffle tracks button..downwards button +1F546..1F54A ; Extended_Pictographic# 7.0 [5] (🕆..🕊️) WHITE LATIN CROSS..dove +1F54B..1F54F ; Extended_Pictographic# 8.0 [5] (🕋..🕏) kaaba..BOWL OF HYGIEIA +1F550..1F567 ; Extended_Pictographic# 6.0 [24] (🕐..🕧) one o’clock..twelve-thirty +1F568..1F579 ; Extended_Pictographic# 7.0 [18] (🕨..🕹️) RIGHT SPEAKER..joystick +1F57A ; Extended_Pictographic# 9.0 [1] (🕺) man dancing +1F57B..1F5A3 ; Extended_Pictographic# 7.0 [41] (🕻..🖣) LEFT HAND TELEPHONE RECEIVER..BLACK DOWN POINTING BACKHAND INDEX +1F5A4 ; Extended_Pictographic# 9.0 [1] (🖤) black heart +1F5A5..1F5FA ; Extended_Pictographic# 7.0 [86] (🖥️..🗺️) desktop computer..world map +1F5FB..1F5FF ; Extended_Pictographic# 6.0 [5] (🗻..🗿) mount fuji..moai +1F600 ; Extended_Pictographic# 6.1 [1] (😀) grinning face +1F601..1F610 ; Extended_Pictographic# 6.0 [16] (😁..😐) beaming face with smiling eyes..neutral face +1F611 ; Extended_Pictographic# 6.1 [1] (😑) expressionless face +1F612..1F614 ; Extended_Pictographic# 6.0 [3] (😒..😔) unamused face..pensive face +1F615 ; Extended_Pictographic# 6.1 [1] (😕) confused face +1F616 ; Extended_Pictographic# 6.0 [1] (😖) confounded face +1F617 ; Extended_Pictographic# 6.1 [1] (😗) kissing face +1F618 ; Extended_Pictographic# 6.0 [1] (😘) face blowing a kiss +1F619 ; Extended_Pictographic# 6.1 [1] (😙) kissing face with smiling eyes +1F61A ; Extended_Pictographic# 6.0 [1] (😚) kissing face with closed eyes +1F61B ; Extended_Pictographic# 6.1 [1] (😛) face with tongue +1F61C..1F61E ; Extended_Pictographic# 6.0 [3] (😜..😞) winking face with tongue..disappointed face +1F61F ; Extended_Pictographic# 6.1 [1] (😟) worried face +1F620..1F625 ; Extended_Pictographic# 6.0 [6] (😠..😥) angry face..sad but relieved face +1F626..1F627 ; Extended_Pictographic# 6.1 [2] (😦..😧) frowning face with open mouth..anguished face +1F628..1F62B ; Extended_Pictographic# 6.0 [4] (😨..😫) fearful face..tired face +1F62C ; Extended_Pictographic# 6.1 [1] (😬) grimacing face +1F62D ; Extended_Pictographic# 6.0 [1] (😭) loudly crying face +1F62E..1F62F ; Extended_Pictographic# 6.1 [2] (😮..😯) face with open mouth..hushed face +1F630..1F633 ; Extended_Pictographic# 6.0 [4] (😰..😳) anxious face with sweat..flushed face +1F634 ; Extended_Pictographic# 6.1 [1] (😴) sleeping face +1F635..1F640 ; Extended_Pictographic# 6.0 [12] (😵..🙀) dizzy face..weary cat +1F641..1F642 ; Extended_Pictographic# 7.0 [2] (🙁..🙂) slightly frowning face..slightly smiling face +1F643..1F644 ; Extended_Pictographic# 8.0 [2] (🙃..🙄) upside-down face..face with rolling eyes +1F645..1F64F ; Extended_Pictographic# 6.0 [11] (🙅..🙏) person gesturing NO..folded hands +1F680..1F6C5 ; Extended_Pictographic# 6.0 [70] (🚀..🛅) rocket..left luggage +1F6C6..1F6CF ; Extended_Pictographic# 7.0 [10] (🛆..🛏️) TRIANGLE WITH ROUNDED CORNERS..bed +1F6D0 ; Extended_Pictographic# 8.0 [1] (🛐) place of worship +1F6D1..1F6D2 ; Extended_Pictographic# 9.0 [2] (🛑..🛒) stop sign..shopping cart +1F6D3..1F6D4 ; Extended_Pictographic# 10.0 [2] (🛓..🛔) STUPA..PAGODA +1F6D5 ; Extended_Pictographic# 12.0 [1] (🛕) hindu temple +1F6D6..1F6DF ; Extended_Pictographic# NA [10] (🛖..🛟) .. +1F6E0..1F6EC ; Extended_Pictographic# 7.0 [13] (🛠️..🛬) hammer and wrench..airplane arrival +1F6ED..1F6EF ; Extended_Pictographic# NA [3] (🛭..🛯) .. +1F6F0..1F6F3 ; Extended_Pictographic# 7.0 [4] (🛰️..🛳️) satellite..passenger ship +1F6F4..1F6F6 ; Extended_Pictographic# 9.0 [3] (🛴..🛶) kick scooter..canoe +1F6F7..1F6F8 ; Extended_Pictographic# 10.0 [2] (🛷..🛸) sled..flying saucer +1F6F9 ; Extended_Pictographic# 11.0 [1] (🛹) skateboard +1F6FA ; Extended_Pictographic# 12.0 [1] (🛺) auto rickshaw +1F6FB..1F6FF ; Extended_Pictographic# NA [5] (🛻..🛿) .. +1F774..1F77F ; Extended_Pictographic# NA [12] (🝴..🝿) .. +1F7D5..1F7D8 ; Extended_Pictographic# 11.0 [4] (🟕..🟘) CIRCLED TRIANGLE..NEGATIVE CIRCLED SQUARE +1F7D9..1F7DF ; Extended_Pictographic# NA [7] (🟙..🟟) .. +1F7E0..1F7EB ; Extended_Pictographic# 12.0 [12] (🟠..🟫) orange circle..brown square +1F7EC..1F7FF ; Extended_Pictographic# NA [20] (🟬..🟿) .. +1F80C..1F80F ; Extended_Pictographic# NA [4] (🠌..🠏) .. +1F848..1F84F ; Extended_Pictographic# NA [8] (🡈..🡏) .. +1F85A..1F85F ; Extended_Pictographic# NA [6] (🡚..🡟) .. +1F888..1F88F ; Extended_Pictographic# NA [8] (🢈..🢏) .. +1F8AE..1F8FF ; Extended_Pictographic# NA [82] (🢮..🣿) .. +1F90C ; Extended_Pictographic# NA [1] (🤌) +1F90D..1F90F ; Extended_Pictographic# 12.0 [3] (🤍..🤏) white heart..pinching hand +1F910..1F918 ; Extended_Pictographic# 8.0 [9] (🤐..🤘) zipper-mouth face..sign of the horns +1F919..1F91E ; Extended_Pictographic# 9.0 [6] (🤙..🤞) call me hand..crossed fingers +1F91F ; Extended_Pictographic# 10.0 [1] (🤟) love-you gesture +1F920..1F927 ; Extended_Pictographic# 9.0 [8] (🤠..🤧) cowboy hat face..sneezing face +1F928..1F92F ; Extended_Pictographic# 10.0 [8] (🤨..🤯) face with raised eyebrow..exploding head +1F930 ; Extended_Pictographic# 9.0 [1] (🤰) pregnant woman +1F931..1F932 ; Extended_Pictographic# 10.0 [2] (🤱..🤲) breast-feeding..palms up together +1F933..1F93A ; Extended_Pictographic# 9.0 [8] (🤳..🤺) selfie..person fencing +1F93C..1F93E ; Extended_Pictographic# 9.0 [3] (🤼..🤾) people wrestling..person playing handball +1F93F ; Extended_Pictographic# 12.0 [1] (🤿) diving mask +1F940..1F945 ; Extended_Pictographic# 9.0 [6] (🥀..🥅) wilted flower..goal net +1F947..1F94B ; Extended_Pictographic# 9.0 [5] (🥇..🥋) 1st place medal..martial arts uniform +1F94C ; Extended_Pictographic# 10.0 [1] (🥌) curling stone +1F94D..1F94F ; Extended_Pictographic# 11.0 [3] (🥍..🥏) lacrosse..flying disc +1F950..1F95E ; Extended_Pictographic# 9.0 [15] (🥐..🥞) croissant..pancakes +1F95F..1F96B ; Extended_Pictographic# 10.0 [13] (🥟..🥫) dumpling..canned food +1F96C..1F970 ; Extended_Pictographic# 11.0 [5] (🥬..🥰) leafy green..smiling face with hearts +1F971 ; Extended_Pictographic# 12.0 [1] (🥱) yawning face +1F972 ; Extended_Pictographic# NA [1] (🥲) +1F973..1F976 ; Extended_Pictographic# 11.0 [4] (🥳..🥶) partying face..cold face +1F977..1F979 ; Extended_Pictographic# NA [3] (🥷..🥹) .. +1F97A ; Extended_Pictographic# 11.0 [1] (🥺) pleading face +1F97B ; Extended_Pictographic# 12.0 [1] (🥻) sari +1F97C..1F97F ; Extended_Pictographic# 11.0 [4] (🥼..🥿) lab coat..flat shoe +1F980..1F984 ; Extended_Pictographic# 8.0 [5] (🦀..🦄) crab..unicorn +1F985..1F991 ; Extended_Pictographic# 9.0 [13] (🦅..🦑) eagle..squid +1F992..1F997 ; Extended_Pictographic# 10.0 [6] (🦒..🦗) giraffe..cricket +1F998..1F9A2 ; Extended_Pictographic# 11.0 [11] (🦘..🦢) kangaroo..swan +1F9A3..1F9A4 ; Extended_Pictographic# NA [2] (🦣..🦤) .. +1F9A5..1F9AA ; Extended_Pictographic# 12.0 [6] (🦥..🦪) sloth..oyster +1F9AB..1F9AD ; Extended_Pictographic# NA [3] (🦫..🦭) .. +1F9AE..1F9AF ; Extended_Pictographic# 12.0 [2] (🦮..🦯) guide dog..probing cane +1F9B0..1F9B9 ; Extended_Pictographic# 11.0 [10] (🦰..🦹) red hair..supervillain +1F9BA..1F9BF ; Extended_Pictographic# 12.0 [6] (🦺..🦿) safety vest..mechanical leg +1F9C0 ; Extended_Pictographic# 8.0 [1] (🧀) cheese wedge +1F9C1..1F9C2 ; Extended_Pictographic# 11.0 [2] (🧁..🧂) cupcake..salt +1F9C3..1F9CA ; Extended_Pictographic# 12.0 [8] (🧃..🧊) beverage box..ice cube +1F9CB..1F9CC ; Extended_Pictographic# NA [2] (🧋..🧌) .. +1F9CD..1F9CF ; Extended_Pictographic# 12.0 [3] (🧍..🧏) person standing..deaf person +1F9D0..1F9E6 ; Extended_Pictographic# 10.0 [23] (🧐..🧦) face with monocle..socks +1F9E7..1F9FF ; Extended_Pictographic# 11.0 [25] (🧧..🧿) red envelope..nazar amulet +1FA00..1FA53 ; Extended_Pictographic# 12.0 [84] (🨀..🩓) NEUTRAL CHESS KING..BLACK CHESS KNIGHT-BISHOP +1FA54..1FA5F ; Extended_Pictographic# NA [12] (🩔..🩟) .. +1FA60..1FA6D ; Extended_Pictographic# 11.0 [14] (🩠..🩭) XIANGQI RED GENERAL..XIANGQI BLACK SOLDIER +1FA6E..1FA6F ; Extended_Pictographic# NA [2] (🩮..🩯) .. +1FA70..1FA73 ; Extended_Pictographic# 12.0 [4] (🩰..🩳) ballet shoes..shorts +1FA74..1FA77 ; Extended_Pictographic# NA [4] (🩴..🩷) .. +1FA78..1FA7A ; Extended_Pictographic# 12.0 [3] (🩸..🩺) drop of blood..stethoscope +1FA7B..1FA7F ; Extended_Pictographic# NA [5] (🩻..🩿) .. +1FA80..1FA82 ; Extended_Pictographic# 12.0 [3] (🪀..🪂) yo-yo..parachute +1FA83..1FA8F ; Extended_Pictographic# NA [13] (🪃..🪏) .. +1FA90..1FA95 ; Extended_Pictographic# 12.0 [6] (🪐..🪕) ringed planet..banjo +1FA96..1FFFD ; Extended_Pictographic# NA[1384] (🪖..🿽) .. + +# Total elements: 3793 + +#EOF diff --git a/lib/pleroma/emoji.ex b/lib/pleroma/emoji.ex index 66e20f0e4..3f5169007 100644 --- a/lib/pleroma/emoji.ex +++ b/lib/pleroma/emoji.ex @@ -260,4 +260,29 @@ defmodule Pleroma.Emoji do Enum.any?(patterns, matcher) && group end) end + + {:ok, file} = File.read("lib/pleroma/emoji-data.txt") + + @unicode_emoji file + |> String.split("\n") + |> Enum.filter(fn line -> String.starts_with?(line, ["1", "2", "3", "4"]) end) + |> Enum.map(fn line -> String.split(line) |> List.first() end) + |> Enum.map(fn line -> + case String.split(line, "..") do + [number] -> + String.to_integer(number, 16) + + [first, last] -> + Range.new(String.to_integer(first, 16), String.to_integer(last, 16)) + |> Enum.to_list() + end + end) + |> List.flatten() + |> Enum.filter(&is_integer/1) + |> Enum.uniq() + |> Enum.map(fn n -> :unicode.characters_to_binary([n], :utf32) end) + + def is_unicode_emoji?(str) do + str in @unicode_emoji + end end -- cgit v1.2.3 From e5b3ad3d049a7c665285f724c53f6cafb0e10118 Mon Sep 17 00:00:00 2001 From: lain Date: Fri, 13 Sep 2019 16:06:34 +0200 Subject: ActivityPub: Use is_unicode_emoji? function. --- lib/pleroma/web/activity_pub/activity_pub.ex | 2 +- lib/pleroma/web/activity_pub/utils.ex | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 6cd168427..4ee9b1885 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -315,7 +315,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do def react_with_emoji(user, object, emoji, options \\ []) do with local <- Keyword.get(options, :local, true), activity_id <- Keyword.get(options, :activity_id, nil), - is_emoji?(emoji), + Pleroma.Emoji.is_unicode_emoji?(emoji), reaction_data <- make_emoji_reaction_data(user, object, emoji, activity_id), {:ok, activity} <- insert(reaction_data, local), {:ok, object} <- add_emoji_reaction_to_object(activity, object) do diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index 1e6a67deb..95e040c6c 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -277,10 +277,6 @@ defmodule Pleroma.Web.ActivityPub.Utils do |> Repo.all() end - def is_emoji?(emoji) do - String.length(emoji) == 1 - end - def make_emoji_reaction_data(user, object, emoji, activity_id) do make_like_data(user, object, activity_id) |> Map.put("type", "EmojiReaction") -- cgit v1.2.3 From 3ff55322201fa7f6b22368988095963fcb82d6e4 Mon Sep 17 00:00:00 2001 From: lain Date: Fri, 13 Sep 2019 16:41:30 +0200 Subject: Linting. --- lib/pleroma/web/pleroma_api/pleroma_api_controller.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/pleroma_api/pleroma_api_controller.ex b/lib/pleroma/web/pleroma_api/pleroma_api_controller.ex index 110240115..d41091d93 100644 --- a/lib/pleroma/web/pleroma_api/pleroma_api_controller.ex +++ b/lib/pleroma/web/pleroma_api/pleroma_api_controller.ex @@ -8,10 +8,10 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do import Pleroma.Web.ControllerHelper, only: [add_link_headers: 7] alias Pleroma.Activity - alias Pleroma.Object - alias Pleroma.User alias Pleroma.Conversation.Participation alias Pleroma.Notification + alias Pleroma.Object + alias Pleroma.User alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.CommonAPI alias Pleroma.Web.MastodonAPI.AccountView -- cgit v1.2.3 From 6fe2f554c36be1ef03ac1d1104a78d0686f48a26 Mon Sep 17 00:00:00 2001 From: lain Date: Fri, 13 Sep 2019 18:27:32 +0200 Subject: Emoji: Generate emoji detecting functions at compile time. Suggested by jvalim --- lib/pleroma/emoji.ex | 52 +++++++++++++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 23 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/emoji.ex b/lib/pleroma/emoji.ex index 3f5169007..65f2d5f39 100644 --- a/lib/pleroma/emoji.ex +++ b/lib/pleroma/emoji.ex @@ -261,28 +261,34 @@ defmodule Pleroma.Emoji do end) end - {:ok, file} = File.read("lib/pleroma/emoji-data.txt") - - @unicode_emoji file - |> String.split("\n") - |> Enum.filter(fn line -> String.starts_with?(line, ["1", "2", "3", "4"]) end) - |> Enum.map(fn line -> String.split(line) |> List.first() end) - |> Enum.map(fn line -> - case String.split(line, "..") do - [number] -> - String.to_integer(number, 16) - - [first, last] -> - Range.new(String.to_integer(first, 16), String.to_integer(last, 16)) - |> Enum.to_list() - end - end) - |> List.flatten() - |> Enum.filter(&is_integer/1) - |> Enum.uniq() - |> Enum.map(fn n -> :unicode.characters_to_binary([n], :utf32) end) - - def is_unicode_emoji?(str) do - str in @unicode_emoji + @external_resource "lib/pleroma/emoji-data.txt" + + emojis = + @external_resource + |> File.read!() + |> String.split("\n") + |> Enum.filter(fn line -> line != "" and not String.starts_with?(line, "#") end) + |> Enum.map(fn line -> + line + |> String.split(";", parts: 2) + |> hd() + |> String.trim() + |> String.split("..") + |> case do + [number] -> + <> + + [first, last] -> + String.to_integer(first, 16)..String.to_integer(last, 16) + |> Enum.map(&<<&1::utf8>>) + end + end) + |> List.flatten() + |> Enum.uniq() + + for emoji <- emojis do + def is_unicode_emoji?(unquote(emoji)), do: true end + + def is_unicode_emoji?(_), do: false end -- cgit v1.2.3 From 04a2910f33405db368687f8749b405eeac06df63 Mon Sep 17 00:00:00 2001 From: lain Date: Mon, 30 Sep 2019 15:13:05 +0200 Subject: Pleroma.Constants: Fix typo. --- lib/pleroma/constants.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/constants.ex b/lib/pleroma/constants.ex index 7d775c3c2..1a432e681 100644 --- a/lib/pleroma/constants.ex +++ b/lib/pleroma/constants.ex @@ -10,7 +10,7 @@ defmodule Pleroma.Constants do const(object_internal_fields, do: [ "reactions", - "reactions_count", + "reaction_count", "likes", "like_count", "announcements", -- cgit v1.2.3 From 6068d2254e2ed00260dc840f18824dc0e0835afa Mon Sep 17 00:00:00 2001 From: lain Date: Mon, 30 Sep 2019 15:13:25 +0200 Subject: PleromaAPIController: Fixes and refactoring. --- .../pleroma_api/controllers/pleroma_api_controller.ex | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) (limited to 'lib') 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 474b8d079..39d371ff7 100644 --- a/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex @@ -23,17 +23,12 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do with %Activity{} = activity <- Activity.get_by_id_with_object(activity_id), %Object{data: %{"reactions" => emoji_reactions}} <- Object.normalize(activity) do reactions = - Enum.reduce(emoji_reactions, %{}, fn {emoji, users}, res -> - users = - users - |> Enum.map(&User.get_cached_by_ap_id/1) - - res - |> Map.put( - emoji, - AccountView.render("accounts.json", %{users: users, for: user, as: :user}) - ) + emoji_reactions + |> Enum.map(fn {emoji, users} -> + users = Enum.map(users, &User.get_cached_by_ap_id/1) + {emoji, AccountView.render("accounts.json", %{users: users, for: user, as: :user})} end) + |> Enum.into(%{}) conn |> json(reactions) @@ -49,7 +44,7 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do activity = Activity.get_by_id(activity_id) do conn |> put_view(StatusView) - |> render("status.json", %{activity: activity, for: user, as: :activity}) + |> render("show.json", %{activity: activity, for: user, as: :activity}) end end -- cgit v1.2.3 From 08256e9299494c0bcd1a295c6079263277b21ba7 Mon Sep 17 00:00:00 2001 From: lain Date: Mon, 30 Sep 2019 15:51:09 +0200 Subject: ActivityPub: Federate reactions. --- lib/pleroma/web/activity_pub/activity_pub.ex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 77fa23db4..a6fb67a28 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -313,7 +313,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do Pleroma.Emoji.is_unicode_emoji?(emoji), reaction_data <- make_emoji_reaction_data(user, object, emoji, activity_id), {:ok, activity} <- insert(reaction_data, local), - {:ok, object} <- add_emoji_reaction_to_object(activity, object) do + {:ok, object} <- add_emoji_reaction_to_object(activity, object), + :ok <- maybe_federate(activity) do {:ok, activity, object} end end -- cgit v1.2.3 From 19bc0b8c79765dc485e081651a4e4c589d18b970 Mon Sep 17 00:00:00 2001 From: lain Date: Mon, 30 Sep 2019 16:38:19 +0200 Subject: . --- lib/pleroma/web/activity_pub/activity_pub.ex | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index a6fb67a28..1f201d587 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -319,6 +319,13 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do end end + def unreact_with_emoji(user, reaction_id, option \\ []) do + with local <- Keyword.get(options, :local, true), + activity_id <- Keyword.get(options, :activity_id, nil), + %Activity{actor: ^user.ap_id} = reaction_activity <- Activity.get_by_ap_id(reaction_id), + unreact_data + end + # TODO: This is weird, maybe we shouldn't check here if we can make the activity. def like( %User{ap_id: ap_id} = user, -- cgit v1.2.3 From dfe5c958eb94326f5a7743c9de0de073260db926 Mon Sep 17 00:00:00 2001 From: lain Date: Wed, 2 Oct 2019 15:08:20 +0200 Subject: ActivityPub: Add undo for emoji reactions. --- lib/pleroma/web/activity_pub/activity_pub.ex | 13 +++++++--- lib/pleroma/web/activity_pub/utils.ex | 37 ++++++++++++++++++++++++++++ lib/pleroma/web/router.ex | 2 -- 3 files changed, 47 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index a9e53141d..458d3590d 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -319,11 +319,18 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do end end - def unreact_with_emoji(user, reaction_id, option \\ []) do + def unreact_with_emoji(user, reaction_id, options \\ []) do with local <- Keyword.get(options, :local, true), activity_id <- Keyword.get(options, :activity_id, nil), - %Activity{actor: ^user.ap_id} = reaction_activity <- Activity.get_by_ap_id(reaction_id), - unreact_data + user_ap_id <- user.ap_id, + %Activity{actor: ^user_ap_id} = reaction_activity <- Activity.get_by_ap_id(reaction_id), + object <- Object.normalize(reaction_activity), + unreact_data <- make_undo_data(user, reaction_activity, activity_id), + {:ok, activity} <- insert(unreact_data, local), + {:ok, object} <- remove_emoji_reaction_from_object(reaction_activity, object), + :ok <- maybe_federate(activity) do + {:ok, activity, object} + end end # TODO: This is weird, maybe we shouldn't check here if we can make the activity. diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index 4c146fd86..7807fa9cd 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -337,6 +337,24 @@ defmodule Pleroma.Web.ActivityPub.Utils do update_element_in_object("reaction", new_reactions, object) end + def remove_emoji_reaction_from_object( + %Activity{data: %{"content" => emoji, "actor" => actor}}, + object + ) do + reactions = object.data["reactions"] || %{} + emoji_actors = reactions[emoji] || [] + new_emoji_actors = List.delete(emoji_actors, actor) + + new_reactions = + if new_emoji_actors == [] do + Map.delete(reactions, emoji) + else + Map.put(reactions, emoji, new_emoji_actors) + end + + update_element_in_object("reaction", new_reactions, object) + end + @spec add_like_to_object(Activity.t(), Object.t()) :: {:ok, Object.t()} | {:error, Ecto.Changeset.t()} def add_like_to_object(%Activity{data: %{"actor" => actor}}, object) do @@ -522,6 +540,25 @@ defmodule Pleroma.Web.ActivityPub.Utils do |> maybe_put("id", activity_id) end + def make_undo_data( + %User{ap_id: actor, follower_address: follower_address}, + %Activity{ + data: %{"id" => undone_activity_id, "context" => context}, + actor: undone_activity_actor + }, + activity_id \\ nil + ) do + %{ + "type" => "Undo", + "actor" => actor, + "object" => undone_activity_id, + "to" => [follower_address, undone_activity_actor], + "cc" => [Pleroma.Constants.as_public()], + "context" => context + } + |> maybe_put("id", activity_id) + end + @spec add_announce_to_object(Activity.t(), Object.t()) :: {:ok, Object.t()} | {:error, Ecto.Changeset.t()} def add_announce_to_object( diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index eae1f676b..ff3dc273e 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -293,8 +293,6 @@ defmodule Pleroma.Web.Router do end scope "/api/v1/pleroma", Pleroma.Web.PleromaAPI do - pipe_through(:authenticated_api) - scope [] do pipe_through(:authenticated_api) pipe_through(:oauth_read) -- cgit v1.2.3 From 9cfe9a57c5a31318abf02fa510d4fdf78505bd97 Mon Sep 17 00:00:00 2001 From: lain Date: Wed, 2 Oct 2019 15:38:57 +0200 Subject: CommonAPI: Add unreactions. --- lib/pleroma/web/activity_pub/utils.ex | 13 +++++++++++++ lib/pleroma/web/common_api/common_api.ex | 9 +++++++++ 2 files changed, 22 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index 7807fa9cd..82e2d8f76 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -452,6 +452,19 @@ defmodule Pleroma.Web.ActivityPub.Utils do |> Repo.one() end + def get_latest_reaction(internal_activity_id, %{ap_id: ap_id}, emoji) do + %{data: %{"object" => object_ap_id}} = Activity.get_by_id(internal_activity_id) + + "EmojiReaction" + |> Activity.Queries.by_type() + |> where(actor: ^ap_id) + |> where([activity], fragment("?->>'content' = ?", activity.data, ^emoji)) + |> Activity.Queries.by_object_id(object_ap_id) + |> order_by([activity], fragment("? desc nulls last", activity.id)) + |> limit(1) + |> Repo.one() + end + #### Announce-related helpers @doc """ diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex index 53ada8fab..995d4b1af 100644 --- a/lib/pleroma/web/common_api/common_api.ex +++ b/lib/pleroma/web/common_api/common_api.ex @@ -125,6 +125,15 @@ defmodule Pleroma.Web.CommonAPI do end end + def unreact_with_emoji(id, user, emoji) do + with %Activity{} = reaction_activity <- Utils.get_latest_reaction(id, user, emoji) do + ActivityPub.unreact_with_emoji(user, reaction_activity.data["id"]) + else + _ -> + {:error, dgettext("errors", "Could not remove reaction emoji")} + end + end + def vote(user, %{data: %{"type" => "Question"}} = object, choices) do with :ok <- validate_not_author(object, user), :ok <- validate_existing_votes(user, object), -- cgit v1.2.3 From 391c7362921ba94a0084b7a25c4126ce7026dc55 Mon Sep 17 00:00:00 2001 From: lain Date: Wed, 2 Oct 2019 18:13:10 +0200 Subject: PleromaAPI: Fix emoji_reactions_by --- lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') 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 39d371ff7..884b3d877 100644 --- a/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex @@ -26,7 +26,7 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do emoji_reactions |> Enum.map(fn {emoji, users} -> users = Enum.map(users, &User.get_cached_by_ap_id/1) - {emoji, AccountView.render("accounts.json", %{users: users, for: user, as: :user})} + {emoji, AccountView.render("index.json", %{users: users, for: user, as: :user})} end) |> Enum.into(%{}) -- cgit v1.2.3 From 4cb603e1df7c9d13db1aa4285e2a18b9be71cd78 Mon Sep 17 00:00:00 2001 From: lain Date: Wed, 2 Oct 2019 18:19:16 +0200 Subject: PleromaAPI: Add unreacting. --- .../web/pleroma_api/controllers/pleroma_api_controller.ex | 14 +++++++++++++- lib/pleroma/web/router.ex | 1 + 2 files changed, 14 insertions(+), 1 deletion(-) (limited to 'lib') 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 884b3d877..8aee7d7c5 100644 --- a/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex @@ -41,7 +41,19 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do def react_with_emoji(%{assigns: %{user: user}} = conn, %{"id" => activity_id, "emoji" => emoji}) do with {:ok, _activity, _object} <- CommonAPI.react_with_emoji(activity_id, user, emoji), - activity = Activity.get_by_id(activity_id) do + 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, _object} <- 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}) diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index ff3dc273e..87d373f55 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -305,6 +305,7 @@ defmodule Pleroma.Web.Router do pipe_through(:oauth_write) patch("/conversations/:id", PleromaAPIController, :update_conversation) post("/statuses/:id/react_with_emoji", PleromaAPIController, :react_with_emoji) + post("/statuses/:id/unreact_with_emoji", PleromaAPIController, :unreact_with_emoji) post("/notifications/read", PleromaAPIController, :read_notification) patch("/accounts/update_avatar", AccountController, :update_avatar) -- cgit v1.2.3 From c9043c6c808129f4f6236d03bf05e5a46f0c6e14 Mon Sep 17 00:00:00 2001 From: lain Date: Thu, 3 Oct 2019 18:37:23 +0200 Subject: Transmogrifier: Handle incoming Undos for EmojiReactions. --- lib/pleroma/web/activity_pub/transmogrifier.ex | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index cb868c336..ea209b5ea 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -721,6 +721,28 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do end end + def handle_incoming( + %{ + "type" => "Undo", + "object" => %{"type" => "EmojiReaction", "id" => reaction_activity_id}, + "actor" => _actor, + "id" => id + } = data, + _options + ) do + with actor <- Containment.get_actor(data), + {:ok, %User{} = actor} <- User.get_or_fetch_by_ap_id(actor), + {:ok, activity, _} <- + ActivityPub.unreact_with_emoji(actor, reaction_activity_id, + activity_id: id, + local: false + ) do + {:ok, activity} + else + _e -> :error + end + end + def handle_incoming( %{ "type" => "Undo", -- cgit v1.2.3 From 43a211bcb111720622a89da3016372f5a3a12184 Mon Sep 17 00:00:00 2001 From: lain Date: Fri, 4 Oct 2019 17:01:04 +0200 Subject: Transmogrifier: Handle misskey likes with reactions like EmojiReactions. --- lib/pleroma/web/activity_pub/transmogrifier.ex | 27 ++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index ea209b5ea..54c18bc0e 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -560,6 +560,33 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do end end + @misskey_reactions %{ + "like" => "👍", + "love" => "❤️", + "laugh" => "😆", + "hmm" => "🤔", + "surprise" => "😮", + "congrats" => "🎉", + "angry" => "💢", + "confused" => "😥", + "rip" => "😇", + "pudding" => "🍮" + } + + @doc "Rewrite misskey likes into EmojiReactions" + def handle_incoming( + %{ + "type" => "Like", + "_misskey_reaction" => reaction + } = data, + options + ) do + data + |> Map.put("type", "EmojiReaction") + |> Map.put("content", @misskey_reactions[reaction]) + |> handle_incoming(options) + end + def handle_incoming( %{"type" => "Like", "object" => object_id, "actor" => _actor, "id" => id} = data, _options -- cgit v1.2.3 From 8dcc2f9f5ecbbc81bc026c85582695de4fbc1a0f Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Fri, 4 Oct 2019 19:00:58 +0300 Subject: Admin API: Allow changing the state of multiple reports at once --- lib/pleroma/web/activity_pub/utils.ex | 12 ++++++++++ lib/pleroma/web/admin_api/admin_api_controller.ex | 29 +++++++++++++++-------- lib/pleroma/web/common_api/common_api.ex | 7 ++++++ lib/pleroma/web/router.ex | 2 +- 4 files changed, 39 insertions(+), 11 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index 0828591ee..824957314 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -672,6 +672,18 @@ defmodule Pleroma.Web.ActivityPub.Utils do |> Repo.update() end + def update_report_state(activity_ids, state) when state in @supported_report_states do + activities_num = length(activity_ids) + + from(a in Activity, where: a.id in ^activity_ids) + |> update(set: [data: fragment("jsonb_set(data, '{state}', ?)", ^state)]) + |> Repo.update_all([]) + |> case do + {^activities_num, _} -> :ok + _ -> {:error, activity_ids} + end + end + def update_report_state(_, _), do: {:error, "Unsupported state"} def update_activity_visibility(activity, visibility) when visibility in @valid_visibilities do diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index 21da8a7ff..0e8c9dac8 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -480,17 +480,26 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do end end - def report_update_state(%{assigns: %{user: admin}} = conn, %{"id" => id, "state" => state}) do - with {:ok, report} <- CommonAPI.update_report_state(id, state) do - ModerationLog.insert_log(%{ - action: "report_update", - actor: admin, - subject: report - }) + def reports_update(%{assigns: %{user: admin}} = conn, %{"reports" => reports}) do + result = + reports + |> Enum.map(fn report -> + with {:ok, activity} <- CommonAPI.update_report_state(report["id"], report["state"]) do + ModerationLog.insert_log(%{ + action: "report_update", + actor: admin, + subject: activity + }) + + activity + else + {:error, message} -> %{id: report["id"], error: message} + end + end) - conn - |> put_view(ReportView) - |> render("show.json", Report.extract_report_info(report)) + case Enum.any?(result, &Map.has_key?(&1, :error)) do + true -> json_response(conn, :bad_request, result) + false -> json_response(conn, :no_content, "") end end diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex index ce73b3270..2b80598ea 100644 --- a/lib/pleroma/web/common_api/common_api.ex +++ b/lib/pleroma/web/common_api/common_api.ex @@ -346,6 +346,13 @@ defmodule Pleroma.Web.CommonAPI do end end + def update_report_state(activity_ids, state) when is_list(activity_ids) do + case Utils.update_report_state(activity_ids, state) do + :ok -> {:ok, activity_ids} + _ -> {:error, dgettext("errors", "Could not update state")} + end + end + def update_report_state(activity_id, state) do with %Activity{} = activity <- Activity.get_by_id(activity_id) do Utils.update_report_state(activity, state) diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index f91af8137..563b01dc5 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -194,7 +194,7 @@ defmodule Pleroma.Web.Router do get("/reports", AdminAPIController, :list_reports) get("/reports/:id", AdminAPIController, :report_show) - put("/reports/:id", AdminAPIController, :report_update_state) + patch("/reports", AdminAPIController, :reports_update) post("/reports/:id/respond", AdminAPIController, :report_respond) put("/statuses/:id", AdminAPIController, :status_update) -- cgit v1.2.3 From 6a85f7d1eabd957588a2f9b8dfea5b7f982573be Mon Sep 17 00:00:00 2001 From: lain Date: Sat, 5 Oct 2019 10:45:42 +0200 Subject: Transmogrifier: Extend misskey like compatibility. --- lib/pleroma/web/activity_pub/transmogrifier.ex | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index 54c18bc0e..2c6edb0b1 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -570,7 +570,8 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do "angry" => "💢", "confused" => "😥", "rip" => "😇", - "pudding" => "🍮" + "pudding" => "🍮", + "star" => "⭐" } @doc "Rewrite misskey likes into EmojiReactions" @@ -583,7 +584,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do ) do data |> Map.put("type", "EmojiReaction") - |> Map.put("content", @misskey_reactions[reaction]) + |> Map.put("content", @misskey_reactions[reaction] || reaction) |> handle_incoming(options) end -- cgit v1.2.3 From d580eedfe93ef08fea7869945c0fd4fe908cb82d Mon Sep 17 00:00:00 2001 From: lain Date: Mon, 7 Oct 2019 12:40:33 +0200 Subject: Linting. --- lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') 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 16c581a95..6db213475 100644 --- a/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex @@ -11,8 +11,8 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do alias Pleroma.Conversation.Participation alias Pleroma.Notification alias Pleroma.Object - alias Pleroma.User alias Pleroma.Plugs.OAuthScopesPlug + alias Pleroma.User alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.CommonAPI alias Pleroma.Web.MastodonAPI.AccountView -- cgit v1.2.3 From 7aceaa517be7b109a9acc15fb4914535b536b66c Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Mon, 7 Oct 2019 15:01:18 +0300 Subject: Admin API: Reports, grouped by status --- lib/pleroma/activity.ex | 21 ++++++ lib/pleroma/web/activity_pub/utils.ex | 89 +++++++++++++++++++++++ lib/pleroma/web/admin_api/admin_api_controller.ex | 17 ++--- lib/pleroma/web/admin_api/views/report_view.ex | 20 +++++ lib/pleroma/web/router.ex | 1 + 5 files changed, 138 insertions(+), 10 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex index c1065611b..daf0ed89f 100644 --- a/lib/pleroma/activity.ex +++ b/lib/pleroma/activity.ex @@ -41,6 +41,9 @@ defmodule Pleroma.Activity do field(:actor, :string) field(:recipients, {:array, :string}, default: []) field(:thread_muted?, :boolean, virtual: true) + + # This is a fake relation, do not use outside of with_preloaded_user_actor/with_joined_user_actor + has_one(:user_actor, User, on_delete: :nothing, foreign_key: :id) # This is a fake relation, do not use outside of with_preloaded_bookmark/get_bookmark has_one(:bookmark, Bookmark) has_many(:notifications, Notification, on_delete: :delete_all) @@ -86,6 +89,24 @@ defmodule Pleroma.Activity do |> preload([activity, object: object], object: object) end + def with_joined_user_actor(query, join_type \\ :inner) do + join(query, join_type, [activity], u in User, + on: + fragment( + "? = ?->>'actor'", + u.ap_id, + activity.data + ), + as: :user_actor + ) + end + + def with_preloaded_user_actor(query, join_type \\ :inner) do + query + |> with_joined_user_actor(join_type) + |> preload([activity, user_actor: user_actor], user_actor: user_actor) + end + def with_preloaded_bookmark(query, %User{} = user) do from([a] in query, left_join: b in Bookmark, diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index 824957314..74eb994ab 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -6,11 +6,13 @@ defmodule Pleroma.Web.ActivityPub.Utils do alias Ecto.Changeset alias Ecto.UUID alias Pleroma.Activity + alias Pleroma.Activity.Queries alias Pleroma.Notification alias Pleroma.Object alias Pleroma.Repo alias Pleroma.User alias Pleroma.Web + alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.Visibility alias Pleroma.Web.Endpoint alias Pleroma.Web.Router.Helpers @@ -664,6 +666,93 @@ defmodule Pleroma.Web.ActivityPub.Utils do #### Report-related helpers + def get_reports(params, page, page_size) do + params = + params + |> Map.put("type", "Flag") + |> Map.put("skip_preload", true) + |> Map.put("total", true) + |> Map.put("limit", page_size) + |> Map.put("offset", (page - 1) * page_size) + + ActivityPub.fetch_activities([], params, :offset) + end + + @spec get_reports_grouped_by_status() :: %{ + required(:groups) => [ + %{ + required(:date) => String.t(), + required(:account) => %User{}, + required(:status) => %Activity{}, + required(:actors) => [%User{}], + required(:reports) => [%Activity{}] + } + ], + required(:total) => integer + } + def get_reports_grouped_by_status do + paginated_activities = get_reported_status_ids() + + groups = + paginated_activities + |> Enum.map(fn entry -> + status = + Activity + |> Queries.by_ap_id(entry[:activity_id]) + |> Activity.with_preloaded_object(:left) + |> Activity.with_preloaded_user_actor() + |> Repo.one() + + reports = get_reports_by_status_id(status.data["id"]) + + max_date = + Enum.max_by(reports, &Pleroma.Web.CommonAPI.Utils.to_masto_date(&1.data["published"])).data[ + "published" + ] + + actors = Enum.map(reports, & &1.user_actor) + + %{ + date: max_date, + account: status.user_actor, + status: status, + actors: actors, + reports: reports + } + end) + + %{ + groups: groups + } + end + + def get_reports_by_status_id(status_id) do + from(a in Activity, + where: fragment("(?)->>'type' = 'Flag'", a.data), + where: fragment("(?)->'object' \\? (?)", a.data, ^status_id) + ) + |> Activity.with_preloaded_user_actor() + |> Repo.all() + end + + @spec get_reported_status_ids() :: %{ + required(:items) => [%Activity{}], + required(:total) => integer + } + def get_reported_status_ids do + from(a in Activity, + where: fragment("(?)->>'type' = 'Flag'", a.data), + select: %{ + date: fragment("max(?->>'published') date", a.data), + activity_id: + fragment("jsonb_array_elements_text((? #- '{object,0}')->'object') activity_id", a.data) + }, + group_by: fragment("activity_id"), + order_by: fragment("date DESC") + ) + |> Repo.all() + end + def update_report_state(%Activity{} = activity, state) when state in @supported_report_states do new_data = Map.put(activity.data, "state", state) diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index 0e8c9dac8..463dd327a 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -10,6 +10,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do alias Pleroma.UserInviteToken alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.Relay + alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.AdminAPI.AccountView alias Pleroma.Web.AdminAPI.Config alias Pleroma.Web.AdminAPI.ConfigView @@ -455,19 +456,15 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do def list_reports(conn, params) do {page, page_size} = page_params(params) - params = - params - |> Map.put("type", "Flag") - |> Map.put("skip_preload", true) - |> Map.put("total", true) - |> Map.put("limit", page_size) - |> Map.put("offset", (page - 1) * page_size) - - reports = ActivityPub.fetch_activities([], params, :offset) + conn + |> put_view(ReportView) + |> render("index.json", %{reports: Utils.get_reports(params, page, page_size)}) + end + def list_grouped_reports(conn, _params) do conn |> put_view(ReportView) - |> render("index.json", %{reports: reports}) + |> render("index_grouped.json", Utils.get_reports_grouped_by_status()) end def report_show(conn, %{"id" => id}) do diff --git a/lib/pleroma/web/admin_api/views/report_view.ex b/lib/pleroma/web/admin_api/views/report_view.ex index 101a74c63..ac25925da 100644 --- a/lib/pleroma/web/admin_api/views/report_view.ex +++ b/lib/pleroma/web/admin_api/views/report_view.ex @@ -42,6 +42,26 @@ defmodule Pleroma.Web.AdminAPI.ReportView do } end + def render("index_grouped.json", %{groups: groups}) do + reports = + Enum.map(groups, fn group -> + %{ + date: group[:date], + account: merge_account_views(group[:account]), + status: StatusView.render("show.json", %{activity: group[:status]}), + actors: Enum.map(group[:actors], &merge_account_views/1), + reports: + group[:reports] + |> Enum.map(&Report.extract_report_info(&1)) + |> Enum.map(&render(__MODULE__, "show.json", &1)) + } + end) + + %{ + reports: reports + } + end + defp merge_account_views(%User{} = user) do Pleroma.Web.MastodonAPI.AccountView.render("show.json", %{user: user}) |> Map.merge(Pleroma.Web.AdminAPI.AccountView.render("show.json", %{user: user})) diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 563b01dc5..b895a7b7e 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -193,6 +193,7 @@ defmodule Pleroma.Web.Router do get("/users/:nickname/statuses", AdminAPIController, :list_user_statuses) get("/reports", AdminAPIController, :list_reports) + get("/grouped_reports", AdminAPIController, :list_grouped_reports) get("/reports/:id", AdminAPIController, :report_show) patch("/reports", AdminAPIController, :reports_update) post("/reports/:id/respond", AdminAPIController, :report_respond) -- cgit v1.2.3 From aa7fd616c7cfeb84551af2170886856a815dc498 Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Mon, 7 Oct 2019 16:03:23 +0300 Subject: Line is too long! --- lib/pleroma/activity.ex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex index daf0ed89f..7b77f72c2 100644 --- a/lib/pleroma/activity.ex +++ b/lib/pleroma/activity.ex @@ -42,7 +42,8 @@ defmodule Pleroma.Activity do field(:recipients, {:array, :string}, default: []) field(:thread_muted?, :boolean, virtual: true) - # This is a fake relation, do not use outside of with_preloaded_user_actor/with_joined_user_actor + # This is a fake relation, + # do not use outside of with_preloaded_user_actor/with_joined_user_actor has_one(:user_actor, User, on_delete: :nothing, foreign_key: :id) # This is a fake relation, do not use outside of with_preloaded_bookmark/get_bookmark has_one(:bookmark, Bookmark) -- cgit v1.2.3 From b777083f3f396a7d8c357ec968f72679befc691c Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Fri, 25 Oct 2019 19:14:18 +0700 Subject: Add `also_known_as` field to Pleroma.User --- lib/pleroma/user.ex | 10 +++++++--- lib/pleroma/web/activity_pub/activity_pub.ex | 3 ++- lib/pleroma/web/activity_pub/transmogrifier.ex | 2 +- 3 files changed, 10 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 7bef6e281..f25345140 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -105,6 +105,7 @@ defmodule Pleroma.User do field(:discoverable, :boolean, default: false) field(:invisible, :boolean, default: false) field(:skip_thread_containment, :boolean, default: false) + field(:also_known_as, {:array, :string}, default: []) field(:notification_settings, :map, default: %{ @@ -324,7 +325,8 @@ defmodule Pleroma.User do :fields, :following_count, :discoverable, - :invisible + :invisible, + :also_known_as ] ) |> validate_required([:name, :ap_id]) @@ -373,7 +375,8 @@ defmodule Pleroma.User do :fields, :raw_fields, :pleroma_settings_store, - :discoverable + :discoverable, + :also_known_as ] ) |> unique_constraint(:nickname) @@ -413,7 +416,8 @@ defmodule Pleroma.User do :hide_followers, :discoverable, :hide_followers_count, - :hide_follows_count + :hide_follows_count, + :also_known_as ] ) |> unique_constraint(:nickname) diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 07dde3537..dc962673c 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -1117,7 +1117,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do name: data["name"], follower_address: data["followers"], following_address: data["following"], - bio: data["summary"] + bio: data["summary"], + also_known_as: Map.get(data, "alsoKnownAs", []) } # nickname can be nil because of virtual actors diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index 9b3ee842b..6ada38e1a 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -616,7 +616,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do update_data = new_user_data - |> Map.take([:avatar, :banner, :bio, :name]) + |> Map.take([:avatar, :banner, :bio, :name, :also_known_as]) |> Map.put(:fields, fields) |> Map.put(:locked, locked) |> Map.put(:invisible, invisible) -- cgit v1.2.3 From 61fc739ab8917ccb5a12d6ab6db6130dc231990b Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Wed, 30 Oct 2019 18:21:49 +0700 Subject: Handle "Move" activity --- lib/pleroma/following_relationship.ex | 24 ++++++++++++++++++++++++ lib/pleroma/web/activity_pub/activity_pub.ex | 24 ++++++++++++++++++++++++ lib/pleroma/web/activity_pub/transmogrifier.ex | 18 ++++++++++++++++++ lib/pleroma/web/activity_pub/visibility.ex | 1 + lib/pleroma/workers/background_worker.ex | 7 +++++++ 5 files changed, 74 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/following_relationship.ex b/lib/pleroma/following_relationship.ex index 2ffac17ee..2f89eb4cf 100644 --- a/lib/pleroma/following_relationship.ex +++ b/lib/pleroma/following_relationship.ex @@ -107,4 +107,28 @@ defmodule Pleroma.FollowingRelationship do [user.follower_address | following] end end + + def move_following(origin, target) do + following_relationships = + __MODULE__ + |> where(following_id: ^origin.id) + |> preload([:follower]) + |> limit(50) + |> Repo.all() + + case following_relationships do + [] -> + :ok + + following_relationships -> + Enum.each(following_relationships, fn following_relationship -> + Repo.transaction(fn -> + Repo.delete(following_relationship) + User.follow(following_relationship.follower, target) + end) + end) + + move_following(origin, target) + end + end end diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 6adadacdc..67c2cb659 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -514,6 +514,30 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do end end + def move(%User{} = origin, %User{} = target, local \\ true) do + params = %{ + "type" => "Move", + "actor" => origin.ap_id, + "object" => origin.ap_id, + "target" => target.ap_id + } + + with true <- origin.ap_id in target.also_known_as, + {:ok, activity} <- insert(params, local) do + maybe_federate(activity) + + BackgroundWorker.enqueue("move_following", %{ + "origin_id" => origin.id, + "target_id" => target.id + }) + + {:ok, activity} + else + false -> {:error, "Target account must have the origin in `alsoKnownAs`"} + err -> err + end + end + defp fetch_activities_for_context_query(context, opts) do public = [Pleroma.Constants.as_public()] diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index c23f2dcd0..78ee6192a 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -785,6 +785,24 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do end end + def handle_incoming( + %{ + "type" => "Move", + "actor" => origin_actor, + "object" => origin_actor, + "target" => target_actor + }, + _options + ) do + with %User{} = origin_user <- User.get_cached_by_ap_id(origin_actor), + {:ok, %User{} = target_user} <- User.get_or_fetch_by_ap_id(target_actor), + true <- origin_actor in target_user.also_known_as do + ActivityPub.move(origin_user, target_user, false) + else + _e -> :error + end + end + def handle_incoming(_, _), do: :error @spec get_obj_helper(String.t(), Keyword.t()) :: {:ok, Object.t()} | nil diff --git a/lib/pleroma/web/activity_pub/visibility.ex b/lib/pleroma/web/activity_pub/visibility.ex index cd4097493..e172f6d3f 100644 --- a/lib/pleroma/web/activity_pub/visibility.ex +++ b/lib/pleroma/web/activity_pub/visibility.ex @@ -14,6 +14,7 @@ defmodule Pleroma.Web.ActivityPub.Visibility do @spec is_public?(Object.t() | Activity.t() | map()) :: boolean() def is_public?(%Object{data: %{"type" => "Tombstone"}}), do: false def is_public?(%Object{data: data}), do: is_public?(data) + def is_public?(%Activity{data: %{"type" => "Move"}}), do: true def is_public?(%Activity{data: data}), do: is_public?(data) def is_public?(%{"directMessage" => true}), do: false def is_public?(data), do: Utils.label_in_message?(Pleroma.Constants.as_public(), data) diff --git a/lib/pleroma/workers/background_worker.ex b/lib/pleroma/workers/background_worker.ex index 7ffc8eabe..323a4da1e 100644 --- a/lib/pleroma/workers/background_worker.ex +++ b/lib/pleroma/workers/background_worker.ex @@ -71,4 +71,11 @@ defmodule Pleroma.Workers.BackgroundWorker do activity = Activity.get_by_id(activity_id) Pleroma.Web.RichMedia.Helpers.perform(:fetch, activity) end + + def perform(%{"op" => "move_following", "origin_id" => origin_id, "target_id" => target_id}, _) do + origin = User.get_cached_by_id(origin_id) + target = User.get_cached_by_id(target_id) + + Pleroma.FollowingRelationship.move_following(origin, target) + end end -- cgit v1.2.3 From 743b622b7b59148525d0f941de3a7c4af7825d22 Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Fri, 1 Nov 2019 18:45:47 +0300 Subject: Force password reset for multiple users --- lib/pleroma/moderation_log.ex | 11 +++++++++++ lib/pleroma/web/admin_api/admin_api_controller.ex | 12 +++++++++--- lib/pleroma/web/router.ex | 2 +- 3 files changed, 21 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/moderation_log.ex b/lib/pleroma/moderation_log.ex index e8884e6e8..9031102ed 100644 --- a/lib/pleroma/moderation_log.ex +++ b/lib/pleroma/moderation_log.ex @@ -540,6 +540,17 @@ defmodule Pleroma.ModerationLog do "@#{actor_nickname} deleted status ##{subject_id}" end + @spec get_log_entry_message(ModerationLog) :: String.t() + def get_log_entry_message(%ModerationLog{ + data: %{ + "actor" => %{"nickname" => actor_nickname}, + "action" => "force_password_reset", + "subject" => subjects + } + }) do + "@#{actor_nickname} force password reset for users: #{users_to_nicknames_string(subjects)}" + end + defp nicknames_to_string(nicknames) do nicknames |> Enum.map(&"@#{&1}") diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index 7ffbb23e7..b08011b4c 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -595,10 +595,16 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do end @doc "Force password reset for a given user" - def force_password_reset(conn, %{"nickname" => nickname}) do - (%User{local: true} = user) = User.get_cached_by_nickname(nickname) + def force_password_reset(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) do + users = nicknames |> Enum.map(&User.get_cached_by_nickname/1) - User.force_password_reset_async(user) + Enum.map(users, &User.force_password_reset_async/1) + + ModerationLog.insert_log(%{ + actor: admin, + subject: users, + action: "force_password_reset" + }) json_response(conn, :no_content, "") end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index f69c5c2bc..8fb4aec13 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -171,7 +171,7 @@ defmodule Pleroma.Web.Router do post("/users/email_invite", AdminAPIController, :email_invite) get("/users/:nickname/password_reset", AdminAPIController, :get_password_reset) - patch("/users/:nickname/force_password_reset", AdminAPIController, :force_password_reset) + patch("/users/force_password_reset", AdminAPIController, :force_password_reset) get("/users", AdminAPIController, :list_users) get("/users/:nickname", AdminAPIController, :user_show) -- cgit v1.2.3 From 4b7c11e3f928befaa13daf142a2405284b0d07e5 Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Mon, 4 Nov 2019 20:44:24 +0300 Subject: excluded invisible actors from gets /api/v1/accounts/:id --- lib/pleroma/user.ex | 31 ++++++++++++---------- lib/pleroma/web/activity_pub/relay.ex | 1 - .../mastodon_api/controllers/account_controller.ex | 2 +- 3 files changed, 18 insertions(+), 16 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index f8c2db1e1..abd1dd936 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -131,6 +131,8 @@ defmodule Pleroma.User do def visible_for?(user, for_user \\ nil) + def visible_for?(%User{invisible: true}, _), do: false + def visible_for?(%User{id: user_id}, %User{id: for_id}) when user_id == for_id, do: true def visible_for?(%User{} = user, for_user) do @@ -1314,22 +1316,23 @@ defmodule Pleroma.User do end end - @doc "Creates an internal service actor by URI if missing. Optionally takes nickname for addressing." + @doc """ + Creates an internal service actor by URI if missing. + Optionally takes nickname for addressing. + """ def get_or_create_service_actor_by_ap_id(uri, nickname \\ nil) do - with %User{} = user <- get_cached_by_ap_id(uri) do - user - else - _ -> - {:ok, user} = - %User{} - |> cast(%{}, [:ap_id, :nickname, :local]) - |> put_change(:ap_id, uri) - |> put_change(:nickname, nickname) - |> put_change(:local, true) - |> put_change(:follower_address, uri <> "/followers") - |> Repo.insert() + with user when is_nil(user) <- get_cached_by_ap_id(uri) do + {:ok, user} = + %User{ + invisible: true, + local: true, + ap_id: uri, + nickname: nickname, + follower_address: uri <> "/followers" + } + |> Repo.insert() - user + user end end diff --git a/lib/pleroma/web/activity_pub/relay.ex b/lib/pleroma/web/activity_pub/relay.ex index fc2619680..99a804568 100644 --- a/lib/pleroma/web/activity_pub/relay.ex +++ b/lib/pleroma/web/activity_pub/relay.ex @@ -14,7 +14,6 @@ defmodule Pleroma.Web.ActivityPub.Relay do relay_ap_id() |> User.get_or_create_service_actor_by_ap_id() - {:ok, actor} = User.set_invisible(actor, true) actor end diff --git a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex index 73fad519e..8f5b91f04 100644 --- a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex @@ -238,7 +238,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do @doc "GET /api/v1/accounts/:id" def show(%{assigns: %{user: for_user}} = conn, %{"id" => nickname_or_id}) do with %User{} = user <- User.get_cached_by_nickname_or_id(nickname_or_id, for: for_user), - true <- User.auth_active?(user) || user.id == for_user.id || User.superuser?(for_user) do + true <- User.visible_for?(user, for_user) do render(conn, "show.json", user: user, for: for_user) else _e -> render_error(conn, :not_found, "Can't find user") -- cgit v1.2.3 From 62bc0657e7ad78a708c1bb6a82eb98aa1f01e819 Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Tue, 5 Nov 2019 08:55:41 +0300 Subject: excluded invisible users from search results --- lib/pleroma/user/search.ex | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/user/search.ex b/lib/pleroma/user/search.ex index 09664db76..b1bb9d4da 100644 --- a/lib/pleroma/user/search.ex +++ b/lib/pleroma/user/search.ex @@ -45,6 +45,7 @@ defmodule Pleroma.User.Search do for_user |> base_query(following) |> filter_blocked_user(for_user) + |> filter_invisible_users() |> filter_blocked_domains(for_user) |> fts_search(query_string) |> trigram_rank(query_string) @@ -98,6 +99,10 @@ defmodule Pleroma.User.Search do defp base_query(_user, false), do: User defp base_query(user, true), do: User.get_followers_query(user) + defp filter_invisible_users(query) do + from(q in query, where: q.invisible == false) + end + defp filter_blocked_user(query, %User{blocks: blocks}) when length(blocks) > 0 do from(q in query, where: not (q.ap_id in ^blocks)) -- cgit v1.2.3 From e52955c961a225618f00f8f0fc0e7dcbf5a51e23 Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Tue, 5 Nov 2019 10:50:03 +0300 Subject: update following_relationship.ex --- lib/pleroma/following_relationship.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/following_relationship.ex b/lib/pleroma/following_relationship.ex index 2ffac17ee..3aff9fb76 100644 --- a/lib/pleroma/following_relationship.ex +++ b/lib/pleroma/following_relationship.ex @@ -101,7 +101,7 @@ defmodule Pleroma.FollowingRelationship do |> select([r, u], u.follower_address) |> Repo.all() - if not user.local or user.nickname in [nil, "internal.fetch"] do + if not user.local or user.invisible do following else [user.follower_address | following] -- cgit v1.2.3 From e1fc6cb78f07653300965d212d9c5ece9f5c3de0 Mon Sep 17 00:00:00 2001 From: AkiraFukushima Date: Tue, 5 Nov 2019 23:52:47 +0900 Subject: Check client and token in GET /oauth/authorize --- lib/pleroma/web/oauth/oauth_controller.ex | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex index fe71aca8c..6fba9f968 100644 --- a/lib/pleroma/web/oauth/oauth_controller.ex +++ b/lib/pleroma/web/oauth/oauth_controller.ex @@ -36,7 +36,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do authorize(conn, Map.merge(params, auth_attrs)) end - def authorize(%Plug.Conn{assigns: %{token: %Token{}}} = conn, params) do + def authorize(%Plug.Conn{assigns: %{token: %Token{}}} = conn, %{"force_login" => _} = params) do if ControllerHelper.truthy_param?(params["force_login"]) do do_authorize(conn, params) else @@ -44,6 +44,22 @@ defmodule Pleroma.Web.OAuth.OAuthController do end end + # Note: the token is set in oauth_plug, but the token and client do not always go together. + # For example, MastodonFE's token is set if user requests with another client, + # after user already authorized to MastodonFE. + # So we have to check client and token. + def authorize( + %Plug.Conn{assigns: %{token: %Token{} = token}} = conn, + %{"client_id" => client_id} = params + ) do + with %Token{} = t <- Repo.get_by(Token, token: token.token) |> Repo.preload(:app), + ^client_id <- t.app.client_id do + handle_existing_authorization(conn, params) + else + _ -> do_authorize(conn, params) + end + end + def authorize(%Plug.Conn{} = conn, params), do: do_authorize(conn, params) defp do_authorize(%Plug.Conn{} = conn, params) do -- cgit v1.2.3 From 54746c6c26dcbb377e651e196d41f2d7dd87f233 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Wed, 6 Nov 2019 14:00:03 +0300 Subject: Object Fetcher: set cache after reinjecting Probably fixes the issue hj had, where polls would have different counters between endpoints. --- lib/pleroma/object/fetcher.ex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/object/fetcher.ex b/lib/pleroma/object/fetcher.ex index 441ae8b65..3bcbd3aea 100644 --- a/lib/pleroma/object/fetcher.ex +++ b/lib/pleroma/object/fetcher.ex @@ -38,7 +38,8 @@ defmodule Pleroma.Object.Fetcher do data <- maybe_reinject_internal_fields(data, struct), changeset <- Object.change(struct, %{data: data}), changeset <- touch_changeset(changeset), - {:ok, object} <- Repo.insert_or_update(changeset) do + {:ok, object} <- Repo.insert_or_update(changeset), + {:ok, object} <- Object.set_cache(object) do {:ok, object} else e -> -- cgit v1.2.3 From f171095960d172d54015b28e8da302b5745dca86 Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Wed, 6 Nov 2019 21:25:46 +1000 Subject: Grouped reports with status data baked in --- lib/pleroma/web/activity_pub/utils.ex | 58 +++++++++++--------------- lib/pleroma/web/admin_api/views/report_view.ex | 4 +- 2 files changed, 27 insertions(+), 35 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index 57349e304..5a51b7884 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -6,7 +6,6 @@ defmodule Pleroma.Web.ActivityPub.Utils do alias Ecto.Changeset alias Ecto.UUID alias Pleroma.Activity - alias Pleroma.Activity.Queries alias Pleroma.Notification alias Pleroma.Object alias Pleroma.Repo @@ -697,8 +696,8 @@ defmodule Pleroma.Web.ActivityPub.Utils do required(:groups) => [ %{ required(:date) => String.t(), - required(:account) => %User{}, - required(:status) => %Activity{}, + required(:account) => %{}, + required(:status) => %{}, required(:actors) => [%User{}], required(:reports) => [%Activity{}] } @@ -706,32 +705,23 @@ defmodule Pleroma.Web.ActivityPub.Utils do required(:total) => integer } def get_reports_grouped_by_status do - paginated_activities = get_reported_status_ids() - groups = - paginated_activities + get_reported_status_ids() |> Enum.map(fn entry -> - status = - Activity - |> Queries.by_ap_id(entry[:activity_id]) - |> Activity.with_preloaded_object(:left) - |> Activity.with_preloaded_user_actor() - |> Repo.one() - - reports = get_reports_by_status_id(status.data["id"]) - - max_date = - Enum.max_by(reports, &Pleroma.Web.CommonAPI.Utils.to_masto_date(&1.data["published"])).data[ - "published" - ] - + activity = Jason.decode!(entry.activity) + reports = get_reports_by_status_id(activity["id"]) + max_date = Enum.max_by(reports, &NaiveDateTime.from_iso8601!(&1.data["published"])) actors = Enum.map(reports, & &1.user_actor) %{ - date: max_date, - account: status.user_actor, - status: status, - actors: actors, + date: max_date.data["published"], + account: activity["actor"], + status: %{ + id: activity["id"], + content: activity["content"], + published: activity["published"] + }, + actors: Enum.uniq(actors), reports: reports } end) @@ -741,28 +731,30 @@ defmodule Pleroma.Web.ActivityPub.Utils do } end - def get_reports_by_status_id(status_id) do + def get_reports_by_status_id(ap_id) do from(a in Activity, where: fragment("(?)->>'type' = 'Flag'", a.data), - where: fragment("(?)->'object' \\? (?)", a.data, ^status_id) + where: fragment("(?)->'object' @> ?", a.data, ^[%{id: ap_id}]) ) |> Activity.with_preloaded_user_actor() |> Repo.all() end - @spec get_reported_status_ids() :: %{ - required(:items) => [%Activity{}], - required(:total) => integer - } + @spec get_reported_status_ids() :: [ + %{ + required(:activity) => String.t(), + required(:date) => String.t() + } + ] def get_reported_status_ids do from(a in Activity, where: fragment("(?)->>'type' = 'Flag'", a.data), select: %{ date: fragment("max(?->>'published') date", a.data), - activity_id: - fragment("jsonb_array_elements_text((? #- '{object,0}')->'object') activity_id", a.data) + activity: + fragment("jsonb_array_elements_text((? #- '{object,0}')->'object') activity", a.data) }, - group_by: fragment("activity_id"), + group_by: fragment("activity"), order_by: fragment("date DESC") ) |> Repo.all() diff --git a/lib/pleroma/web/admin_api/views/report_view.ex b/lib/pleroma/web/admin_api/views/report_view.ex index ac25925da..ca88595c7 100644 --- a/lib/pleroma/web/admin_api/views/report_view.ex +++ b/lib/pleroma/web/admin_api/views/report_view.ex @@ -47,8 +47,8 @@ defmodule Pleroma.Web.AdminAPI.ReportView do Enum.map(groups, fn group -> %{ date: group[:date], - account: merge_account_views(group[:account]), - status: StatusView.render("show.json", %{activity: group[:status]}), + account: group[:account], + status: group[:status], actors: Enum.map(group[:actors], &merge_account_views/1), reports: group[:reports] -- cgit v1.2.3 From 84175fe30e3661cafe6d5a0a5c7243a60b7d0ff0 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Wed, 6 Nov 2019 16:41:19 +0300 Subject: Set better Cache-Control header for static content Closes #1382 --- lib/pleroma/web/endpoint.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/endpoint.ex b/lib/pleroma/web/endpoint.ex index 2212e93f4..49735b5c2 100644 --- a/lib/pleroma/web/endpoint.ex +++ b/lib/pleroma/web/endpoint.ex @@ -12,7 +12,7 @@ defmodule Pleroma.Web.Endpoint do plug(Pleroma.Plugs.HTTPSecurityPlug) plug(Pleroma.Plugs.UploadedMedia) - @static_cache_control "public, no-cache" + @static_cache_control "public max-age=86400 must-revalidate" # InstanceStatic needs to be before Plug.Static to be able to override shipped-static files # If you're adding new paths to `only:` you'll need to configure them in InstanceStatic as well -- cgit v1.2.3 From 365657320c27d3fc379cf742d1339dd7871255dd Mon Sep 17 00:00:00 2001 From: rinpatch Date: Wed, 6 Nov 2019 17:22:23 +0300 Subject: Fix TrailingFormatPlug not being active for /api/oauth_tokens --- lib/pleroma/plugs/trailing_format_plug.ex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/plugs/trailing_format_plug.ex b/lib/pleroma/plugs/trailing_format_plug.ex index ce366b218..a4b8a406d 100644 --- a/lib/pleroma/plugs/trailing_format_plug.ex +++ b/lib/pleroma/plugs/trailing_format_plug.ex @@ -24,7 +24,8 @@ defmodule Pleroma.Plugs.TrailingFormatPlug do "/api/help", "/api/externalprofile", "/notice", - "/api/pleroma/emoji" + "/api/pleroma/emoji", + "/api/oauth_tokens" ] def init(opts) do -- cgit v1.2.3 From 32afa07995997d6ac8e0bbc7a16bfea8f3eeeed4 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Thu, 7 Nov 2019 01:40:55 +0300 Subject: Fetcher: fix local check returning unwrapped object This resulted in error messages about failed refetches being logged. --- lib/pleroma/object/fetcher.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/object/fetcher.ex b/lib/pleroma/object/fetcher.ex index 3bcbd3aea..9a9a46550 100644 --- a/lib/pleroma/object/fetcher.ex +++ b/lib/pleroma/object/fetcher.ex @@ -54,7 +54,7 @@ defmodule Pleroma.Object.Fetcher do {:ok, object} <- reinject_object(object, data) do {:ok, object} else - {:local, true} -> object + {:local, true} -> {:ok, object} e -> {:error, e} end end -- cgit v1.2.3 From 7888803ffed428438ed107d35a856647a46b347d Mon Sep 17 00:00:00 2001 From: eugenijm Date: Thu, 7 Nov 2019 03:00:21 +0300 Subject: Mastodon API: Add the `recipients` parameter to `GET /api/v1/conversations` --- lib/pleroma/conversation/participation.ex | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/conversation/participation.ex b/lib/pleroma/conversation/participation.ex index 176b82a20..aafe57280 100644 --- a/lib/pleroma/conversation/participation.ex +++ b/lib/pleroma/conversation/participation.ex @@ -122,9 +122,37 @@ defmodule Pleroma.Conversation.Participation do order_by: [desc: p.updated_at], preload: [conversation: [:users]] ) + |> restrict_recipients(user, params) |> Pleroma.Pagination.fetch_paginated(params) end + def restrict_recipients(query, user, %{"recipients" => user_ids}) do + user_ids = + [user.id | user_ids] + |> Enum.uniq() + |> Enum.reduce([], fn user_id, acc -> + case FlakeId.Ecto.CompatType.dump(user_id) do + {:ok, user_id} -> [user_id | acc] + _ -> acc + end + end) + + conversation_subquery = + __MODULE__ + |> group_by([p], p.conversation_id) + |> having( + [p], + count(p.user_id) == ^length(user_ids) and + fragment("array_agg(?) @> ?", p.user_id, ^user_ids) + ) + |> select([p], %{id: p.conversation_id}) + + query + |> join(:inner, [p], c in subquery(conversation_subquery), on: p.conversation_id == c.id) + end + + def restrict_recipients(query, _, _), do: query + def for_user_and_conversation(user, conversation) do from(p in __MODULE__, where: p.user_id == ^user.id, -- cgit v1.2.3 From 7258db023e88d5aee5eac06525c42dcb073abd46 Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Thu, 7 Nov 2019 22:45:36 +1000 Subject: Support old flag format --- lib/pleroma/web/activity_pub/utils.ex | 94 +++++++++++++---------- lib/pleroma/web/admin_api/admin_api_controller.ex | 4 +- 2 files changed, 57 insertions(+), 41 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index 5a51b7884..5e7f76bb6 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -616,26 +616,31 @@ defmodule Pleroma.Web.ActivityPub.Utils do def make_flag_data(_, _), do: %{} defp build_flag_object(%{account: account, statuses: statuses} = _) do - [account.ap_id] ++ - Enum.map(statuses || [], fn act -> - id = - case act do - %Activity{} = act -> act.data["id"] - act when is_map(act) -> act["id"] - act when is_binary(act) -> act - end + [account.ap_id] ++ build_flag_object(%{statuses: statuses}) + end - activity = Activity.get_by_ap_id_with_object(id) - actor = User.get_by_ap_id(activity.object.data["actor"]) + defp build_flag_object(%{statuses: statuses}) do + Enum.map(statuses || [], &build_flag_object/1) + end - %{ - "type" => "Note", - "id" => activity.data["id"], - "content" => activity.object.data["content"], - "published" => activity.object.data["published"], - "actor" => AccountView.render("show.json", %{user: actor}) - } - end) + defp build_flag_object(act) when is_map(act) or is_binary(act) do + id = + case act do + %Activity{} = act -> act.data["id"] + act when is_map(act) -> act["id"] + act when is_binary(act) -> act + end + + activity = Activity.get_by_ap_id_with_object(id) + actor = User.get_by_ap_id(activity.object.data["actor"]) + + %{ + "type" => "Note", + "id" => activity.data["id"], + "content" => activity.object.data["content"], + "published" => activity.object.data["published"], + "actor" => AccountView.render("show.json", %{user: actor}) + } end defp build_flag_object(_), do: [] @@ -692,7 +697,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do ActivityPub.fetch_activities([], params, :offset) end - @spec get_reports_grouped_by_status() :: %{ + @spec get_reports_grouped_by_status(%{required(:activity) => String.t()}) :: %{ required(:groups) => [ %{ required(:date) => String.t(), @@ -704,30 +709,39 @@ defmodule Pleroma.Web.ActivityPub.Utils do ], required(:total) => integer } - def get_reports_grouped_by_status do - groups = - get_reported_status_ids() + def get_reports_grouped_by_status(groups) do + parsed_groups = + groups |> Enum.map(fn entry -> - activity = Jason.decode!(entry.activity) - reports = get_reports_by_status_id(activity["id"]) - max_date = Enum.max_by(reports, &NaiveDateTime.from_iso8601!(&1.data["published"])) - actors = Enum.map(reports, & &1.user_actor) + activity = + case Jason.decode(entry.activity) do + {:ok, activity} -> activity + _ -> build_flag_object(entry.activity) + end - %{ - date: max_date.data["published"], - account: activity["actor"], - status: %{ - id: activity["id"], - content: activity["content"], - published: activity["published"] - }, - actors: Enum.uniq(actors), - reports: reports - } + parse_report_group(activity) end) %{ - groups: groups + groups: parsed_groups + } + end + + def parse_report_group(activity) do + reports = get_reports_by_status_id(activity["id"]) + max_date = Enum.max_by(reports, &NaiveDateTime.from_iso8601!(&1.data["published"])) + actors = Enum.map(reports, & &1.user_actor) + + %{ + date: max_date.data["published"], + account: activity["actor"], + status: %{ + id: activity["id"], + content: activity["content"], + published: activity["published"] + }, + actors: Enum.uniq(actors), + reports: reports } end @@ -740,13 +754,13 @@ defmodule Pleroma.Web.ActivityPub.Utils do |> Repo.all() end - @spec get_reported_status_ids() :: [ + @spec get_reported_activities() :: [ %{ required(:activity) => String.t(), required(:date) => String.t() } ] - def get_reported_status_ids do + def get_reported_activities do from(a in Activity, where: fragment("(?)->>'type' = 'Flag'", a.data), select: %{ diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index 1f48ce8c1..7d5ff7629 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -625,9 +625,11 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do end def list_grouped_reports(conn, _params) do + reports = Utils.get_reported_activities() + conn |> put_view(ReportView) - |> render("index_grouped.json", Utils.get_reports_grouped_by_status()) + |> render("index_grouped.json", Utils.get_reports_grouped_by_status(reports)) end def report_show(conn, %{"id" => id}) do -- cgit v1.2.3 From 532fd38b123b94e6a60387bd8c8409e50913e81a Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Fri, 8 Nov 2019 12:48:28 -0600 Subject: nodeinfo: add multifetch feature (ref pleroma-fe!977). --- lib/pleroma/web/nodeinfo/nodeinfo_controller.ex | 1 + 1 file changed, 1 insertion(+) (limited to 'lib') diff --git a/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex b/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex index 192984242..d7ae503f6 100644 --- a/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex +++ b/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex @@ -58,6 +58,7 @@ defmodule Pleroma.Web.Nodeinfo.NodeinfoController do "polls", "pleroma_explicit_addressing", "shareable_emoji_packs", + "multifetch", if Config.get([:media_proxy, :enabled]) do "media_proxy" end, -- cgit v1.2.3 From 5b60d82592e3fd19646add354de4cde903abf38c Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Fri, 8 Nov 2019 14:51:28 -0600 Subject: object containment: handle all cases where ID is invalid (missing, nil, non-string) --- lib/pleroma/object/containment.ex | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/object/containment.ex b/lib/pleroma/object/containment.ex index 68535c09e..a1f9c1250 100644 --- a/lib/pleroma/object/containment.ex +++ b/lib/pleroma/object/containment.ex @@ -64,15 +64,15 @@ defmodule Pleroma.Object.Containment do def contain_origin(id, %{"attributedTo" => actor} = params), do: contain_origin(id, Map.put(params, "actor", actor)) - def contain_origin_from_id(_id, %{"id" => nil}), do: :error - - def contain_origin_from_id(id, %{"id" => other_id} = _params) do + def contain_origin_from_id(id, %{"id" => other_id} = _params) when is_binary(other_id) do id_uri = URI.parse(id) other_uri = URI.parse(other_id) compare_uris(id_uri, other_uri) end + def contain_origin_from_id(_id, _data), do: :error + def contain_child(%{"object" => %{"id" => id, "attributedTo" => _} = object}), do: contain_origin(id, object) -- cgit v1.2.3 From a4d3a8ec03ec10bb7a9ba3c3e69d9ddc559ed2a0 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Sat, 2 Mar 2019 14:17:55 +0000 Subject: static fe: proof of concept --- lib/pleroma/web/static_fe/static_fe_controller.ex | 42 ++++++ lib/pleroma/web/static_fe/static_fe_view.ex | 19 +++ .../web/templates/layout/static_fe.html.eex | 150 +++++++++++++++++++++ .../templates/static_fe/static_fe/notice.html.eex | 6 + .../static_fe/static_fe/user_card.html.eex | 11 ++ 5 files changed, 228 insertions(+) create mode 100644 lib/pleroma/web/static_fe/static_fe_controller.ex create mode 100644 lib/pleroma/web/static_fe/static_fe_view.ex create mode 100644 lib/pleroma/web/templates/layout/static_fe.html.eex create mode 100644 lib/pleroma/web/templates/static_fe/static_fe/notice.html.eex create mode 100644 lib/pleroma/web/templates/static_fe/static_fe/user_card.html.eex (limited to 'lib') diff --git a/lib/pleroma/web/static_fe/static_fe_controller.ex b/lib/pleroma/web/static_fe/static_fe_controller.ex new file mode 100644 index 000000000..067af9816 --- /dev/null +++ b/lib/pleroma/web/static_fe/static_fe_controller.ex @@ -0,0 +1,42 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.StaticFE.StaticFEController do + use Pleroma.Web, :controller + + alias Pleroma.Repo + alias Pleroma.Activity + alias Pleroma.Object + alias Pleroma.User + alias Pleroma.Web.ActivityPub.Visibility + + require Logger + + def show_notice(conn, %{"notice_id" => notice_id}) do + with %Activity{} = activity <- Repo.get(Activity, notice_id), + true <- Visibility.is_public?(activity), + %User{} = user <- User.get_or_fetch(activity.data["actor"]), + %Object{} = object <- Object.normalize(activity.data["object"]) do + conn + |> put_layout(:static_fe) + |> put_status(200) + |> put_view(Pleroma.Web.StaticFE.StaticFEView) + |> render("notice.html", %{notice: activity, object: object, user: user}) + else + _ -> + conn + |> put_status(404) + |> text("Not found") + end + end + + def show(%{path_info: ["notice", notice_id]} = conn, _params), do: show_notice(conn, %{"notice_id" => notice_id}) + + # Fallback for unhandled types + def show(conn, _params) do + conn + |> put_status(404) + |> text("Not found") + end +end diff --git a/lib/pleroma/web/static_fe/static_fe_view.ex b/lib/pleroma/web/static_fe/static_fe_view.ex new file mode 100644 index 000000000..7f58e1b2d --- /dev/null +++ b/lib/pleroma/web/static_fe/static_fe_view.ex @@ -0,0 +1,19 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.StaticFE.StaticFEView do + use Pleroma.Web, :view + + alias Pleroma.User + alias Pleroma.Web.MediaProxy + alias Pleroma.Formatter + + def emoji_for_user(%User{} = user) do + (user.info.source_data["tag"] || []) + |> Enum.filter(fn %{"type" => t} -> t == "Emoji" end) + |> Enum.map(fn %{"icon" => %{"url" => url}, "name" => name} -> + {String.trim(name, ":"), url} + end) + end +end diff --git a/lib/pleroma/web/templates/layout/static_fe.html.eex b/lib/pleroma/web/templates/layout/static_fe.html.eex new file mode 100644 index 000000000..c20958162 --- /dev/null +++ b/lib/pleroma/web/templates/layout/static_fe.html.eex @@ -0,0 +1,150 @@ + + + + + + + <%= Application.get_env(:pleroma, :instance)[:name] %> + + + + +
+ <%= render @view_module, @view_template, assigns %> +
+ + diff --git a/lib/pleroma/web/templates/static_fe/static_fe/notice.html.eex b/lib/pleroma/web/templates/static_fe/static_fe/notice.html.eex new file mode 100644 index 000000000..9957697ad --- /dev/null +++ b/lib/pleroma/web/templates/static_fe/static_fe/notice.html.eex @@ -0,0 +1,6 @@ +
+ <%= render("user_card.html", %{user: @user}) %> +
+
<%= @object.data["content"] %>
+
+
diff --git a/lib/pleroma/web/templates/static_fe/static_fe/user_card.html.eex b/lib/pleroma/web/templates/static_fe/static_fe/user_card.html.eex new file mode 100644 index 000000000..8b397c639 --- /dev/null +++ b/lib/pleroma/web/templates/static_fe/static_fe/user_card.html.eex @@ -0,0 +1,11 @@ + -- cgit v1.2.3 From ff8d0902f351f871ab34ae7b127dd3e02e8af4cd Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Sat, 2 Mar 2019 14:23:26 +0000 Subject: static fe: formatting --- lib/pleroma/web/static_fe/static_fe_controller.ex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/static_fe/static_fe_controller.ex b/lib/pleroma/web/static_fe/static_fe_controller.ex index 067af9816..2ac857759 100644 --- a/lib/pleroma/web/static_fe/static_fe_controller.ex +++ b/lib/pleroma/web/static_fe/static_fe_controller.ex @@ -31,7 +31,8 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do end end - def show(%{path_info: ["notice", notice_id]} = conn, _params), do: show_notice(conn, %{"notice_id" => notice_id}) + def show(%{path_info: ["notice", notice_id]} = conn, _params), + do: show_notice(conn, %{"notice_id" => notice_id}) # Fallback for unhandled types def show(conn, _params) do -- cgit v1.2.3 From 8f08da750aaa8e04c4a940a566ec831a559a4852 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Sat, 2 Mar 2019 20:10:30 +0000 Subject: static fe: use a generic activity representer to render activities --- lib/pleroma/web/static_fe/activity_representer.ex | 52 +++++++++++++++++++++++ lib/pleroma/web/static_fe/static_fe_controller.ex | 13 ++---- 2 files changed, 55 insertions(+), 10 deletions(-) create mode 100644 lib/pleroma/web/static_fe/activity_representer.ex (limited to 'lib') diff --git a/lib/pleroma/web/static_fe/activity_representer.ex b/lib/pleroma/web/static_fe/activity_representer.ex new file mode 100644 index 000000000..93f8a8813 --- /dev/null +++ b/lib/pleroma/web/static_fe/activity_representer.ex @@ -0,0 +1,52 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.StaticFE.ActivityRepresenter do + alias Pleroma.Activity + alias Pleroma.Object + alias Pleroma.User + alias Pleroma.Web.ActivityPub.Visibility + + def prepare_activity(%User{} = user, %Object{} = object) do + %{} + |> set_user(user) + |> set_object(object) + |> set_title(object) + |> set_content(object) + |> set_attachments(object) + end + + defp set_user(data, %User{} = user), do: Map.put(data, :user, user) + + defp set_object(data, %Object{} = object), do: Map.put(data, :object, object) + + defp set_title(data, %Object{data: %{"name" => name}}) when is_binary(name), + do: Map.put(data, :title, name) + + defp set_title(data, %Object{data: %{"summary" => summary}}) when is_binary(summary), + do: Map.put(data, :title, summary) + + defp set_title(data, _), do: Map.put(data, :title, nil) + + defp set_content(data, %Object{data: %{"content" => content}}) when is_binary(content), + do: Map.put(data, :content, content) + + defp set_content(data, _), do: Map.put(data, :content, nil) + + # TODO: attachments + defp set_attachments(data, _), do: Map.put(data, :attachments, []) + + def represent(activity_id) do + with %Activity{data: %{"type" => "Create"}} = activity <- Activity.get_by_id(activity_id), + true <- Visibility.is_public?(activity), + %Object{} = object <- Object.normalize(activity.data["object"]), + %User{} = user <- User.get_or_fetch(activity.data["actor"]), + data <- prepare_activity(user, object) do + {:ok, data} + else + e -> + {:error, e} + end + end +end diff --git a/lib/pleroma/web/static_fe/static_fe_controller.ex b/lib/pleroma/web/static_fe/static_fe_controller.ex index 2ac857759..7d7cb6ddd 100644 --- a/lib/pleroma/web/static_fe/static_fe_controller.ex +++ b/lib/pleroma/web/static_fe/static_fe_controller.ex @@ -5,24 +5,17 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do use Pleroma.Web, :controller - alias Pleroma.Repo - alias Pleroma.Activity - alias Pleroma.Object - alias Pleroma.User - alias Pleroma.Web.ActivityPub.Visibility + alias Pleroma.Web.StaticFE.ActivityRepresenter require Logger def show_notice(conn, %{"notice_id" => notice_id}) do - with %Activity{} = activity <- Repo.get(Activity, notice_id), - true <- Visibility.is_public?(activity), - %User{} = user <- User.get_or_fetch(activity.data["actor"]), - %Object{} = object <- Object.normalize(activity.data["object"]) do + with {:ok, data} <- ActivityRepresenter.represent(notice_id) do conn |> put_layout(:static_fe) |> put_status(200) |> put_view(Pleroma.Web.StaticFE.StaticFEView) - |> render("notice.html", %{notice: activity, object: object, user: user}) + |> render("notice.html", data) else _ -> conn -- cgit v1.2.3 From 2b5bd5236d793edba54366ec9fed447207a09976 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Sat, 2 Mar 2019 21:12:38 +0000 Subject: static fe: add user profile rendering --- lib/pleroma/web/static_fe/activity_representer.ex | 3 ++ lib/pleroma/web/static_fe/static_fe_controller.ex | 24 ++++++++++++++- lib/pleroma/web/static_fe/static_fe_view.ex | 2 ++ lib/pleroma/web/static_fe/user_representer.ex | 35 ++++++++++++++++++++++ .../web/templates/layout/static_fe.html.eex | 4 +++ .../templates/static_fe/static_fe/notice.html.eex | 4 +-- .../templates/static_fe/static_fe/profile.html.eex | 7 +++++ .../static_fe/static_fe/user_card.html.eex | 2 +- 8 files changed, 77 insertions(+), 4 deletions(-) create mode 100644 lib/pleroma/web/static_fe/user_representer.ex create mode 100644 lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex (limited to 'lib') diff --git a/lib/pleroma/web/static_fe/activity_representer.ex b/lib/pleroma/web/static_fe/activity_representer.ex index 93f8a8813..9c4315610 100644 --- a/lib/pleroma/web/static_fe/activity_representer.ex +++ b/lib/pleroma/web/static_fe/activity_representer.ex @@ -17,6 +17,9 @@ defmodule Pleroma.Web.StaticFE.ActivityRepresenter do |> set_attachments(object) end + def prepare_activity(%User{} = user, %Activity{} = activity), do: + prepare_activity(user, Object.normalize(activity.data["object"])) + defp set_user(data, %User{} = user), do: Map.put(data, :user, user) defp set_object(data, %Object{} = object), do: Map.put(data, :object, object) diff --git a/lib/pleroma/web/static_fe/static_fe_controller.ex b/lib/pleroma/web/static_fe/static_fe_controller.ex index 7d7cb6ddd..78cd325c8 100644 --- a/lib/pleroma/web/static_fe/static_fe_controller.ex +++ b/lib/pleroma/web/static_fe/static_fe_controller.ex @@ -6,6 +6,7 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do use Pleroma.Web, :controller alias Pleroma.Web.StaticFE.ActivityRepresenter + alias Pleroma.Web.StaticFE.UserRepresenter require Logger @@ -15,7 +16,22 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do |> put_layout(:static_fe) |> put_status(200) |> put_view(Pleroma.Web.StaticFE.StaticFEView) - |> render("notice.html", data) + |> render("notice.html", %{data: data}) + else + _ -> + conn + |> put_status(404) + |> text("Not found") + end + end + + def show_user(conn, %{"username_or_id" => username_or_id}) do + with {:ok, data} <- UserRepresenter.represent(username_or_id) do + conn + |> put_layout(:static_fe) + |> put_status(200) + |> put_view(Pleroma.Web.StaticFE.StaticFEView) + |> render("profile.html", %{data: data}) else _ -> conn @@ -27,6 +43,12 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do def show(%{path_info: ["notice", notice_id]} = conn, _params), do: show_notice(conn, %{"notice_id" => notice_id}) + def show(%{path_info: ["users", user_id]} = conn, _params), + do: show_user(conn, %{"username_or_id" => user_id}) + + def show(%{path_info: [user_id]} = conn, _params), + do: show_user(conn, %{"username_or_id" => user_id}) + # Fallback for unhandled types def show(conn, _params) do conn diff --git a/lib/pleroma/web/static_fe/static_fe_view.ex b/lib/pleroma/web/static_fe/static_fe_view.ex index 7f58e1b2d..71e47d2c1 100644 --- a/lib/pleroma/web/static_fe/static_fe_view.ex +++ b/lib/pleroma/web/static_fe/static_fe_view.ex @@ -9,6 +9,8 @@ defmodule Pleroma.Web.StaticFE.StaticFEView do alias Pleroma.Web.MediaProxy alias Pleroma.Formatter + import Phoenix.HTML + def emoji_for_user(%User{} = user) do (user.info.source_data["tag"] || []) |> Enum.filter(fn %{"type" => t} -> t == "Emoji" end) diff --git a/lib/pleroma/web/static_fe/user_representer.ex b/lib/pleroma/web/static_fe/user_representer.ex new file mode 100644 index 000000000..9d2f1eb85 --- /dev/null +++ b/lib/pleroma/web/static_fe/user_representer.ex @@ -0,0 +1,35 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.StaticFE.UserRepresenter do + alias Pleroma.User + alias Pleroma.Web.ActivityPub.ActivityPub + alias Pleroma.Web.StaticFE.ActivityRepresenter + + def prepare_user(%User{} = user) do + %{} + |> set_user(user) + |> set_timeline(user) + end + + defp set_user(data, %User{} = user), do: Map.put(data, :user, user) + + defp set_timeline(data, %User{} = user) do + activities = + ActivityPub.fetch_user_activities(user, nil, %{}) + |> Enum.map(fn activity -> ActivityRepresenter.prepare_activity(user, activity) end) + + Map.put(data, :timeline, activities) + end + + def represent(username_or_id) do + with %User{} = user <- User.get_cached_by_nickname_or_id(username_or_id), + data <- prepare_user(user) do + {:ok, data} + else + e -> + {:error, e} + end + end +end diff --git a/lib/pleroma/web/templates/layout/static_fe.html.eex b/lib/pleroma/web/templates/layout/static_fe.html.eex index c20958162..40a560460 100644 --- a/lib/pleroma/web/templates/layout/static_fe.html.eex +++ b/lib/pleroma/web/templates/layout/static_fe.html.eex @@ -22,6 +22,10 @@ border-radius: 4px; } + .activity { + margin-bottom: 1em; + } + .avatar { cursor: pointer; } diff --git a/lib/pleroma/web/templates/static_fe/static_fe/notice.html.eex b/lib/pleroma/web/templates/static_fe/static_fe/notice.html.eex index 9957697ad..e8d905d79 100644 --- a/lib/pleroma/web/templates/static_fe/static_fe/notice.html.eex +++ b/lib/pleroma/web/templates/static_fe/static_fe/notice.html.eex @@ -1,6 +1,6 @@
- <%= render("user_card.html", %{user: @user}) %> + <%= render("user_card.html", %{user: @data.user}) %>
-
<%= @object.data["content"] %>
+
<%= raw @data.content %>
diff --git a/lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex b/lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex new file mode 100644 index 000000000..9ae4139ed --- /dev/null +++ b/lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex @@ -0,0 +1,7 @@ +

<%= raw (@data.user.name |> Formatter.emojify(emoji_for_user(@data.user))) %>

+

<%= raw @data.user.bio %>

+
+<%= for activity <- @data.timeline do %> + <%= render("notice.html", %{data: activity}) %> +<% end %> +
diff --git a/lib/pleroma/web/templates/static_fe/static_fe/user_card.html.eex b/lib/pleroma/web/templates/static_fe/static_fe/user_card.html.eex index 8b397c639..c7789f9ac 100644 --- a/lib/pleroma/web/templates/static_fe/static_fe/user_card.html.eex +++ b/lib/pleroma/web/templates/static_fe/static_fe/user_card.html.eex @@ -4,7 +4,7 @@ - <%= @user.name |> Formatter.emojify(emoji_for_user(@user)) %> + <%= raw (@user.name |> Formatter.emojify(emoji_for_user(@user))) %> <%= @user.nickname %> -- cgit v1.2.3 From e2904b5777ecf6c8ffe7fe46f09284bb38b03fc2 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Sat, 2 Mar 2019 21:40:02 +0000 Subject: static fe: reformat activity representer --- lib/pleroma/web/static_fe/activity_representer.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/static_fe/activity_representer.ex b/lib/pleroma/web/static_fe/activity_representer.ex index 9c4315610..446c6023e 100644 --- a/lib/pleroma/web/static_fe/activity_representer.ex +++ b/lib/pleroma/web/static_fe/activity_representer.ex @@ -17,8 +17,8 @@ defmodule Pleroma.Web.StaticFE.ActivityRepresenter do |> set_attachments(object) end - def prepare_activity(%User{} = user, %Activity{} = activity), do: - prepare_activity(user, Object.normalize(activity.data["object"])) + def prepare_activity(%User{} = user, %Activity{} = activity), + do: prepare_activity(user, Object.normalize(activity.data["object"])) defp set_user(data, %User{} = user), do: Map.put(data, :user, user) -- cgit v1.2.3 From b33fbd58e3852fc9de58917fafbb2c575a21dde1 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Sat, 2 Mar 2019 22:35:54 +0000 Subject: static fe: add support for message subjects --- lib/pleroma/web/templates/static_fe/static_fe/notice.html.eex | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/templates/static_fe/static_fe/notice.html.eex b/lib/pleroma/web/templates/static_fe/static_fe/notice.html.eex index e8d905d79..791bd2562 100644 --- a/lib/pleroma/web/templates/static_fe/static_fe/notice.html.eex +++ b/lib/pleroma/web/templates/static_fe/static_fe/notice.html.eex @@ -1,6 +1,13 @@
<%= render("user_card.html", %{user: @data.user}) %>
-
<%= raw @data.content %>
+ <%= if @data.title do %> +
+ <%= raw @data.title %> + <% end %> +
<%= raw @data.content %>
+ <%= if @data.title do %> +
+ <% end %>
-- cgit v1.2.3 From ca5ef201ef8397981acf0647fe5cffea66299bfa Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Sun, 3 Mar 2019 13:36:59 +0000 Subject: static fe: add remote follow button --- lib/pleroma/web/static_fe/static_fe_view.ex | 1 + lib/pleroma/web/templates/layout/static_fe.html.eex | 9 +++++++++ lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex | 9 ++++++++- 3 files changed, 18 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/static_fe/static_fe_view.ex b/lib/pleroma/web/static_fe/static_fe_view.ex index 71e47d2c1..c01e8d40b 100644 --- a/lib/pleroma/web/static_fe/static_fe_view.ex +++ b/lib/pleroma/web/static_fe/static_fe_view.ex @@ -8,6 +8,7 @@ defmodule Pleroma.Web.StaticFE.StaticFEView do alias Pleroma.User alias Pleroma.Web.MediaProxy alias Pleroma.Formatter + alias Pleroma.Web.Router.Helpers import Phoenix.HTML diff --git a/lib/pleroma/web/templates/layout/static_fe.html.eex b/lib/pleroma/web/templates/layout/static_fe.html.eex index 40a560460..7ce9ead90 100644 --- a/lib/pleroma/web/templates/layout/static_fe.html.eex +++ b/lib/pleroma/web/templates/layout/static_fe.html.eex @@ -70,6 +70,15 @@ text-decoration: none; } + .pull-right { + float: right; + } + + .collapse { + margin: 0; + width: auto; + } + h1 { margin: 0; } diff --git a/lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex b/lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex index 9ae4139ed..47b7d5286 100644 --- a/lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex +++ b/lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex @@ -1,4 +1,11 @@ -

<%= raw (@data.user.name |> Formatter.emojify(emoji_for_user(@data.user))) %>

+

+
+ + + +
+ <%= raw (@data.user.name |> Formatter.emojify(emoji_for_user(@data.user))) %> +

<%= raw @data.user.bio %>

<%= for activity <- @data.timeline do %> -- cgit v1.2.3 From d1320160f436c719ecca8b31463dd16a1ab2bdb9 Mon Sep 17 00:00:00 2001 From: Phil Hagelberg Date: Sun, 27 Oct 2019 15:20:43 -0700 Subject: Looks like source_data is on user directly now. --- lib/pleroma/web/static_fe/static_fe_view.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/static_fe/static_fe_view.ex b/lib/pleroma/web/static_fe/static_fe_view.ex index c01e8d40b..ba67de835 100644 --- a/lib/pleroma/web/static_fe/static_fe_view.ex +++ b/lib/pleroma/web/static_fe/static_fe_view.ex @@ -13,7 +13,7 @@ defmodule Pleroma.Web.StaticFE.StaticFEView do import Phoenix.HTML def emoji_for_user(%User{} = user) do - (user.info.source_data["tag"] || []) + (user.source_data["tag"] || []) |> Enum.filter(fn %{"type" => t} -> t == "Emoji" end) |> Enum.map(fn %{"icon" => %{"url" => url}, "name" => name} -> {String.trim(name, ":"), url} -- cgit v1.2.3 From c1fc1399860c57460cee173ce8ddb980aabf10de Mon Sep 17 00:00:00 2001 From: Phil Hagelberg Date: Sun, 27 Oct 2019 16:37:57 -0700 Subject: Add permalinks to the static-fe notice rendering. --- lib/pleroma/web/static_fe/activity_representer.ex | 15 ++++++++++++--- .../web/templates/static_fe/static_fe/notice.html.eex | 6 ++++-- 2 files changed, 16 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/static_fe/activity_representer.ex b/lib/pleroma/web/static_fe/activity_representer.ex index 446c6023e..e383b8415 100644 --- a/lib/pleroma/web/static_fe/activity_representer.ex +++ b/lib/pleroma/web/static_fe/activity_representer.ex @@ -7,18 +7,21 @@ defmodule Pleroma.Web.StaticFE.ActivityRepresenter do alias Pleroma.Object alias Pleroma.User alias Pleroma.Web.ActivityPub.Visibility + alias Pleroma.Web.Router.Helpers - def prepare_activity(%User{} = user, %Object{} = object) do + def prepare_activity(%User{} = user, %Object{} = object, activity_id) do %{} |> set_user(user) |> set_object(object) |> set_title(object) |> set_content(object) + |> set_link(activity_id) + |> set_published(object) |> set_attachments(object) end def prepare_activity(%User{} = user, %Activity{} = activity), - do: prepare_activity(user, Object.normalize(activity.data["object"])) + do: prepare_activity(user, Object.normalize(activity.data["object"]), activity.id) defp set_user(data, %User{} = user), do: Map.put(data, :user, user) @@ -37,6 +40,12 @@ defmodule Pleroma.Web.StaticFE.ActivityRepresenter do defp set_content(data, _), do: Map.put(data, :content, nil) + defp set_link(data, activity_id), + do: Map.put(data, :link, Helpers.o_status_url(Pleroma.Web.Endpoint, :notice, activity_id)) + + defp set_published(data, %Object{data: %{"published" => published}}), + do: Map.put(data, :published, published) + # TODO: attachments defp set_attachments(data, _), do: Map.put(data, :attachments, []) @@ -45,7 +54,7 @@ defmodule Pleroma.Web.StaticFE.ActivityRepresenter do true <- Visibility.is_public?(activity), %Object{} = object <- Object.normalize(activity.data["object"]), %User{} = user <- User.get_or_fetch(activity.data["actor"]), - data <- prepare_activity(user, object) do + data <- prepare_activity(user, object, activity_id) do {:ok, data} else e -> diff --git a/lib/pleroma/web/templates/static_fe/static_fe/notice.html.eex b/lib/pleroma/web/templates/static_fe/static_fe/notice.html.eex index 791bd2562..d305d9057 100644 --- a/lib/pleroma/web/templates/static_fe/static_fe/notice.html.eex +++ b/lib/pleroma/web/templates/static_fe/static_fe/notice.html.eex @@ -1,13 +1,15 @@
<%= render("user_card.html", %{user: @data.user}) %>
- <%= if @data.title do %> + <%= if @data.title != "" do %>
<%= raw @data.title %> <% end %>
<%= raw @data.content %>
- <%= if @data.title do %> + <%= if @data.title != "" do %>
<% end %> +

+ <%= @data.published %>

-- cgit v1.2.3 From e79d8985ab90bcad33d9ff13c6a16f006c6abac9 Mon Sep 17 00:00:00 2001 From: Phil Hagelberg Date: Sun, 27 Oct 2019 17:53:20 -0700 Subject: Don't show 404 in static-fe controller unless it's actually not found. --- lib/pleroma/web/static_fe/static_fe_controller.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/static_fe/static_fe_controller.ex b/lib/pleroma/web/static_fe/static_fe_controller.ex index 78cd325c8..8bbd06aa9 100644 --- a/lib/pleroma/web/static_fe/static_fe_controller.ex +++ b/lib/pleroma/web/static_fe/static_fe_controller.ex @@ -18,7 +18,7 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do |> put_view(Pleroma.Web.StaticFE.StaticFEView) |> render("notice.html", %{data: data}) else - _ -> + {:error, nil} -> conn |> put_status(404) |> text("Not found") @@ -33,7 +33,7 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do |> put_view(Pleroma.Web.StaticFE.StaticFEView) |> render("profile.html", %{data: data}) else - _ -> + {:error, nil} -> conn |> put_status(404) |> text("Not found") -- cgit v1.2.3 From 0cf04e10880fb0779f34102cacb40950a119d4f8 Mon Sep 17 00:00:00 2001 From: Phil Hagelberg Date: Sun, 27 Oct 2019 19:01:18 -0700 Subject: Fix OStatus controller to know about StaticFEController. But only when it's configured to be on. --- lib/pleroma/web/ostatus/ostatus_controller.ex | 64 ++++++++++++++------------- 1 file changed, 34 insertions(+), 30 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/ostatus/ostatus_controller.ex b/lib/pleroma/web/ostatus/ostatus_controller.ex index 6958519de..76a244d0f 100644 --- a/lib/pleroma/web/ostatus/ostatus_controller.ex +++ b/lib/pleroma/web/ostatus/ostatus_controller.ex @@ -76,37 +76,41 @@ defmodule Pleroma.Web.OStatus.OStatusController do end def notice(%{assigns: %{format: format}} = conn, %{"id" => id}) do - with {_, %Activity{} = activity} <- {:activity, Activity.get_by_id_with_object(id)}, - {_, true} <- {:public?, Visibility.is_public?(activity)}, - %User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do - cond do - format == "html" && activity.data["type"] == "Create" -> - %Object{} = object = Object.normalize(activity) - - RedirectController.redirector_with_meta( - conn, - %{ - activity_id: activity.id, - object: object, - url: Router.Helpers.o_status_url(Endpoint, :notice, activity.id), - user: user - } - ) - - format == "html" -> - RedirectController.redirector(conn, nil) - - true -> - represent_activity(conn, format, activity, user) - end + if Pleroma.Config.get([:instance, :static_fe], false) do + Pleroma.Web.StaticFE.StaticFEController.show(conn, %{"notice_id" => id}) else - reason when reason in [{:public?, false}, {:activity, nil}] -> - conn - |> put_status(404) - |> RedirectController.redirector(nil, 404) - - e -> - e + with {_, %Activity{} = activity} <- {:activity, Activity.get_by_id_with_object(id)}, + {_, true} <- {:public?, Visibility.is_public?(activity)}, + %User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do + cond do + format == "html" && activity.data["type"] == "Create" -> + %Object{} = object = Object.normalize(activity) + + RedirectController.redirector_with_meta( + conn, + %{ + activity_id: activity.id, + object: object, + url: Router.Helpers.o_status_url(Endpoint, :notice, activity.id), + user: user + } + ) + + format == "html" -> + RedirectController.redirector(conn, nil) + + true -> + represent_activity(conn, format, activity, user) + end + else + reason when reason in [{:public?, false}, {:activity, nil}] -> + conn + |> put_status(404) + |> RedirectController.redirector(nil, 404) + + e -> + e + end end end -- cgit v1.2.3 From 1d8950798c8aef2cee4458c68d34a72da630ec41 Mon Sep 17 00:00:00 2001 From: Phil Hagelberg Date: Sun, 27 Oct 2019 19:02:19 -0700 Subject: Fix activity_representer to work with User.get_or_fetch returning tuple. --- lib/pleroma/web/ostatus/ostatus_controller.ex | 2 +- lib/pleroma/web/static_fe/activity_representer.ex | 15 ++++++--------- 2 files changed, 7 insertions(+), 10 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/ostatus/ostatus_controller.ex b/lib/pleroma/web/ostatus/ostatus_controller.ex index 76a244d0f..ab5fdbc78 100644 --- a/lib/pleroma/web/ostatus/ostatus_controller.ex +++ b/lib/pleroma/web/ostatus/ostatus_controller.ex @@ -81,7 +81,7 @@ defmodule Pleroma.Web.OStatus.OStatusController do else with {_, %Activity{} = activity} <- {:activity, Activity.get_by_id_with_object(id)}, {_, true} <- {:public?, Visibility.is_public?(activity)}, - %User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do + %User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do cond do format == "html" && activity.data["type"] == "Create" -> %Object{} = object = Object.normalize(activity) diff --git a/lib/pleroma/web/static_fe/activity_representer.ex b/lib/pleroma/web/static_fe/activity_representer.ex index e383b8415..9bee732d5 100644 --- a/lib/pleroma/web/static_fe/activity_representer.ex +++ b/lib/pleroma/web/static_fe/activity_representer.ex @@ -9,20 +9,19 @@ defmodule Pleroma.Web.StaticFE.ActivityRepresenter do alias Pleroma.Web.ActivityPub.Visibility alias Pleroma.Web.Router.Helpers - def prepare_activity(%User{} = user, %Object{} = object, activity_id) do + def prepare_activity(%User{} = user, %Activity{} = activity) do + object = Object.normalize(activity.data["object"]) + %{} |> set_user(user) |> set_object(object) |> set_title(object) |> set_content(object) - |> set_link(activity_id) + |> set_link(activity.id) |> set_published(object) |> set_attachments(object) end - def prepare_activity(%User{} = user, %Activity{} = activity), - do: prepare_activity(user, Object.normalize(activity.data["object"]), activity.id) - defp set_user(data, %User{} = user), do: Map.put(data, :user, user) defp set_object(data, %Object{} = object), do: Map.put(data, :object, object) @@ -52,10 +51,8 @@ defmodule Pleroma.Web.StaticFE.ActivityRepresenter do def represent(activity_id) do with %Activity{data: %{"type" => "Create"}} = activity <- Activity.get_by_id(activity_id), true <- Visibility.is_public?(activity), - %Object{} = object <- Object.normalize(activity.data["object"]), - %User{} = user <- User.get_or_fetch(activity.data["actor"]), - data <- prepare_activity(user, object, activity_id) do - {:ok, data} + {:ok, %User{} = user} <- User.get_or_fetch(activity.data["actor"]) do + {:ok, prepare_activity(user, activity)} else e -> {:error, e} -- cgit v1.2.3 From 748d800acb56cd1e66adf78e5938623b8da7cde1 Mon Sep 17 00:00:00 2001 From: Phil Hagelberg Date: Mon, 28 Oct 2019 19:05:45 -0700 Subject: Show images, video, and audio attachments to notices. --- lib/pleroma/web/static_fe/activity_representer.ex | 10 +++++++- lib/pleroma/web/static_fe/static_fe_view.ex | 7 ++++++ .../web/templates/layout/static_fe.html.eex | 5 ++++ .../static_fe/static_fe/_attachment.html.eex | 8 +++++++ .../templates/static_fe/static_fe/notice.html.eex | 28 ++++++++++++++++------ 5 files changed, 50 insertions(+), 8 deletions(-) create mode 100644 lib/pleroma/web/templates/static_fe/static_fe/_attachment.html.eex (limited to 'lib') diff --git a/lib/pleroma/web/static_fe/activity_representer.ex b/lib/pleroma/web/static_fe/activity_representer.ex index 9bee732d5..7b7e1730c 100644 --- a/lib/pleroma/web/static_fe/activity_representer.ex +++ b/lib/pleroma/web/static_fe/activity_representer.ex @@ -19,6 +19,8 @@ defmodule Pleroma.Web.StaticFE.ActivityRepresenter do |> set_content(object) |> set_link(activity.id) |> set_published(object) + |> set_sensitive(object) + |> set_attachment(object.data["attachment"]) |> set_attachments(object) end @@ -39,17 +41,23 @@ defmodule Pleroma.Web.StaticFE.ActivityRepresenter do defp set_content(data, _), do: Map.put(data, :content, nil) + defp set_attachment(data, attachment), do: Map.put(data, :attachment, attachment) + defp set_link(data, activity_id), do: Map.put(data, :link, Helpers.o_status_url(Pleroma.Web.Endpoint, :notice, activity_id)) defp set_published(data, %Object{data: %{"published" => published}}), do: Map.put(data, :published, published) + defp set_sensitive(data, %Object{data: %{"sensitive" => sensitive}}), + do: Map.put(data, :sensitive, sensitive) + # TODO: attachments defp set_attachments(data, _), do: Map.put(data, :attachments, []) def represent(activity_id) do - with %Activity{data: %{"type" => "Create"}} = activity <- Activity.get_by_id(activity_id), + with %Activity{data: %{"type" => "Create"}} = activity <- + Activity.get_by_id_with_object(activity_id), true <- Visibility.is_public?(activity), {:ok, %User{} = user} <- User.get_or_fetch(activity.data["actor"]) do {:ok, prepare_activity(user, activity)} diff --git a/lib/pleroma/web/static_fe/static_fe_view.ex b/lib/pleroma/web/static_fe/static_fe_view.ex index ba67de835..2b3b968d3 100644 --- a/lib/pleroma/web/static_fe/static_fe_view.ex +++ b/lib/pleroma/web/static_fe/static_fe_view.ex @@ -8,10 +8,13 @@ defmodule Pleroma.Web.StaticFE.StaticFEView do alias Pleroma.User alias Pleroma.Web.MediaProxy alias Pleroma.Formatter + alias Pleroma.Web.Metadata.Utils alias Pleroma.Web.Router.Helpers import Phoenix.HTML + @media_types ["image", "audio", "video"] + def emoji_for_user(%User{} = user) do (user.source_data["tag"] || []) |> Enum.filter(fn %{"type" => t} -> t == "Emoji" end) @@ -19,4 +22,8 @@ defmodule Pleroma.Web.StaticFE.StaticFEView do {String.trim(name, ":"), url} end) end + + def fetch_media_type(url) do + Utils.fetch_media_type(@media_types, url["mediaType"]) + end end diff --git a/lib/pleroma/web/templates/layout/static_fe.html.eex b/lib/pleroma/web/templates/layout/static_fe.html.eex index 7ce9ead90..c1fbd89cd 100644 --- a/lib/pleroma/web/templates/layout/static_fe.html.eex +++ b/lib/pleroma/web/templates/layout/static_fe.html.eex @@ -36,6 +36,11 @@ margin-right: 4px; } + .activity-content img, video { + max-width: 800px; + max-height: 800px; + } + a { color: white; } diff --git a/lib/pleroma/web/templates/static_fe/static_fe/_attachment.html.eex b/lib/pleroma/web/templates/static_fe/static_fe/_attachment.html.eex new file mode 100644 index 000000000..7e04e9550 --- /dev/null +++ b/lib/pleroma/web/templates/static_fe/static_fe/_attachment.html.eex @@ -0,0 +1,8 @@ +<%= case @mediaType do %> +<% "audio" -> %> + +<% "video" -> %> + +<% _ -> %> +<%= @name %> +<% end %> diff --git a/lib/pleroma/web/templates/static_fe/static_fe/notice.html.eex b/lib/pleroma/web/templates/static_fe/static_fe/notice.html.eex index d305d9057..9a7824a32 100644 --- a/lib/pleroma/web/templates/static_fe/static_fe/notice.html.eex +++ b/lib/pleroma/web/templates/static_fe/static_fe/notice.html.eex @@ -1,15 +1,29 @@
<%= render("user_card.html", %{user: @data.user}) %> +

+ <%= @data.published %>

<%= if @data.title != "" do %> -
- <%= raw @data.title %> - <% end %> +
+ <%= raw @data.title %> +
<%= raw @data.content %>
+
+ <% else %>
<%= raw @data.content %>
- <%= if @data.title != "" do %> -
<% end %> -

- <%= @data.published %>

+ <%= for %{"name" => name, "url" => [url | _]} <- @data.attachment do %> + <%= if @data.sensitive do %> +
+ sensitive media +
+ <%= render("_attachment.html", %{name: name, url: url["href"], + mediaType: fetch_media_type(url)}) %> +
+
+ <% else %> + <%= render("_attachment.html", %{name: name, url: url["href"], + mediaType: fetch_media_type(url)}) %> + <% end %> + <% end %>
-- cgit v1.2.3 From cc1b07132f1c532c623530ed2375ff7fbdc6d559 Mon Sep 17 00:00:00 2001 From: Phil Hagelberg Date: Mon, 28 Oct 2019 19:47:20 -0700 Subject: Notices should show entire thread from context. --- lib/pleroma/web/static_fe/static_fe_controller.ex | 12 ++++++++- .../web/templates/layout/static_fe.html.eex | 5 ++++ .../templates/static_fe/static_fe/_notice.html.eex | 29 ++++++++++++++++++++++ .../static_fe/static_fe/conversation.html.eex | 5 ++++ .../templates/static_fe/static_fe/notice.html.eex | 29 ---------------------- .../templates/static_fe/static_fe/profile.html.eex | 6 ++--- 6 files changed, 53 insertions(+), 33 deletions(-) create mode 100644 lib/pleroma/web/templates/static_fe/static_fe/_notice.html.eex create mode 100644 lib/pleroma/web/templates/static_fe/static_fe/conversation.html.eex delete mode 100644 lib/pleroma/web/templates/static_fe/static_fe/notice.html.eex (limited to 'lib') diff --git a/lib/pleroma/web/static_fe/static_fe_controller.ex b/lib/pleroma/web/static_fe/static_fe_controller.ex index 8bbd06aa9..d2b55767d 100644 --- a/lib/pleroma/web/static_fe/static_fe_controller.ex +++ b/lib/pleroma/web/static_fe/static_fe_controller.ex @@ -5,6 +5,7 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do use Pleroma.Web, :controller + alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.StaticFE.ActivityRepresenter alias Pleroma.Web.StaticFE.UserRepresenter @@ -12,11 +13,20 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do def show_notice(conn, %{"notice_id" => notice_id}) do with {:ok, data} <- ActivityRepresenter.represent(notice_id) do + context = data.object.data["context"] + activities = ActivityPub.fetch_activities_for_context(context, %{}) + + data = + for a <- Enum.reverse(activities) do + ActivityRepresenter.prepare_activity(data.user, a) + |> Map.put(:selected, a.object.id == data.object.id) + end + conn |> put_layout(:static_fe) |> put_status(200) |> put_view(Pleroma.Web.StaticFE.StaticFEView) - |> render("notice.html", %{data: data}) + |> render("conversation.html", %{data: data}) else {:error, nil} -> conn diff --git a/lib/pleroma/web/templates/layout/static_fe.html.eex b/lib/pleroma/web/templates/layout/static_fe.html.eex index c1fbd89cd..9d7ee366a 100644 --- a/lib/pleroma/web/templates/layout/static_fe.html.eex +++ b/lib/pleroma/web/templates/layout/static_fe.html.eex @@ -23,6 +23,7 @@ } .activity { + padding: 1em; margin-bottom: 1em; } @@ -41,6 +42,10 @@ max-height: 800px; } + #selected { + background-color: #1b2735; + } + a { color: white; } diff --git a/lib/pleroma/web/templates/static_fe/static_fe/_notice.html.eex b/lib/pleroma/web/templates/static_fe/static_fe/_notice.html.eex new file mode 100644 index 000000000..90b5ef67c --- /dev/null +++ b/lib/pleroma/web/templates/static_fe/static_fe/_notice.html.eex @@ -0,0 +1,29 @@ +
id="selected" <% end %>> +

+ <%= @data.published %>

+ <%= render("user_card.html", %{user: @data.user}) %> +
+ <%= if @data.title != "" do %> +
+ <%= raw @data.title %> +
<%= raw @data.content %>
+
+ <% else %> +
<%= raw @data.content %>
+ <% end %> + <%= for %{"name" => name, "url" => [url | _]} <- @data.attachment do %> + <%= if @data.sensitive do %> +
+ sensitive media +
+ <%= render("_attachment.html", %{name: name, url: url["href"], + mediaType: fetch_media_type(url)}) %> +
+
+ <% else %> + <%= render("_attachment.html", %{name: name, url: url["href"], + mediaType: fetch_media_type(url)}) %> + <% end %> + <% end %> +
+
diff --git a/lib/pleroma/web/templates/static_fe/static_fe/conversation.html.eex b/lib/pleroma/web/templates/static_fe/static_fe/conversation.html.eex new file mode 100644 index 000000000..35c3c17cd --- /dev/null +++ b/lib/pleroma/web/templates/static_fe/static_fe/conversation.html.eex @@ -0,0 +1,5 @@ +
+ <%= for notice <- @data do %> + <%= render("_notice.html", %{data: notice}) %> + <% end %> +
diff --git a/lib/pleroma/web/templates/static_fe/static_fe/notice.html.eex b/lib/pleroma/web/templates/static_fe/static_fe/notice.html.eex deleted file mode 100644 index 9a7824a32..000000000 --- a/lib/pleroma/web/templates/static_fe/static_fe/notice.html.eex +++ /dev/null @@ -1,29 +0,0 @@ -
- <%= render("user_card.html", %{user: @data.user}) %> -

- <%= @data.published %>

-
- <%= if @data.title != "" do %> -
- <%= raw @data.title %> -
<%= raw @data.content %>
-
- <% else %> -
<%= raw @data.content %>
- <% end %> - <%= for %{"name" => name, "url" => [url | _]} <- @data.attachment do %> - <%= if @data.sensitive do %> -
- sensitive media -
- <%= render("_attachment.html", %{name: name, url: url["href"], - mediaType: fetch_media_type(url)}) %> -
-
- <% else %> - <%= render("_attachment.html", %{name: name, url: url["href"], - mediaType: fetch_media_type(url)}) %> - <% end %> - <% end %> -
-
diff --git a/lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex b/lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex index 47b7d5286..79bf5a729 100644 --- a/lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex +++ b/lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex @@ -8,7 +8,7 @@

<%= raw @data.user.bio %>

-<%= for activity <- @data.timeline do %> - <%= render("notice.html", %{data: activity}) %> -<% end %> + <%= for activity <- @data.timeline do %> + <%= render("_notice.html", %{data: activity}) %> + <% end %>
-- cgit v1.2.3 From 2d1897e8a739a54a07ab0eae5cf11c260428e532 Mon Sep 17 00:00:00 2001 From: Phil Hagelberg Date: Tue, 29 Oct 2019 17:45:26 -0700 Subject: Apply all suggested changes from reviewers. --- lib/pleroma/web/ostatus/ostatus_controller.ex | 2 +- lib/pleroma/web/static_fe/activity_representer.ex | 4 +- lib/pleroma/web/static_fe/static_fe_controller.ex | 47 ++++++++-------------- lib/pleroma/web/static_fe/static_fe_view.ex | 9 +++-- lib/pleroma/web/static_fe/user_representer.ex | 9 ++--- .../templates/static_fe/static_fe/_notice.html.eex | 3 +- 6 files changed, 30 insertions(+), 44 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/ostatus/ostatus_controller.ex b/lib/pleroma/web/ostatus/ostatus_controller.ex index ab5fdbc78..be275977e 100644 --- a/lib/pleroma/web/ostatus/ostatus_controller.ex +++ b/lib/pleroma/web/ostatus/ostatus_controller.ex @@ -77,7 +77,7 @@ defmodule Pleroma.Web.OStatus.OStatusController do def notice(%{assigns: %{format: format}} = conn, %{"id" => id}) do if Pleroma.Config.get([:instance, :static_fe], false) do - Pleroma.Web.StaticFE.StaticFEController.show(conn, %{"notice_id" => id}) + Pleroma.Web.StaticFE.StaticFEController.call(conn, :show_notice) else with {_, %Activity{} = activity} <- {:activity, Activity.get_by_id_with_object(id)}, {_, true} <- {:public?, Visibility.is_public?(activity)}, diff --git a/lib/pleroma/web/static_fe/activity_representer.ex b/lib/pleroma/web/static_fe/activity_representer.ex index 7b7e1730c..8a499195c 100644 --- a/lib/pleroma/web/static_fe/activity_representer.ex +++ b/lib/pleroma/web/static_fe/activity_representer.ex @@ -62,8 +62,8 @@ defmodule Pleroma.Web.StaticFE.ActivityRepresenter do {:ok, %User{} = user} <- User.get_or_fetch(activity.data["actor"]) do {:ok, prepare_activity(user, activity)} else - e -> - {:error, e} + {:error, reason} -> {:error, reason} + _error -> {:error, "Not found"} end end end diff --git a/lib/pleroma/web/static_fe/static_fe_controller.ex b/lib/pleroma/web/static_fe/static_fe_controller.ex index d2b55767d..6e8d0d622 100644 --- a/lib/pleroma/web/static_fe/static_fe_controller.ex +++ b/lib/pleroma/web/static_fe/static_fe_controller.ex @@ -9,9 +9,12 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do alias Pleroma.Web.StaticFE.ActivityRepresenter alias Pleroma.Web.StaticFE.UserRepresenter - require Logger + plug(:put_layout, :static_fe) + plug(:put_view, Pleroma.Web.StaticFE.StaticFEView) + plug(:assign_id) + action_fallback(:not_found) - def show_notice(conn, %{"notice_id" => notice_id}) do + def show_notice(%{assigns: %{notice_id: notice_id}} = conn, _params) do with {:ok, data} <- ActivityRepresenter.represent(notice_id) do context = data.object.data["context"] activities = ActivityPub.fetch_activities_for_context(context, %{}) @@ -22,45 +25,29 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do |> Map.put(:selected, a.object.id == data.object.id) end - conn - |> put_layout(:static_fe) - |> put_status(200) - |> put_view(Pleroma.Web.StaticFE.StaticFEView) - |> render("conversation.html", %{data: data}) - else - {:error, nil} -> - conn - |> put_status(404) - |> text("Not found") + render(conn, "conversation.html", data: data) end end - def show_user(conn, %{"username_or_id" => username_or_id}) do + def show_user(%{assigns: %{username_or_id: username_or_id}} = conn, _params) do with {:ok, data} <- UserRepresenter.represent(username_or_id) do - conn - |> put_layout(:static_fe) - |> put_status(200) - |> put_view(Pleroma.Web.StaticFE.StaticFEView) - |> render("profile.html", %{data: data}) - else - {:error, nil} -> - conn - |> put_status(404) - |> text("Not found") + render(conn, "profile.html", data: data) end end - def show(%{path_info: ["notice", notice_id]} = conn, _params), - do: show_notice(conn, %{"notice_id" => notice_id}) + def assign_id(%{path_info: ["notice", notice_id]} = conn, _opts), + do: assign(conn, :notice_id, notice_id) - def show(%{path_info: ["users", user_id]} = conn, _params), - do: show_user(conn, %{"username_or_id" => user_id}) + def assign_id(%{path_info: ["users", user_id]} = conn, _opts), + do: assign(conn, :username_or_id, user_id) - def show(%{path_info: [user_id]} = conn, _params), - do: show_user(conn, %{"username_or_id" => user_id}) + def assign_id(%{path_info: [user_id]} = conn, _opts), + do: assign(conn, :username_or_id, user_id) + + def assign_id(conn, _opts), do: conn # Fallback for unhandled types - def show(conn, _params) do + def not_found(conn, _opts) do conn |> put_status(404) |> text("Not found") diff --git a/lib/pleroma/web/static_fe/static_fe_view.ex b/lib/pleroma/web/static_fe/static_fe_view.ex index 2b3b968d3..d633751dd 100644 --- a/lib/pleroma/web/static_fe/static_fe_view.ex +++ b/lib/pleroma/web/static_fe/static_fe_view.ex @@ -11,19 +11,20 @@ defmodule Pleroma.Web.StaticFE.StaticFEView do alias Pleroma.Web.Metadata.Utils alias Pleroma.Web.Router.Helpers - import Phoenix.HTML + use Phoenix.HTML @media_types ["image", "audio", "video"] def emoji_for_user(%User{} = user) do - (user.source_data["tag"] || []) + user.source_data + |> Map.get("tag", []) |> Enum.filter(fn %{"type" => t} -> t == "Emoji" end) |> Enum.map(fn %{"icon" => %{"url" => url}, "name" => name} -> {String.trim(name, ":"), url} end) end - def fetch_media_type(url) do - Utils.fetch_media_type(@media_types, url["mediaType"]) + def fetch_media_type(%{"mediaType" => mediaType}) do + Utils.fetch_media_type(@media_types, mediaType) end end diff --git a/lib/pleroma/web/static_fe/user_representer.ex b/lib/pleroma/web/static_fe/user_representer.ex index 9d2f1eb85..26320ea69 100644 --- a/lib/pleroma/web/static_fe/user_representer.ex +++ b/lib/pleroma/web/static_fe/user_representer.ex @@ -24,12 +24,9 @@ defmodule Pleroma.Web.StaticFE.UserRepresenter do end def represent(username_or_id) do - with %User{} = user <- User.get_cached_by_nickname_or_id(username_or_id), - data <- prepare_user(user) do - {:ok, data} - else - e -> - {:error, e} + case User.get_cached_by_nickname_or_id(username_or_id) do + %User{} = user -> {:ok, prepare_user(user)} + nil -> {:error, "User not found"} end end end diff --git a/lib/pleroma/web/templates/static_fe/static_fe/_notice.html.eex b/lib/pleroma/web/templates/static_fe/static_fe/_notice.html.eex index 90b5ef67c..ed43ae838 100644 --- a/lib/pleroma/web/templates/static_fe/static_fe/_notice.html.eex +++ b/lib/pleroma/web/templates/static_fe/static_fe/_notice.html.eex @@ -1,6 +1,7 @@
id="selected" <% end %>>

- <%= @data.published %>

+ <%= link @data.published, to: @data.link, class: "activity-link" %> +

<%= render("user_card.html", %{user: @data.user}) %>
<%= if @data.title != "" do %> -- cgit v1.2.3 From e944a2213dd5eaaf69b9e8d8f5e035dbba2fdab1 Mon Sep 17 00:00:00 2001 From: Phil Hagelberg Date: Tue, 29 Oct 2019 17:53:58 -0700 Subject: Use gettext for sensitive media warning. --- lib/pleroma/web/static_fe/static_fe_view.ex | 1 + lib/pleroma/web/templates/static_fe/static_fe/_notice.html.eex | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/static_fe/static_fe_view.ex b/lib/pleroma/web/static_fe/static_fe_view.ex index d633751dd..1194b7ecc 100644 --- a/lib/pleroma/web/static_fe/static_fe_view.ex +++ b/lib/pleroma/web/static_fe/static_fe_view.ex @@ -6,6 +6,7 @@ defmodule Pleroma.Web.StaticFE.StaticFEView do use Pleroma.Web, :view alias Pleroma.User + alias Pleroma.Web.Gettext alias Pleroma.Web.MediaProxy alias Pleroma.Formatter alias Pleroma.Web.Metadata.Utils diff --git a/lib/pleroma/web/templates/static_fe/static_fe/_notice.html.eex b/lib/pleroma/web/templates/static_fe/static_fe/_notice.html.eex index ed43ae838..c4cdb1029 100644 --- a/lib/pleroma/web/templates/static_fe/static_fe/_notice.html.eex +++ b/lib/pleroma/web/templates/static_fe/static_fe/_notice.html.eex @@ -15,7 +15,7 @@ <%= for %{"name" => name, "url" => [url | _]} <- @data.attachment do %> <%= if @data.sensitive do %>
- sensitive media + <%= Gettext.gettext("sensitive media") %>
<%= render("_attachment.html", %{name: name, url: url["href"], mediaType: fetch_media_type(url)}) %> -- cgit v1.2.3 From 41fde63defd332a84b6c4d4ca78848e623a9d122 Mon Sep 17 00:00:00 2001 From: Phil Hagelberg Date: Tue, 29 Oct 2019 19:27:42 -0700 Subject: Get rid of @data in views and use separate fields. --- lib/pleroma/web/static_fe/static_fe_controller.ex | 12 +++++------- .../web/templates/static_fe/static_fe/_notice.html.eex | 18 +++++++++--------- .../static_fe/static_fe/conversation.html.eex | 4 ++-- .../web/templates/static_fe/static_fe/profile.html.eex | 10 +++++----- 4 files changed, 21 insertions(+), 23 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/static_fe/static_fe_controller.ex b/lib/pleroma/web/static_fe/static_fe_controller.ex index 6e8d0d622..c77df8e7d 100644 --- a/lib/pleroma/web/static_fe/static_fe_controller.ex +++ b/lib/pleroma/web/static_fe/static_fe_controller.ex @@ -17,22 +17,20 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do def show_notice(%{assigns: %{notice_id: notice_id}} = conn, _params) do with {:ok, data} <- ActivityRepresenter.represent(notice_id) do context = data.object.data["context"] - activities = ActivityPub.fetch_activities_for_context(context, %{}) - data = - for a <- Enum.reverse(activities) do + activities = + for a <- Enum.reverse(ActivityPub.fetch_activities_for_context(context, %{})) do ActivityRepresenter.prepare_activity(data.user, a) |> Map.put(:selected, a.object.id == data.object.id) end - render(conn, "conversation.html", data: data) + render(conn, "conversation.html", activities: activities) end end def show_user(%{assigns: %{username_or_id: username_or_id}} = conn, _params) do - with {:ok, data} <- UserRepresenter.represent(username_or_id) do - render(conn, "profile.html", data: data) - end + {:ok, data} = UserRepresenter.represent(username_or_id) + render(conn, "profile.html", %{user: data.user, timeline: data.timeline}) end def assign_id(%{path_info: ["notice", notice_id]} = conn, _opts), diff --git a/lib/pleroma/web/templates/static_fe/static_fe/_notice.html.eex b/lib/pleroma/web/templates/static_fe/static_fe/_notice.html.eex index c4cdb1029..b16d19a2c 100644 --- a/lib/pleroma/web/templates/static_fe/static_fe/_notice.html.eex +++ b/lib/pleroma/web/templates/static_fe/static_fe/_notice.html.eex @@ -1,19 +1,19 @@ -
id="selected" <% end %>> +
id="selected" <% end %>>

- <%= link @data.published, to: @data.link, class: "activity-link" %> + <%= link @published, to: @link, class: "activity-link" %>

- <%= render("user_card.html", %{user: @data.user}) %> + <%= render("user_card.html", %{user: @user}) %>
- <%= if @data.title != "" do %> + <%= if @title != "" do %>
- <%= raw @data.title %> -
<%= raw @data.content %>
+ <%= raw @title %> +
<%= raw @content %>
<% else %> -
<%= raw @data.content %>
+
<%= raw @content %>
<% end %> - <%= for %{"name" => name, "url" => [url | _]} <- @data.attachment do %> - <%= if @data.sensitive do %> + <%= for %{"name" => name, "url" => [url | _]} <- @attachment do %> + <%= if @sensitive do %>
<%= Gettext.gettext("sensitive media") %>
diff --git a/lib/pleroma/web/templates/static_fe/static_fe/conversation.html.eex b/lib/pleroma/web/templates/static_fe/static_fe/conversation.html.eex index 35c3c17cd..f0d3b5972 100644 --- a/lib/pleroma/web/templates/static_fe/static_fe/conversation.html.eex +++ b/lib/pleroma/web/templates/static_fe/static_fe/conversation.html.eex @@ -1,5 +1,5 @@
- <%= for notice <- @data do %> - <%= render("_notice.html", %{data: notice}) %> + <%= for activity <- @activities do %> + <%= render("_notice.html", activity) %> <% end %>
diff --git a/lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex b/lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex index 79bf5a729..da23be1e5 100644 --- a/lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex +++ b/lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex @@ -1,14 +1,14 @@

- +
- <%= raw (@data.user.name |> Formatter.emojify(emoji_for_user(@data.user))) %> + <%= raw (@user.name |> Formatter.emojify(emoji_for_user(@user))) %>

-

<%= raw @data.user.bio %>

+

<%= raw @user.bio %>

- <%= for activity <- @data.timeline do %> - <%= render("_notice.html", %{data: activity}) %> + <%= for activity <- @timeline do %> + <%= render("_notice.html", Map.put(activity, :selected, false)) %> <% end %>
-- cgit v1.2.3 From 33a26b61c30ad8084003f0f1c646bc997a8d88ac Mon Sep 17 00:00:00 2001 From: Phil Hagelberg Date: Tue, 29 Oct 2019 20:30:43 -0700 Subject: Remove activity/user representer; move logic to controller. --- lib/pleroma/web/static_fe/activity_representer.ex | 69 ----------------------- lib/pleroma/web/static_fe/static_fe_controller.ex | 59 ++++++++++++++----- lib/pleroma/web/static_fe/user_representer.ex | 32 ----------- 3 files changed, 46 insertions(+), 114 deletions(-) delete mode 100644 lib/pleroma/web/static_fe/activity_representer.ex delete mode 100644 lib/pleroma/web/static_fe/user_representer.ex (limited to 'lib') diff --git a/lib/pleroma/web/static_fe/activity_representer.ex b/lib/pleroma/web/static_fe/activity_representer.ex deleted file mode 100644 index 8a499195c..000000000 --- a/lib/pleroma/web/static_fe/activity_representer.ex +++ /dev/null @@ -1,69 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.StaticFE.ActivityRepresenter do - alias Pleroma.Activity - alias Pleroma.Object - alias Pleroma.User - alias Pleroma.Web.ActivityPub.Visibility - alias Pleroma.Web.Router.Helpers - - def prepare_activity(%User{} = user, %Activity{} = activity) do - object = Object.normalize(activity.data["object"]) - - %{} - |> set_user(user) - |> set_object(object) - |> set_title(object) - |> set_content(object) - |> set_link(activity.id) - |> set_published(object) - |> set_sensitive(object) - |> set_attachment(object.data["attachment"]) - |> set_attachments(object) - end - - defp set_user(data, %User{} = user), do: Map.put(data, :user, user) - - defp set_object(data, %Object{} = object), do: Map.put(data, :object, object) - - defp set_title(data, %Object{data: %{"name" => name}}) when is_binary(name), - do: Map.put(data, :title, name) - - defp set_title(data, %Object{data: %{"summary" => summary}}) when is_binary(summary), - do: Map.put(data, :title, summary) - - defp set_title(data, _), do: Map.put(data, :title, nil) - - defp set_content(data, %Object{data: %{"content" => content}}) when is_binary(content), - do: Map.put(data, :content, content) - - defp set_content(data, _), do: Map.put(data, :content, nil) - - defp set_attachment(data, attachment), do: Map.put(data, :attachment, attachment) - - defp set_link(data, activity_id), - do: Map.put(data, :link, Helpers.o_status_url(Pleroma.Web.Endpoint, :notice, activity_id)) - - defp set_published(data, %Object{data: %{"published" => published}}), - do: Map.put(data, :published, published) - - defp set_sensitive(data, %Object{data: %{"sensitive" => sensitive}}), - do: Map.put(data, :sensitive, sensitive) - - # TODO: attachments - defp set_attachments(data, _), do: Map.put(data, :attachments, []) - - def represent(activity_id) do - with %Activity{data: %{"type" => "Create"}} = activity <- - Activity.get_by_id_with_object(activity_id), - true <- Visibility.is_public?(activity), - {:ok, %User{} = user} <- User.get_or_fetch(activity.data["actor"]) do - {:ok, prepare_activity(user, activity)} - else - {:error, reason} -> {:error, reason} - _error -> {:error, "Not found"} - end - end -end diff --git a/lib/pleroma/web/static_fe/static_fe_controller.ex b/lib/pleroma/web/static_fe/static_fe_controller.ex index c77df8e7d..a5cb76167 100644 --- a/lib/pleroma/web/static_fe/static_fe_controller.ex +++ b/lib/pleroma/web/static_fe/static_fe_controller.ex @@ -5,32 +5,65 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do use Pleroma.Web, :controller + alias Pleroma.Activity + alias Pleroma.Object + alias Pleroma.User alias Pleroma.Web.ActivityPub.ActivityPub - alias Pleroma.Web.StaticFE.ActivityRepresenter - alias Pleroma.Web.StaticFE.UserRepresenter + alias Pleroma.Web.Router.Helpers plug(:put_layout, :static_fe) plug(:put_view, Pleroma.Web.StaticFE.StaticFEView) plug(:assign_id) action_fallback(:not_found) + defp get_title(%Object{data: %{"name" => name}}) when is_binary(name), + do: name + + defp get_title(%Object{data: %{"summary" => summary}}) when is_binary(summary), + do: summary + + defp get_title(_), do: nil + + def represent(%Activity{} = activity, %User{} = user, selected) do + %{ + user: user, + title: get_title(activity.object), + content: activity.object.data["content"] || nil, + attachment: activity.object.data["attachment"], + link: Helpers.o_status_url(Pleroma.Web.Endpoint, :notice, activity.id), + published: activity.object.data["published"], + sensitive: activity.object.data["sensitive"], + selected: selected + } + end + + def represent(%Activity{} = activity, selected) do + {:ok, user} = User.get_or_fetch(activity.data["actor"]) + represent(activity, user, selected) + end + def show_notice(%{assigns: %{notice_id: notice_id}} = conn, _params) do - with {:ok, data} <- ActivityRepresenter.represent(notice_id) do - context = data.object.data["context"] + activity = Activity.get_by_id_with_object(notice_id) + context = activity.object.data["context"] + activities = ActivityPub.fetch_activities_for_context(context, %{}) - activities = - for a <- Enum.reverse(ActivityPub.fetch_activities_for_context(context, %{})) do - ActivityRepresenter.prepare_activity(data.user, a) - |> Map.put(:selected, a.object.id == data.object.id) - end + represented = + for a <- Enum.reverse(activities) do + represent(activity, a.object.id == activity.object.id) + end - render(conn, "conversation.html", activities: activities) - end + render(conn, "conversation.html", activities: represented) end def show_user(%{assigns: %{username_or_id: username_or_id}} = conn, _params) do - {:ok, data} = UserRepresenter.represent(username_or_id) - render(conn, "profile.html", %{user: data.user, timeline: data.timeline}) + %User{} = user = User.get_cached_by_nickname_or_id(username_or_id) + + timeline = + for activity <- ActivityPub.fetch_user_activities(user, nil, %{}) do + represent(activity, user, false) + end + + render(conn, "profile.html", %{user: user, timeline: timeline}) end def assign_id(%{path_info: ["notice", notice_id]} = conn, _opts), diff --git a/lib/pleroma/web/static_fe/user_representer.ex b/lib/pleroma/web/static_fe/user_representer.ex deleted file mode 100644 index 26320ea69..000000000 --- a/lib/pleroma/web/static_fe/user_representer.ex +++ /dev/null @@ -1,32 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.StaticFE.UserRepresenter do - alias Pleroma.User - alias Pleroma.Web.ActivityPub.ActivityPub - alias Pleroma.Web.StaticFE.ActivityRepresenter - - def prepare_user(%User{} = user) do - %{} - |> set_user(user) - |> set_timeline(user) - end - - defp set_user(data, %User{} = user), do: Map.put(data, :user, user) - - defp set_timeline(data, %User{} = user) do - activities = - ActivityPub.fetch_user_activities(user, nil, %{}) - |> Enum.map(fn activity -> ActivityRepresenter.prepare_activity(user, activity) end) - - Map.put(data, :timeline, activities) - end - - def represent(username_or_id) do - case User.get_cached_by_nickname_or_id(username_or_id) do - %User{} = user -> {:ok, prepare_user(user)} - nil -> {:error, "User not found"} - end - end -end -- cgit v1.2.3 From 918e1353f6bc7f6dfe317a87d942dfa2e53064af Mon Sep 17 00:00:00 2001 From: Phil Hagelberg Date: Tue, 29 Oct 2019 20:55:43 -0700 Subject: Add header to profile/notice pages linking to pleroma-fe. --- lib/pleroma/web/static_fe/static_fe_controller.ex | 6 ++++-- .../web/templates/static_fe/static_fe/_notice.html.eex | 2 +- .../web/templates/static_fe/static_fe/_user_card.html.eex | 11 +++++++++++ .../web/templates/static_fe/static_fe/conversation.html.eex | 2 ++ .../web/templates/static_fe/static_fe/profile.html.eex | 6 ++++-- .../web/templates/static_fe/static_fe/user_card.html.eex | 11 ----------- 6 files changed, 22 insertions(+), 16 deletions(-) create mode 100644 lib/pleroma/web/templates/static_fe/static_fe/_user_card.html.eex delete mode 100644 lib/pleroma/web/templates/static_fe/static_fe/user_card.html.eex (limited to 'lib') diff --git a/lib/pleroma/web/static_fe/static_fe_controller.ex b/lib/pleroma/web/static_fe/static_fe_controller.ex index a5cb76167..fe2fb09c4 100644 --- a/lib/pleroma/web/static_fe/static_fe_controller.ex +++ b/lib/pleroma/web/static_fe/static_fe_controller.ex @@ -43,6 +43,7 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do end def show_notice(%{assigns: %{notice_id: notice_id}} = conn, _params) do + instance_name = Pleroma.Config.get([:instance, :name], "Pleroma") activity = Activity.get_by_id_with_object(notice_id) context = activity.object.data["context"] activities = ActivityPub.fetch_activities_for_context(context, %{}) @@ -52,10 +53,11 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do represent(activity, a.object.id == activity.object.id) end - render(conn, "conversation.html", activities: represented) + render(conn, "conversation.html", %{activities: represented, instance_name: instance_name}) end def show_user(%{assigns: %{username_or_id: username_or_id}} = conn, _params) do + instance_name = Pleroma.Config.get([:instance, :name], "Pleroma") %User{} = user = User.get_cached_by_nickname_or_id(username_or_id) timeline = @@ -63,7 +65,7 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do represent(activity, user, false) end - render(conn, "profile.html", %{user: user, timeline: timeline}) + render(conn, "profile.html", %{user: user, timeline: timeline, instance_name: instance_name}) end def assign_id(%{path_info: ["notice", notice_id]} = conn, _opts), diff --git a/lib/pleroma/web/templates/static_fe/static_fe/_notice.html.eex b/lib/pleroma/web/templates/static_fe/static_fe/_notice.html.eex index b16d19a2c..d1daa281c 100644 --- a/lib/pleroma/web/templates/static_fe/static_fe/_notice.html.eex +++ b/lib/pleroma/web/templates/static_fe/static_fe/_notice.html.eex @@ -2,7 +2,7 @@

<%= link @published, to: @link, class: "activity-link" %>

- <%= render("user_card.html", %{user: @user}) %> + <%= render("_user_card.html", %{user: @user}) %>
<%= if @title != "" do %>
diff --git a/lib/pleroma/web/templates/static_fe/static_fe/_user_card.html.eex b/lib/pleroma/web/templates/static_fe/static_fe/_user_card.html.eex new file mode 100644 index 000000000..c7789f9ac --- /dev/null +++ b/lib/pleroma/web/templates/static_fe/static_fe/_user_card.html.eex @@ -0,0 +1,11 @@ + diff --git a/lib/pleroma/web/templates/static_fe/static_fe/conversation.html.eex b/lib/pleroma/web/templates/static_fe/static_fe/conversation.html.eex index f0d3b5972..3a1249df2 100644 --- a/lib/pleroma/web/templates/static_fe/static_fe/conversation.html.eex +++ b/lib/pleroma/web/templates/static_fe/static_fe/conversation.html.eex @@ -1,3 +1,5 @@ +

<%= link @instance_name, to: "/" %>

+
<%= for activity <- @activities do %> <%= render("_notice.html", activity) %> diff --git a/lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex b/lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex index da23be1e5..8f2c74627 100644 --- a/lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex +++ b/lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex @@ -1,11 +1,13 @@ -

+

<%= link @instance_name, to: "/" %>

+ +

<%= raw (@user.name |> Formatter.emojify(emoji_for_user(@user))) %> -

+

<%= raw @user.bio %>

<%= for activity <- @timeline do %> diff --git a/lib/pleroma/web/templates/static_fe/static_fe/user_card.html.eex b/lib/pleroma/web/templates/static_fe/static_fe/user_card.html.eex deleted file mode 100644 index c7789f9ac..000000000 --- a/lib/pleroma/web/templates/static_fe/static_fe/user_card.html.eex +++ /dev/null @@ -1,11 +0,0 @@ - -- cgit v1.2.3 From 93e9c0cedf0e2b4ab5966832cc912369c7aaf3ad Mon Sep 17 00:00:00 2001 From: Phil Hagelberg Date: Tue, 29 Oct 2019 21:09:05 -0700 Subject: Format dates using CommonAPI utils. --- lib/pleroma/web/static_fe/static_fe_view.ex | 5 +++++ lib/pleroma/web/templates/static_fe/static_fe/_notice.html.eex | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/static_fe/static_fe_view.ex b/lib/pleroma/web/static_fe/static_fe_view.ex index 1194b7ecc..c19aa07e1 100644 --- a/lib/pleroma/web/static_fe/static_fe_view.ex +++ b/lib/pleroma/web/static_fe/static_fe_view.ex @@ -28,4 +28,9 @@ defmodule Pleroma.Web.StaticFE.StaticFEView do def fetch_media_type(%{"mediaType" => mediaType}) do Utils.fetch_media_type(@media_types, mediaType) end + + def format_date(date) do + {:ok, date, _} = DateTime.from_iso8601(date) + Pleroma.Web.CommonAPI.Utils.format_asctime(date) + end end diff --git a/lib/pleroma/web/templates/static_fe/static_fe/_notice.html.eex b/lib/pleroma/web/templates/static_fe/static_fe/_notice.html.eex index d1daa281c..9841fcf84 100644 --- a/lib/pleroma/web/templates/static_fe/static_fe/_notice.html.eex +++ b/lib/pleroma/web/templates/static_fe/static_fe/_notice.html.eex @@ -1,6 +1,6 @@
id="selected" <% end %>>

- <%= link @published, to: @link, class: "activity-link" %> + <%= link format_date(@published), to: @link, class: "activity-link" %>

<%= render("_user_card.html", %{user: @user}) %>
-- cgit v1.2.3 From e4b9784c3938772edf45340107a34a58aeeea690 Mon Sep 17 00:00:00 2001 From: Phil Hagelberg Date: Tue, 29 Oct 2019 22:05:18 -0700 Subject: Show counts for replies, likes, and announces for selected notice. Using text instead of an icon, for now. --- lib/pleroma/web/static_fe/static_fe_controller.ex | 15 +++++++++++++-- lib/pleroma/web/templates/layout/static_fe.html.eex | 6 ++++++ .../web/templates/static_fe/static_fe/_notice.html.eex | 7 +++++++ 3 files changed, 26 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/static_fe/static_fe_controller.ex b/lib/pleroma/web/static_fe/static_fe_controller.ex index fe2fb09c4..d2e72b476 100644 --- a/lib/pleroma/web/static_fe/static_fe_controller.ex +++ b/lib/pleroma/web/static_fe/static_fe_controller.ex @@ -24,6 +24,16 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do defp get_title(_), do: nil + def get_counts(%Activity{} = activity) do + %Object{data: data} = Object.normalize(activity) + + %{ + likes: data["like_count"] || 0, + replies: data["repliesCount"] || 0, + announces: data["announcement_count"] || 0 + } + end + def represent(%Activity{} = activity, %User{} = user, selected) do %{ user: user, @@ -33,7 +43,8 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do link: Helpers.o_status_url(Pleroma.Web.Endpoint, :notice, activity.id), published: activity.object.data["published"], sensitive: activity.object.data["sensitive"], - selected: selected + selected: selected, + counts: get_counts(activity) } end @@ -50,7 +61,7 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do represented = for a <- Enum.reverse(activities) do - represent(activity, a.object.id == activity.object.id) + represent(a, a.object.id == activity.object.id) end render(conn, "conversation.html", %{activities: represented, instance_name: instance_name}) diff --git a/lib/pleroma/web/templates/layout/static_fe.html.eex b/lib/pleroma/web/templates/layout/static_fe.html.eex index 9d7ee366a..e42047de9 100644 --- a/lib/pleroma/web/templates/layout/static_fe.html.eex +++ b/lib/pleroma/web/templates/layout/static_fe.html.eex @@ -24,6 +24,7 @@ .activity { padding: 1em; + padding-bottom: 2em; margin-bottom: 1em; } @@ -46,6 +47,11 @@ background-color: #1b2735; } + .counts dt, .counts dd { + float: left; + margin-left: 1em; + } + a { color: white; } diff --git a/lib/pleroma/web/templates/static_fe/static_fe/_notice.html.eex b/lib/pleroma/web/templates/static_fe/static_fe/_notice.html.eex index 9841fcf84..2a46dadb4 100644 --- a/lib/pleroma/web/templates/static_fe/static_fe/_notice.html.eex +++ b/lib/pleroma/web/templates/static_fe/static_fe/_notice.html.eex @@ -27,4 +27,11 @@ <% end %> <% end %>
+ <%= if @selected do %> +
+
<%= Gettext.gettext("replies") %>
<%= @counts.replies %>
+
<%= Gettext.gettext("announces") %>
<%= @counts.announces %>
+
<%= Gettext.gettext("likes") %>
<%= @counts.likes %>
+
+ <% end %>
-- cgit v1.2.3 From 1dc785b74be6dc790d2b24e833642060303ecee2 Mon Sep 17 00:00:00 2001 From: Phil Hagelberg Date: Wed, 30 Oct 2019 20:20:26 -0700 Subject: Move static-fe CSS to a separate file. --- .../web/templates/layout/static_fe.html.eex | 165 +-------------------- 1 file changed, 1 insertion(+), 164 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/templates/layout/static_fe.html.eex b/lib/pleroma/web/templates/layout/static_fe.html.eex index e42047de9..62b59f17c 100644 --- a/lib/pleroma/web/templates/layout/static_fe.html.eex +++ b/lib/pleroma/web/templates/layout/static_fe.html.eex @@ -6,170 +6,7 @@ <%= Application.get_env(:pleroma, :instance)[:name] %> - +
-- cgit v1.2.3 From 5d7c44266ba0355557e5a62ecca69428c5784d88 Mon Sep 17 00:00:00 2001 From: Phil Hagelberg Date: Wed, 30 Oct 2019 20:20:54 -0700 Subject: Change date formatting. --- lib/pleroma/web/static_fe/static_fe_view.ex | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/static_fe/static_fe_view.ex b/lib/pleroma/web/static_fe/static_fe_view.ex index c19aa07e1..6128b2497 100644 --- a/lib/pleroma/web/static_fe/static_fe_view.ex +++ b/lib/pleroma/web/static_fe/static_fe_view.ex @@ -5,6 +5,8 @@ defmodule Pleroma.Web.StaticFE.StaticFEView do use Pleroma.Web, :view + alias Calendar.Strftime + alias Pleroma.Emoji.Formatter alias Pleroma.User alias Pleroma.Web.Gettext alias Pleroma.Web.MediaProxy @@ -31,6 +33,6 @@ defmodule Pleroma.Web.StaticFE.StaticFEView do def format_date(date) do {:ok, date, _} = DateTime.from_iso8601(date) - Pleroma.Web.CommonAPI.Utils.format_asctime(date) + Strftime.strftime!(date, "%Y/%m/%d %l:%M:%S %p UTC") end end -- cgit v1.2.3 From 2ac1ece652621df9adf591255f4506564a8ace68 Mon Sep 17 00:00:00 2001 From: Phil Hagelberg Date: Wed, 30 Oct 2019 20:21:10 -0700 Subject: Fix a bug where reblogs were displayed under the wrong user. --- lib/pleroma/web/static_fe/static_fe_controller.ex | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/static_fe/static_fe_controller.ex b/lib/pleroma/web/static_fe/static_fe_controller.ex index d2e72b476..9b565d07d 100644 --- a/lib/pleroma/web/static_fe/static_fe_controller.ex +++ b/lib/pleroma/web/static_fe/static_fe_controller.ex @@ -34,7 +34,9 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do } end - def represent(%Activity{} = activity, %User{} = user, selected) do + def represent(%Activity{} = activity, selected) do + {:ok, user} = User.get_or_fetch(activity.object.data["actor"]) + %{ user: user, title: get_title(activity.object), @@ -48,11 +50,6 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do } end - def represent(%Activity{} = activity, selected) do - {:ok, user} = User.get_or_fetch(activity.data["actor"]) - represent(activity, user, selected) - end - def show_notice(%{assigns: %{notice_id: notice_id}} = conn, _params) do instance_name = Pleroma.Config.get([:instance, :name], "Pleroma") activity = Activity.get_by_id_with_object(notice_id) @@ -73,7 +70,7 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do timeline = for activity <- ActivityPub.fetch_user_activities(user, nil, %{}) do - represent(activity, user, false) + represent(activity, false) end render(conn, "profile.html", %{user: user, timeline: timeline, instance_name: instance_name}) -- cgit v1.2.3 From 274cc18e8a585bd72353f9135c18aec0cb8e7ce3 Mon Sep 17 00:00:00 2001 From: Phil Hagelberg Date: Thu, 31 Oct 2019 17:44:43 -0700 Subject: Visually separate header. --- lib/pleroma/web/static_fe/static_fe_controller.ex | 10 +++--- lib/pleroma/web/static_fe/static_fe_view.ex | 1 + .../static_fe/static_fe/conversation.html.eex | 16 ++++++---- .../templates/static_fe/static_fe/profile.html.eex | 36 +++++++++++++--------- 4 files changed, 37 insertions(+), 26 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/static_fe/static_fe_controller.ex b/lib/pleroma/web/static_fe/static_fe_controller.ex index 9b565d07d..c35657d8e 100644 --- a/lib/pleroma/web/static_fe/static_fe_controller.ex +++ b/lib/pleroma/web/static_fe/static_fe_controller.ex @@ -34,17 +34,17 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do } end - def represent(%Activity{} = activity, selected) do + def represent(%Activity{object: %Object{data: data}} = activity, selected) do {:ok, user} = User.get_or_fetch(activity.object.data["actor"]) %{ user: user, title: get_title(activity.object), - content: activity.object.data["content"] || nil, - attachment: activity.object.data["attachment"], + content: data["content"] || nil, + attachment: data["attachment"], link: Helpers.o_status_url(Pleroma.Web.Endpoint, :notice, activity.id), - published: activity.object.data["published"], - sensitive: activity.object.data["sensitive"], + published: data["published"], + sensitive: data["sensitive"], selected: selected, counts: get_counts(activity) } diff --git a/lib/pleroma/web/static_fe/static_fe_view.ex b/lib/pleroma/web/static_fe/static_fe_view.ex index 6128b2497..160261af9 100644 --- a/lib/pleroma/web/static_fe/static_fe_view.ex +++ b/lib/pleroma/web/static_fe/static_fe_view.ex @@ -8,6 +8,7 @@ defmodule Pleroma.Web.StaticFE.StaticFEView do alias Calendar.Strftime alias Pleroma.Emoji.Formatter alias Pleroma.User + alias Pleroma.Web.Endpoint alias Pleroma.Web.Gettext alias Pleroma.Web.MediaProxy alias Pleroma.Formatter diff --git a/lib/pleroma/web/templates/static_fe/static_fe/conversation.html.eex b/lib/pleroma/web/templates/static_fe/static_fe/conversation.html.eex index 3a1249df2..7ac4a9e5f 100644 --- a/lib/pleroma/web/templates/static_fe/static_fe/conversation.html.eex +++ b/lib/pleroma/web/templates/static_fe/static_fe/conversation.html.eex @@ -1,7 +1,11 @@ -

<%= link @instance_name, to: "/" %>

+
+

<%= link @instance_name, to: "/" %>

+
-
- <%= for activity <- @activities do %> - <%= render("_notice.html", activity) %> - <% end %> -
+
+
+ <%= for activity <- @activities do %> + <%= render("_notice.html", activity) %> + <% end %> +
+
diff --git a/lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex b/lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex index 8f2c74627..9b3d0509e 100644 --- a/lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex +++ b/lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex @@ -1,16 +1,22 @@ -

<%= link @instance_name, to: "/" %>

+
+

<%= link @instance_name, to: "/" %>

-

-
- - - -
- <%= raw (@user.name |> Formatter.emojify(emoji_for_user(@user))) %> -

-

<%= raw @user.bio %>

-
- <%= for activity <- @timeline do %> - <%= render("_notice.html", Map.put(activity, :selected, false)) %> - <% end %> -
+

+
+ + + +
+ <%= raw Formatter.emojify(@user.name, emoji_for_user(@user)) %> | + <%= link "@#{@user.nickname}@#{Endpoint.host()}", to: User.profile_url(@user) %> +

+

<%= raw @user.bio %>

+
+ +
+
+ <%= for activity <- @timeline do %> + <%= render("_notice.html", Map.put(activity, :selected, false)) %> + <% end %> +
+
-- cgit v1.2.3 From c6c706161e462bb6190cb4471e81e5a8c3b66d20 Mon Sep 17 00:00:00 2001 From: Phil Hagelberg Date: Thu, 31 Oct 2019 18:26:34 -0700 Subject: Make sure notice link is remote if the post is remote. --- lib/pleroma/web/static_fe/static_fe_controller.ex | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/static_fe/static_fe_controller.ex b/lib/pleroma/web/static_fe/static_fe_controller.ex index c35657d8e..5f69218ce 100644 --- a/lib/pleroma/web/static_fe/static_fe_controller.ex +++ b/lib/pleroma/web/static_fe/static_fe_controller.ex @@ -37,12 +37,19 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do def represent(%Activity{object: %Object{data: data}} = activity, selected) do {:ok, user} = User.get_or_fetch(activity.object.data["actor"]) + link = + if user.local do + Helpers.o_status_url(Pleroma.Web.Endpoint, :notice, activity) + else + data["url"] || data["external_url"] || data["id"] + end + %{ user: user, title: get_title(activity.object), content: data["content"] || nil, attachment: data["attachment"], - link: Helpers.o_status_url(Pleroma.Web.Endpoint, :notice, activity.id), + link: link, published: data["published"], sensitive: data["sensitive"], selected: selected, -- cgit v1.2.3 From dc3b87d153415bee6a169b4c787f79dbee74c622 Mon Sep 17 00:00:00 2001 From: Phil Hagelberg Date: Fri, 1 Nov 2019 19:47:18 -0700 Subject: Move static FE routing into its own plug. Previously it was piggybacking on FallbackRedirectController for users and OStatusController for notices; now it's all in one place. --- lib/pleroma/plugs/static_fe_plug.ex | 14 +++++ lib/pleroma/web/ostatus/ostatus_controller.ex | 64 +++++++++++------------ lib/pleroma/web/router.ex | 1 + lib/pleroma/web/static_fe/static_fe_controller.ex | 33 ++++-------- 4 files changed, 56 insertions(+), 56 deletions(-) create mode 100644 lib/pleroma/plugs/static_fe_plug.ex (limited to 'lib') diff --git a/lib/pleroma/plugs/static_fe_plug.ex b/lib/pleroma/plugs/static_fe_plug.ex new file mode 100644 index 000000000..d3abaf4cc --- /dev/null +++ b/lib/pleroma/plugs/static_fe_plug.ex @@ -0,0 +1,14 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Plugs.StaticFEPlug do + def init(options), do: options + + def call(conn, _) do + case Pleroma.Config.get([:instance, :static_fe], false) do + true -> Pleroma.Web.StaticFE.StaticFEController.call(conn, :show) + _ -> conn + end + end +end diff --git a/lib/pleroma/web/ostatus/ostatus_controller.ex b/lib/pleroma/web/ostatus/ostatus_controller.ex index be275977e..6958519de 100644 --- a/lib/pleroma/web/ostatus/ostatus_controller.ex +++ b/lib/pleroma/web/ostatus/ostatus_controller.ex @@ -76,41 +76,37 @@ defmodule Pleroma.Web.OStatus.OStatusController do end def notice(%{assigns: %{format: format}} = conn, %{"id" => id}) do - if Pleroma.Config.get([:instance, :static_fe], false) do - Pleroma.Web.StaticFE.StaticFEController.call(conn, :show_notice) - else - with {_, %Activity{} = activity} <- {:activity, Activity.get_by_id_with_object(id)}, - {_, true} <- {:public?, Visibility.is_public?(activity)}, - %User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do - cond do - format == "html" && activity.data["type"] == "Create" -> - %Object{} = object = Object.normalize(activity) - - RedirectController.redirector_with_meta( - conn, - %{ - activity_id: activity.id, - object: object, - url: Router.Helpers.o_status_url(Endpoint, :notice, activity.id), - user: user - } - ) - - format == "html" -> - RedirectController.redirector(conn, nil) - - true -> - represent_activity(conn, format, activity, user) - end - else - reason when reason in [{:public?, false}, {:activity, nil}] -> - conn - |> put_status(404) - |> RedirectController.redirector(nil, 404) - - e -> - e + with {_, %Activity{} = activity} <- {:activity, Activity.get_by_id_with_object(id)}, + {_, true} <- {:public?, Visibility.is_public?(activity)}, + %User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do + cond do + format == "html" && activity.data["type"] == "Create" -> + %Object{} = object = Object.normalize(activity) + + RedirectController.redirector_with_meta( + conn, + %{ + activity_id: activity.id, + object: object, + url: Router.Helpers.o_status_url(Endpoint, :notice, activity.id), + user: user + } + ) + + format == "html" -> + RedirectController.redirector(conn, nil) + + true -> + represent_activity(conn, format, activity, user) end + else + reason when reason in [{:public?, false}, {:activity, nil}] -> + conn + |> put_status(404) + |> RedirectController.redirector(nil, 404) + + e -> + e end end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 8fb4aec13..ecf5f744c 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -495,6 +495,7 @@ defmodule Pleroma.Web.Router do pipeline :ostatus do plug(:accepts, ["html", "xml", "atom", "activity+json", "json"]) + plug(Pleroma.Plugs.StaticFEPlug) end pipeline :oembed do diff --git a/lib/pleroma/web/static_fe/static_fe_controller.ex b/lib/pleroma/web/static_fe/static_fe_controller.ex index 5f69218ce..96e30f317 100644 --- a/lib/pleroma/web/static_fe/static_fe_controller.ex +++ b/lib/pleroma/web/static_fe/static_fe_controller.ex @@ -14,7 +14,6 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do plug(:put_layout, :static_fe) plug(:put_view, Pleroma.Web.StaticFE.StaticFEView) plug(:assign_id) - action_fallback(:not_found) defp get_title(%Object{data: %{"name" => name}}) when is_binary(name), do: name @@ -34,14 +33,15 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do } end + def represent(%Activity{} = activity), do: represent(activity, false) + def represent(%Activity{object: %Object{data: data}} = activity, selected) do {:ok, user} = User.get_or_fetch(activity.object.data["actor"]) link = - if user.local do - Helpers.o_status_url(Pleroma.Web.Endpoint, :notice, activity) - else - data["url"] || data["external_url"] || data["id"] + case user.local do + true -> Helpers.o_status_url(Pleroma.Web.Endpoint, :notice, activity) + _ -> data["url"] || data["external_url"] || data["id"] end %{ @@ -57,28 +57,27 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do } end - def show_notice(%{assigns: %{notice_id: notice_id}} = conn, _params) do + def show(%{assigns: %{notice_id: notice_id}} = conn, _params) do instance_name = Pleroma.Config.get([:instance, :name], "Pleroma") activity = Activity.get_by_id_with_object(notice_id) context = activity.object.data["context"] activities = ActivityPub.fetch_activities_for_context(context, %{}) - represented = + timeline = for a <- Enum.reverse(activities) do represent(a, a.object.id == activity.object.id) end - render(conn, "conversation.html", %{activities: represented, instance_name: instance_name}) + render(conn, "conversation.html", %{activities: timeline, instance_name: instance_name}) end - def show_user(%{assigns: %{username_or_id: username_or_id}} = conn, _params) do + def show(%{assigns: %{username_or_id: username_or_id}} = conn, _params) do instance_name = Pleroma.Config.get([:instance, :name], "Pleroma") %User{} = user = User.get_cached_by_nickname_or_id(username_or_id) timeline = - for activity <- ActivityPub.fetch_user_activities(user, nil, %{}) do - represent(activity, false) - end + ActivityPub.fetch_user_activities(user, nil, %{}) + |> Enum.map(&represent/1) render(conn, "profile.html", %{user: user, timeline: timeline, instance_name: instance_name}) end @@ -89,15 +88,5 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do def assign_id(%{path_info: ["users", user_id]} = conn, _opts), do: assign(conn, :username_or_id, user_id) - def assign_id(%{path_info: [user_id]} = conn, _opts), - do: assign(conn, :username_or_id, user_id) - def assign_id(conn, _opts), do: conn - - # Fallback for unhandled types - def not_found(conn, _opts) do - conn - |> put_status(404) - |> text("Not found") - end end -- cgit v1.2.3 From e8bee35578fbbc442657baa4dee0047906b247a9 Mon Sep 17 00:00:00 2001 From: Phil Hagelberg Date: Sun, 3 Nov 2019 12:29:17 -0800 Subject: Static FE plug should only respond to text/html requests. --- lib/pleroma/plugs/static_fe_plug.ex | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/plugs/static_fe_plug.ex b/lib/pleroma/plugs/static_fe_plug.ex index d3abaf4cc..dcbabc9df 100644 --- a/lib/pleroma/plugs/static_fe_plug.ex +++ b/lib/pleroma/plugs/static_fe_plug.ex @@ -5,9 +5,14 @@ defmodule Pleroma.Plugs.StaticFEPlug do def init(options), do: options + def accepts_html?({"accept", a}), do: String.contains?(a, "text/html") + def accepts_html?({_, _}), do: false + def call(conn, _) do - case Pleroma.Config.get([:instance, :static_fe], false) do - true -> Pleroma.Web.StaticFE.StaticFEController.call(conn, :show) + with true <- Pleroma.Config.get([:instance, :static_fe], false), + {_, _} <- Enum.find(conn.req_headers, &accepts_html?/1) do + Pleroma.Web.StaticFE.StaticFEController.call(conn, :show) + else _ -> conn end end -- cgit v1.2.3 From 8969c5522d0ff4b95705ce8dd1249aa76414fe0e Mon Sep 17 00:00:00 2001 From: Phil Hagelberg Date: Mon, 4 Nov 2019 22:02:10 -0800 Subject: Make many of the improvements suggested in review. --- lib/pleroma/plugs/static_fe_plug.ex | 21 ++++++++++++++------- lib/pleroma/web/static_fe/static_fe_controller.ex | 16 ++++++---------- lib/pleroma/web/static_fe/static_fe_view.ex | 2 ++ lib/pleroma/web/templates/layout/static_fe.html.eex | 2 +- .../static_fe/static_fe/conversation.html.eex | 2 +- .../templates/static_fe/static_fe/profile.html.eex | 2 +- 6 files changed, 25 insertions(+), 20 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/plugs/static_fe_plug.ex b/lib/pleroma/plugs/static_fe_plug.ex index dcbabc9df..2af45e52a 100644 --- a/lib/pleroma/plugs/static_fe_plug.ex +++ b/lib/pleroma/plugs/static_fe_plug.ex @@ -3,17 +3,24 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Plugs.StaticFEPlug do - def init(options), do: options + import Plug.Conn + alias Pleroma.Web.StaticFE.StaticFEController - def accepts_html?({"accept", a}), do: String.contains?(a, "text/html") - def accepts_html?({_, _}), do: false + def init(options), do: options def call(conn, _) do - with true <- Pleroma.Config.get([:instance, :static_fe], false), - {_, _} <- Enum.find(conn.req_headers, &accepts_html?/1) do - Pleroma.Web.StaticFE.StaticFEController.call(conn, :show) + if enabled?() and accepts_html?(conn) do + conn + |> StaticFEController.call(:show) + |> halt() else - _ -> conn + conn end end + + defp enabled?, do: Pleroma.Config.get([:instance, :static_fe], false) + + defp accepts_html?(conn) do + conn |> get_req_header("accept") |> List.first() |> String.contains?("text/html") + end end diff --git a/lib/pleroma/web/static_fe/static_fe_controller.ex b/lib/pleroma/web/static_fe/static_fe_controller.ex index 96e30f317..a00c6db4f 100644 --- a/lib/pleroma/web/static_fe/static_fe_controller.ex +++ b/lib/pleroma/web/static_fe/static_fe_controller.ex @@ -58,28 +58,24 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do end def show(%{assigns: %{notice_id: notice_id}} = conn, _params) do - instance_name = Pleroma.Config.get([:instance, :name], "Pleroma") activity = Activity.get_by_id_with_object(notice_id) - context = activity.object.data["context"] - activities = ActivityPub.fetch_activities_for_context(context, %{}) - timeline = - for a <- Enum.reverse(activities) do - represent(a, a.object.id == activity.object.id) - end + activity.object.data["context"] + |> ActivityPub.fetch_activities_for_context(%{}) + |> Enum.reverse() + |> Enum.map(&represent(&1, &1.object.id == activity.object.id)) - render(conn, "conversation.html", %{activities: timeline, instance_name: instance_name}) + render(conn, "conversation.html", %{activities: timeline}) end def show(%{assigns: %{username_or_id: username_or_id}} = conn, _params) do - instance_name = Pleroma.Config.get([:instance, :name], "Pleroma") %User{} = user = User.get_cached_by_nickname_or_id(username_or_id) timeline = ActivityPub.fetch_user_activities(user, nil, %{}) |> Enum.map(&represent/1) - render(conn, "profile.html", %{user: user, timeline: timeline, instance_name: instance_name}) + render(conn, "profile.html", %{user: user, timeline: timeline}) end def assign_id(%{path_info: ["notice", notice_id]} = conn, _opts), diff --git a/lib/pleroma/web/static_fe/static_fe_view.ex b/lib/pleroma/web/static_fe/static_fe_view.ex index 160261af9..5612a06bb 100644 --- a/lib/pleroma/web/static_fe/static_fe_view.ex +++ b/lib/pleroma/web/static_fe/static_fe_view.ex @@ -36,4 +36,6 @@ defmodule Pleroma.Web.StaticFE.StaticFEView do {:ok, date, _} = DateTime.from_iso8601(date) Strftime.strftime!(date, "%Y/%m/%d %l:%M:%S %p UTC") end + + def instance_name, do: Pleroma.Config.get([:instance, :name], "Pleroma") end diff --git a/lib/pleroma/web/templates/layout/static_fe.html.eex b/lib/pleroma/web/templates/layout/static_fe.html.eex index 62b59f17c..4b889bb19 100644 --- a/lib/pleroma/web/templates/layout/static_fe.html.eex +++ b/lib/pleroma/web/templates/layout/static_fe.html.eex @@ -4,7 +4,7 @@ - <%= Application.get_env(:pleroma, :instance)[:name] %> + <%= Pleroma.Config.get([:instance, :name]) %> diff --git a/lib/pleroma/web/templates/static_fe/static_fe/conversation.html.eex b/lib/pleroma/web/templates/static_fe/static_fe/conversation.html.eex index 7ac4a9e5f..2acd84828 100644 --- a/lib/pleroma/web/templates/static_fe/static_fe/conversation.html.eex +++ b/lib/pleroma/web/templates/static_fe/static_fe/conversation.html.eex @@ -1,5 +1,5 @@
-

<%= link @instance_name, to: "/" %>

+

<%= link instance_name(), to: "/" %>

diff --git a/lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex b/lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex index 9b3d0509e..fa3df3b4e 100644 --- a/lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex +++ b/lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex @@ -1,5 +1,5 @@
-

<%= link @instance_name, to: "/" %>

+

<%= link instance_name(), to: "/" %>

-- cgit v1.2.3 From df2f59be911acd4626886befbc0c6bcd75752080 Mon Sep 17 00:00:00 2001 From: Phil Hagelberg Date: Mon, 4 Nov 2019 22:49:05 -0800 Subject: Pagination for user profiles. --- lib/pleroma/web/static_fe/static_fe_controller.ex | 22 ++++++++++++++++++---- .../templates/static_fe/static_fe/profile.html.eex | 9 +++++++++ 2 files changed, 27 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/static_fe/static_fe_controller.ex b/lib/pleroma/web/static_fe/static_fe_controller.ex index a00c6db4f..9f4eeaa36 100644 --- a/lib/pleroma/web/static_fe/static_fe_controller.ex +++ b/lib/pleroma/web/static_fe/static_fe_controller.ex @@ -15,6 +15,8 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do plug(:put_view, Pleroma.Web.StaticFE.StaticFEView) plug(:assign_id) + @page_keys ["max_id", "min_id", "limit", "since_id", "order"] + defp get_title(%Object{data: %{"name" => name}}) when is_binary(name), do: name @@ -53,7 +55,8 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do published: data["published"], sensitive: data["sensitive"], selected: selected, - counts: get_counts(activity) + counts: get_counts(activity), + id: activity.id } end @@ -68,14 +71,25 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do render(conn, "conversation.html", %{activities: timeline}) end - def show(%{assigns: %{username_or_id: username_or_id}} = conn, _params) do + def show(%{assigns: %{username_or_id: username_or_id}} = conn, params) do %User{} = user = User.get_cached_by_nickname_or_id(username_or_id) timeline = - ActivityPub.fetch_user_activities(user, nil, %{}) + ActivityPub.fetch_user_activities(user, nil, Map.take(params, @page_keys)) |> Enum.map(&represent/1) - render(conn, "profile.html", %{user: user, timeline: timeline}) + prev_page_id = + (params["min_id"] || params["max_id"]) && + List.first(timeline) && List.first(timeline).id + + next_page_id = List.last(timeline) && List.last(timeline).id + + render(conn, "profile.html", %{ + user: user, + timeline: timeline, + prev_page_id: prev_page_id, + next_page_id: next_page_id + }) end def assign_id(%{path_info: ["notice", notice_id]} = conn, _opts), diff --git a/lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex b/lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex index fa3df3b4e..94063c92d 100644 --- a/lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex +++ b/lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex @@ -18,5 +18,14 @@ <%= for activity <- @timeline do %> <%= render("_notice.html", Map.put(activity, :selected, false)) %> <% end %> +

+ <%= if @prev_page_id do %> + <%= link "«", to: "?min_id=" <> @prev_page_id %> + <% end %> + <%= if @prev_page_id && @next_page_id, do: " | " %> + <%= if @next_page_id do %> + <%= link "»", to: "?max_id=" <> @next_page_id %> + <% end %> +

-- cgit v1.2.3 From 828259fb6517d35b5f950e07601bab0bdc5b5efd Mon Sep 17 00:00:00 2001 From: Phil Hagelberg Date: Mon, 4 Nov 2019 22:56:51 -0800 Subject: Catch 404s. --- lib/pleroma/web/static_fe/static_fe_controller.ex | 65 ++++++++++++++--------- 1 file changed, 39 insertions(+), 26 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/static_fe/static_fe_controller.ex b/lib/pleroma/web/static_fe/static_fe_controller.ex index 9f4eeaa36..4798cad24 100644 --- a/lib/pleroma/web/static_fe/static_fe_controller.ex +++ b/lib/pleroma/web/static_fe/static_fe_controller.ex @@ -61,35 +61,48 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do end def show(%{assigns: %{notice_id: notice_id}} = conn, _params) do - activity = Activity.get_by_id_with_object(notice_id) - timeline = - activity.object.data["context"] - |> ActivityPub.fetch_activities_for_context(%{}) - |> Enum.reverse() - |> Enum.map(&represent(&1, &1.object.id == activity.object.id)) - - render(conn, "conversation.html", %{activities: timeline}) + case Activity.get_by_id_with_object(notice_id) do + %Activity{} = activity -> + timeline = + activity.object.data["context"] + |> ActivityPub.fetch_activities_for_context(%{}) + |> Enum.reverse() + |> Enum.map(&represent(&1, &1.object.id == activity.object.id)) + + render(conn, "conversation.html", %{activities: timeline}) + + _ -> + conn + |> put_status(404) + |> render_error(:not_found, "Notice not found") + end end def show(%{assigns: %{username_or_id: username_or_id}} = conn, params) do - %User{} = user = User.get_cached_by_nickname_or_id(username_or_id) - - timeline = - ActivityPub.fetch_user_activities(user, nil, Map.take(params, @page_keys)) - |> Enum.map(&represent/1) - - prev_page_id = - (params["min_id"] || params["max_id"]) && - List.first(timeline) && List.first(timeline).id - - next_page_id = List.last(timeline) && List.last(timeline).id - - render(conn, "profile.html", %{ - user: user, - timeline: timeline, - prev_page_id: prev_page_id, - next_page_id: next_page_id - }) + case User.get_cached_by_nickname_or_id(username_or_id) do + %User{} = user -> + timeline = + ActivityPub.fetch_user_activities(user, nil, Map.take(params, @page_keys)) + |> Enum.map(&represent/1) + + prev_page_id = + (params["min_id"] || params["max_id"]) && + List.first(timeline) && List.first(timeline).id + + next_page_id = List.last(timeline) && List.last(timeline).id + + render(conn, "profile.html", %{ + user: user, + timeline: timeline, + prev_page_id: prev_page_id, + next_page_id: next_page_id + }) + + _ -> + conn + |> put_status(404) + |> render_error(:not_found, "User not found") + end end def assign_id(%{path_info: ["notice", notice_id]} = conn, _opts), -- cgit v1.2.3 From bfd5d798262f0ecc7ebc260d92c766d39c0766de Mon Sep 17 00:00:00 2001 From: Phil Hagelberg Date: Tue, 5 Nov 2019 21:28:36 -0800 Subject: Include metadata in static FE conversations and profiles. --- lib/pleroma/web/static_fe/static_fe_controller.ex | 11 +++++++++-- lib/pleroma/web/templates/layout/static_fe.html.eex | 5 ++--- 2 files changed, 11 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/static_fe/static_fe_controller.ex b/lib/pleroma/web/static_fe/static_fe_controller.ex index 4798cad24..10bd3fecd 100644 --- a/lib/pleroma/web/static_fe/static_fe_controller.ex +++ b/lib/pleroma/web/static_fe/static_fe_controller.ex @@ -9,6 +9,7 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do alias Pleroma.Object alias Pleroma.User alias Pleroma.Web.ActivityPub.ActivityPub + alias Pleroma.Web.Metadata alias Pleroma.Web.Router.Helpers plug(:put_layout, :static_fe) @@ -63,13 +64,16 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do def show(%{assigns: %{notice_id: notice_id}} = conn, _params) do case Activity.get_by_id_with_object(notice_id) do %Activity{} = activity -> + %User{} = user = User.get_by_ap_id(activity.object.data["actor"]) + meta = Metadata.build_tags(%{activity_id: notice_id, object: activity.object, user: user}) + timeline = activity.object.data["context"] |> ActivityPub.fetch_activities_for_context(%{}) |> Enum.reverse() |> Enum.map(&represent(&1, &1.object.id == activity.object.id)) - render(conn, "conversation.html", %{activities: timeline}) + render(conn, "conversation.html", %{activities: timeline, meta: meta}) _ -> conn @@ -81,6 +85,8 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do def show(%{assigns: %{username_or_id: username_or_id}} = conn, params) do case User.get_cached_by_nickname_or_id(username_or_id) do %User{} = user -> + meta = Metadata.build_tags(%{user: user}) + timeline = ActivityPub.fetch_user_activities(user, nil, Map.take(params, @page_keys)) |> Enum.map(&represent/1) @@ -95,7 +101,8 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do user: user, timeline: timeline, prev_page_id: prev_page_id, - next_page_id: next_page_id + next_page_id: next_page_id, + meta: meta }) _ -> diff --git a/lib/pleroma/web/templates/layout/static_fe.html.eex b/lib/pleroma/web/templates/layout/static_fe.html.eex index 4b889bb19..5d820bb4b 100644 --- a/lib/pleroma/web/templates/layout/static_fe.html.eex +++ b/lib/pleroma/web/templates/layout/static_fe.html.eex @@ -3,9 +3,8 @@ - - <%= Pleroma.Config.get([:instance, :name]) %> - + <%= Pleroma.Config.get([:instance, :name]) %> + <%= Phoenix.HTML.raw(@meta || "") %> -- cgit v1.2.3 From e27c61218d292c5fbf268f27e81dbe22f93ba90f Mon Sep 17 00:00:00 2001 From: Phil Hagelberg Date: Tue, 5 Nov 2019 21:37:46 -0800 Subject: Expand subject content automatically when config is set. --- lib/pleroma/web/static_fe/static_fe_view.ex | 7 +++++++ lib/pleroma/web/templates/static_fe/static_fe/_notice.html.eex | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/static_fe/static_fe_view.ex b/lib/pleroma/web/static_fe/static_fe_view.ex index 5612a06bb..72e667728 100644 --- a/lib/pleroma/web/static_fe/static_fe_view.ex +++ b/lib/pleroma/web/static_fe/static_fe_view.ex @@ -38,4 +38,11 @@ defmodule Pleroma.Web.StaticFE.StaticFEView do end def instance_name, do: Pleroma.Config.get([:instance, :name], "Pleroma") + + def open_content? do + Pleroma.Config.get( + [:frontend_configurations, :collapse_message_with_subjects], + true + ) + end end diff --git a/lib/pleroma/web/templates/static_fe/static_fe/_notice.html.eex b/lib/pleroma/web/templates/static_fe/static_fe/_notice.html.eex index 2a46dadb4..df5e5eedd 100644 --- a/lib/pleroma/web/templates/static_fe/static_fe/_notice.html.eex +++ b/lib/pleroma/web/templates/static_fe/static_fe/_notice.html.eex @@ -5,7 +5,7 @@ <%= render("_user_card.html", %{user: @user}) %>
<%= if @title != "" do %> -
+
open<% end %>> <%= raw @title %>
<%= raw @content %>
-- cgit v1.2.3 From b0080fa73010cda34215baeee230481b5c56dbca Mon Sep 17 00:00:00 2001 From: Phil Hagelberg Date: Tue, 5 Nov 2019 22:00:19 -0800 Subject: Render errors in HTML, not with JS. --- lib/pleroma/web/static_fe/static_fe_controller.ex | 4 ++-- lib/pleroma/web/templates/layout/static_fe.html.eex | 2 +- lib/pleroma/web/templates/static_fe/static_fe/error.html.eex | 7 +++++++ 3 files changed, 10 insertions(+), 3 deletions(-) create mode 100644 lib/pleroma/web/templates/static_fe/static_fe/error.html.eex (limited to 'lib') diff --git a/lib/pleroma/web/static_fe/static_fe_controller.ex b/lib/pleroma/web/static_fe/static_fe_controller.ex index 10bd3fecd..0be47d6b3 100644 --- a/lib/pleroma/web/static_fe/static_fe_controller.ex +++ b/lib/pleroma/web/static_fe/static_fe_controller.ex @@ -78,7 +78,7 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do _ -> conn |> put_status(404) - |> render_error(:not_found, "Notice not found") + |> render("error.html", %{message: "Post not found.", meta: ""}) end end @@ -108,7 +108,7 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do _ -> conn |> put_status(404) - |> render_error(:not_found, "User not found") + |> render("error.html", %{message: "User not found.", meta: ""}) end end diff --git a/lib/pleroma/web/templates/layout/static_fe.html.eex b/lib/pleroma/web/templates/layout/static_fe.html.eex index 5d820bb4b..819632cec 100644 --- a/lib/pleroma/web/templates/layout/static_fe.html.eex +++ b/lib/pleroma/web/templates/layout/static_fe.html.eex @@ -4,7 +4,7 @@ <%= Pleroma.Config.get([:instance, :name]) %> - <%= Phoenix.HTML.raw(@meta || "") %> + <%= Phoenix.HTML.raw(assigns[:meta] || "") %> diff --git a/lib/pleroma/web/templates/static_fe/static_fe/error.html.eex b/lib/pleroma/web/templates/static_fe/static_fe/error.html.eex new file mode 100644 index 000000000..d98a1eba7 --- /dev/null +++ b/lib/pleroma/web/templates/static_fe/static_fe/error.html.eex @@ -0,0 +1,7 @@ +
+

<%= gettext("Oops") %>

+
+ +
+

<%= @message %>

+
-- cgit v1.2.3 From 886a07ba573a7dc566f51cfb44e69dac49f401cd Mon Sep 17 00:00:00 2001 From: Phil Hagelberg Date: Thu, 7 Nov 2019 19:31:28 -0800 Subject: Move static_fe config to its own section instead of in :instance. --- lib/pleroma/plugs/static_fe_plug.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/plugs/static_fe_plug.ex b/lib/pleroma/plugs/static_fe_plug.ex index 2af45e52a..b3fb3c582 100644 --- a/lib/pleroma/plugs/static_fe_plug.ex +++ b/lib/pleroma/plugs/static_fe_plug.ex @@ -18,7 +18,7 @@ defmodule Pleroma.Plugs.StaticFEPlug do end end - defp enabled?, do: Pleroma.Config.get([:instance, :static_fe], false) + defp enabled?, do: Pleroma.Config.get([:static_fe, :enabled], false) defp accepts_html?(conn) do conn |> get_req_header("accept") |> List.first() |> String.contains?("text/html") -- cgit v1.2.3 From 4729027f91852a921cf74f507fbc1ac8761a07f0 Mon Sep 17 00:00:00 2001 From: Phil Hagelberg Date: Thu, 7 Nov 2019 21:43:21 -0800 Subject: Prevent non-local notices from rendering. --- lib/pleroma/web/static_fe/static_fe_controller.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/static_fe/static_fe_controller.ex b/lib/pleroma/web/static_fe/static_fe_controller.ex index 0be47d6b3..66d2d0367 100644 --- a/lib/pleroma/web/static_fe/static_fe_controller.ex +++ b/lib/pleroma/web/static_fe/static_fe_controller.ex @@ -63,7 +63,7 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do def show(%{assigns: %{notice_id: notice_id}} = conn, _params) do case Activity.get_by_id_with_object(notice_id) do - %Activity{} = activity -> + %Activity{local: true} = activity -> %User{} = user = User.get_by_ap_id(activity.object.data["actor"]) meta = Metadata.build_tags(%{activity_id: notice_id, object: activity.object, user: user}) -- cgit v1.2.3 From ef7c3bdc7a5d4047eca15b8469e1f7d7ab3bd39e Mon Sep 17 00:00:00 2001 From: Phil Hagelberg Date: Fri, 8 Nov 2019 08:55:32 -0800 Subject: Add some further test cases. Including like ... private visibility, cos that's super important. --- lib/pleroma/web/static_fe/static_fe_controller.ex | 28 ++++++++++++----------- 1 file changed, 15 insertions(+), 13 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/static_fe/static_fe_controller.ex b/lib/pleroma/web/static_fe/static_fe_controller.ex index 66d2d0367..5e60c82b0 100644 --- a/lib/pleroma/web/static_fe/static_fe_controller.ex +++ b/lib/pleroma/web/static_fe/static_fe_controller.ex @@ -9,6 +9,7 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do alias Pleroma.Object alias Pleroma.User alias Pleroma.Web.ActivityPub.ActivityPub + alias Pleroma.Web.ActivityPub.Visibility alias Pleroma.Web.Metadata alias Pleroma.Web.Router.Helpers @@ -62,19 +63,20 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do end def show(%{assigns: %{notice_id: notice_id}} = conn, _params) do - case Activity.get_by_id_with_object(notice_id) do - %Activity{local: true} = activity -> - %User{} = user = User.get_by_ap_id(activity.object.data["actor"]) - meta = Metadata.build_tags(%{activity_id: notice_id, object: activity.object, user: user}) - - timeline = - activity.object.data["context"] - |> ActivityPub.fetch_activities_for_context(%{}) - |> Enum.reverse() - |> Enum.map(&represent(&1, &1.object.id == activity.object.id)) - - render(conn, "conversation.html", %{activities: timeline, meta: meta}) - + with %Activity{local: true} = activity <- + Activity.get_by_id_with_object(notice_id), + true <- Visibility.is_public?(activity.object), + %User{} = user <- User.get_by_ap_id(activity.object.data["actor"]) do + meta = Metadata.build_tags(%{activity_id: notice_id, object: activity.object, user: user}) + + timeline = + activity.object.data["context"] + |> ActivityPub.fetch_activities_for_context(%{}) + |> Enum.reverse() + |> Enum.map(&represent(&1, &1.object.id == activity.object.id)) + + render(conn, "conversation.html", %{activities: timeline, meta: meta}) + else _ -> conn |> put_status(404) -- cgit v1.2.3 From 3cc49cdb78bf14897030c476b00fb07064f2d74e Mon Sep 17 00:00:00 2001 From: Phil Hagelberg Date: Sat, 9 Nov 2019 18:26:19 -0800 Subject: Formatter moved to new module. --- lib/pleroma/web/static_fe/static_fe_view.ex | 1 - 1 file changed, 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/static_fe/static_fe_view.ex b/lib/pleroma/web/static_fe/static_fe_view.ex index 72e667728..821ece9a9 100644 --- a/lib/pleroma/web/static_fe/static_fe_view.ex +++ b/lib/pleroma/web/static_fe/static_fe_view.ex @@ -11,7 +11,6 @@ defmodule Pleroma.Web.StaticFE.StaticFEView do alias Pleroma.Web.Endpoint alias Pleroma.Web.Gettext alias Pleroma.Web.MediaProxy - alias Pleroma.Formatter alias Pleroma.Web.Metadata.Utils alias Pleroma.Web.Router.Helpers -- cgit v1.2.3 From 9d0b989521dc181eea2e5912445df1c543457a90 Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Fri, 8 Nov 2019 09:23:24 +0300 Subject: add subject to atom feed --- lib/pleroma/web/activity_pub/activity_pub.ex | 1 - lib/pleroma/web/feed/feed_controller.ex | 21 ++++++------- lib/pleroma/web/feed/feed_view.ex | 35 ++++++++++++---------- .../controllers/timeline_controller.ex | 2 -- .../web/templates/feed/feed/_activity.xml.eex | 8 +++-- lib/pleroma/web/templates/feed/feed/feed.xml.eex | 2 +- 6 files changed, 36 insertions(+), 33 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 51a9c6169..65dd251f3 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -568,7 +568,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do |> fetch_activities_query(opts) |> restrict_unlisted() |> Pagination.fetch_paginated(opts, pagination) - |> Enum.reverse() end @valid_visibilities ~w[direct unlisted public private] diff --git a/lib/pleroma/web/feed/feed_controller.ex b/lib/pleroma/web/feed/feed_controller.ex index d91ecef9c..d0e23007d 100644 --- a/lib/pleroma/web/feed/feed_controller.ex +++ b/lib/pleroma/web/feed/feed_controller.ex @@ -33,21 +33,22 @@ defmodule Pleroma.Web.Feed.FeedController do def feed(conn, %{"nickname" => nickname} = params) do with {_, %User{} = user} <- {:fetch_user, User.get_cached_by_nickname(nickname)} do - query_params = - params - |> Map.take(["max_id"]) - |> Map.put("type", ["Create"]) - |> Map.put("whole_db", true) - |> Map.put("actor_id", user.ap_id) - activities = - query_params + %{ + "type" => ["Create"], + "whole_db" => true, + "actor_id" => user.ap_id + } + |> Map.merge(Map.take(params, ["max_id"])) |> ActivityPub.fetch_public_activities() - |> Enum.reverse() conn |> put_resp_content_type("application/atom+xml") - |> render("feed.xml", user: user, activities: activities) + |> render("feed.xml", + user: user, + activities: activities, + feed_config: Pleroma.Config.get([:feed]) + ) end end diff --git a/lib/pleroma/web/feed/feed_view.ex b/lib/pleroma/web/feed/feed_view.ex index 5eef1e757..bb1332fd3 100644 --- a/lib/pleroma/web/feed/feed_view.ex +++ b/lib/pleroma/web/feed/feed_view.ex @@ -6,12 +6,23 @@ defmodule Pleroma.Web.Feed.FeedView do use Phoenix.HTML use Pleroma.Web, :view + alias Pleroma.Formatter alias Pleroma.Object alias Pleroma.User alias Pleroma.Web.MediaProxy require Pleroma.Constants + def prepare_activity(activity) do + object = activity_object(activity) + + %{ + activity: activity, + data: Map.get(object, :data), + object: object + } + end + def most_recent_update(activities, user) do (List.first(activities) || user).updated_at |> NaiveDateTime.to_iso8601() @@ -23,31 +34,23 @@ defmodule Pleroma.Web.Feed.FeedView do |> MediaProxy.url() end - def last_activity(activities) do - List.last(activities) - end + def last_activity(activities), do: List.last(activities) - def activity_object(activity) do - Object.normalize(activity) - end + def activity_object(activity), do: Object.normalize(activity) - def activity_object_data(activity) do - activity - |> activity_object() - |> Map.get(:data) + def activity_title(%{data: %{"content" => content}}, opts \\ %{}) do + content + |> Formatter.truncate(opts[:max_length], opts[:omission]) + |> escape() end - def activity_content(activity) do - content = activity_object_data(activity)["content"] - + def activity_content(%{data: %{"content" => content}}) do content |> String.replace(~r/[\n\r]/, "") |> escape() end - def activity_context(activity) do - activity.data["context"] - end + def activity_context(activity), do: activity.data["context"] def attachment_href(attachment) do attachment["url"] diff --git a/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex b/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex index f2d2d3ccb..384159336 100644 --- a/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex @@ -71,7 +71,6 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do |> Map.put("blocking_user", user) |> Map.put("muting_user", user) |> ActivityPub.fetch_public_activities() - |> Enum.reverse() conn |> add_link_headers(activities, %{"local" => local_only}) @@ -110,7 +109,6 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do |> Map.put("tag_all", tag_all) |> Map.put("tag_reject", tag_reject) |> ActivityPub.fetch_public_activities() - |> Enum.reverse() conn |> add_link_headers(activities, %{"local" => local_only}) diff --git a/lib/pleroma/web/templates/feed/feed/_activity.xml.eex b/lib/pleroma/web/templates/feed/feed/_activity.xml.eex index d1f5e903c..514eacaed 100644 --- a/lib/pleroma/web/templates/feed/feed/_activity.xml.eex +++ b/lib/pleroma/web/templates/feed/feed/_activity.xml.eex @@ -2,11 +2,13 @@ http://activitystrea.ms/schema/1.0/note http://activitystrea.ms/schema/1.0/post <%= @data["id"] %> - <%= "New note by #{@user.nickname}" %> - <%= activity_content(@activity) %> + <%= activity_title(@object, Keyword.get(@feed_config, :post_title, %{})) %> + <%= activity_content(@object) %> <%= @data["published"] %> <%= @data["published"] %> - <%= activity_context(@activity) %> + + <%= activity_context(@activity) %> + <%= if @data["summary"] do %> diff --git a/lib/pleroma/web/templates/feed/feed/feed.xml.eex b/lib/pleroma/web/templates/feed/feed/feed.xml.eex index 45df9dc09..5ae36d345 100644 --- a/lib/pleroma/web/templates/feed/feed/feed.xml.eex +++ b/lib/pleroma/web/templates/feed/feed/feed.xml.eex @@ -19,6 +19,6 @@ <% end %> <%= for activity <- @activities do %> - <%= render @view_module, "_activity.xml", Map.merge(assigns, %{activity: activity, data: activity_object_data(activity)}) %> + <%= render @view_module, "_activity.xml", Map.merge(assigns, prepare_activity(activity)) %> <% end %> -- cgit v1.2.3 From 6a4201e0b444748318845caddf0e972d0fac87d7 Mon Sep 17 00:00:00 2001 From: Alexander Date: Sun, 10 Nov 2019 22:54:37 +0300 Subject: fix for migrate task --- lib/mix/tasks/pleroma/config.ex | 2 +- lib/pleroma/docs/json.ex | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/config.ex b/lib/mix/tasks/pleroma/config.ex index 11e4fde43..0e21408b2 100644 --- a/lib/mix/tasks/pleroma/config.ex +++ b/lib/mix/tasks/pleroma/config.ex @@ -45,7 +45,7 @@ defmodule Mix.Tasks.Pleroma.Config do if Pleroma.Config.get([:instance, :dynamic_configuration]) do config_path = "config/#{env}.exported_from_db.secret.exs" - {:ok, file} = File.open(config_path, [:write]) + {:ok, file} = File.open(config_path, [:write, :utf8]) IO.write(file, "use Mix.Config\r\n") Repo.all(Config) diff --git a/lib/pleroma/docs/json.ex b/lib/pleroma/docs/json.ex index 18ba01d58..f2a56d845 100644 --- a/lib/pleroma/docs/json.ex +++ b/lib/pleroma/docs/json.ex @@ -5,7 +5,7 @@ defmodule Pleroma.Docs.JSON do def process(descriptions) do config_path = "docs/generate_config.json" - with {:ok, file} <- File.open(config_path, [:write]), + with {:ok, file} <- File.open(config_path, [:write, :utf8]), json <- generate_json(descriptions), :ok <- IO.write(file, json), :ok <- File.close(file) do -- cgit v1.2.3 From 31343e4321a3c4053b66a1d6dc3da0e42dbdd972 Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Mon, 11 Nov 2019 19:06:09 +0900 Subject: Code style fixes --- lib/pleroma/activity.ex | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex index 7b77f72c2..7e283df32 100644 --- a/lib/pleroma/activity.ex +++ b/lib/pleroma/activity.ex @@ -92,12 +92,7 @@ defmodule Pleroma.Activity do def with_joined_user_actor(query, join_type \\ :inner) do join(query, join_type, [activity], u in User, - on: - fragment( - "? = ?->>'actor'", - u.ap_id, - activity.data - ), + on: u.ap_id == activity.actor, as: :user_actor ) end -- cgit v1.2.3 From 8521553ad92981e9939ce6ce2208db685ecd068c Mon Sep 17 00:00:00 2001 From: lain Date: Mon, 11 Nov 2019 12:37:13 +0100 Subject: User: Don't let deactivated users authenticate. --- lib/pleroma/user.ex | 3 +++ 1 file changed, 3 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index f8c2db1e1..fcb1d5143 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -124,6 +124,9 @@ defmodule Pleroma.User do timestamps() end + @doc "Returns if the user should be allowed to authenticate" + def auth_active?(%User{deactivated: true}), do: false + def auth_active?(%User{confirmation_pending: true}), do: !Pleroma.Config.get([:instance, :account_activation_required]) -- cgit v1.2.3 From f6056e9c9cdb280238845e4c9a0d2a1fb82cab78 Mon Sep 17 00:00:00 2001 From: lain Date: Mon, 11 Nov 2019 12:43:46 +0100 Subject: UserEnabledPlug: Don't authenticate unconfirmed users. --- lib/pleroma/plugs/user_enabled_plug.ex | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/plugs/user_enabled_plug.ex b/lib/pleroma/plugs/user_enabled_plug.ex index fbb4bf115..8d102ee5b 100644 --- a/lib/pleroma/plugs/user_enabled_plug.ex +++ b/lib/pleroma/plugs/user_enabled_plug.ex @@ -10,9 +10,13 @@ defmodule Pleroma.Plugs.UserEnabledPlug do options end - def call(%{assigns: %{user: %User{deactivated: true}}} = conn, _) do - conn - |> assign(:user, nil) + def call(%{assigns: %{user: %User{} = user}} = conn, _) do + if User.auth_active?(user) do + conn + else + conn + |> assign(:user, nil) + end end def call(conn, _) do -- cgit v1.2.3 From 94627baa5cca524fe0c4f7043e25d71ed245626a Mon Sep 17 00:00:00 2001 From: Steven Fuchs Date: Mon, 11 Nov 2019 12:13:06 +0000 Subject: New rate limiter --- lib/pleroma/application.ex | 3 +- lib/pleroma/plugs/rate_limiter.ex | 131 ------------ .../plugs/rate_limiter/limiter_supervisor.ex | 44 ++++ lib/pleroma/plugs/rate_limiter/rate_limiter.ex | 227 +++++++++++++++++++++ lib/pleroma/plugs/rate_limiter/supervisor.ex | 16 ++ .../mastodon_api/controllers/account_controller.ex | 6 +- .../mastodon_api/controllers/auth_controller.ex | 2 +- .../mastodon_api/controllers/search_controller.ex | 2 +- .../mastodon_api/controllers/status_controller.ex | 6 +- .../web/mongooseim/mongoose_im_controller.ex | 4 +- lib/pleroma/web/oauth/oauth_controller.ex | 3 +- lib/pleroma/web/ostatus/ostatus_controller.ex | 5 +- .../pleroma_api/controllers/account_controller.ex | 2 +- 13 files changed, 305 insertions(+), 146 deletions(-) delete mode 100644 lib/pleroma/plugs/rate_limiter.ex create mode 100644 lib/pleroma/plugs/rate_limiter/limiter_supervisor.ex create mode 100644 lib/pleroma/plugs/rate_limiter/rate_limiter.ex create mode 100644 lib/pleroma/plugs/rate_limiter/supervisor.ex (limited to 'lib') diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index d681eecc8..2b6a55f98 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -36,7 +36,8 @@ defmodule Pleroma.Application do Pleroma.Emoji, Pleroma.Captcha, Pleroma.Daemons.ScheduledActivityDaemon, - Pleroma.Daemons.ActivityExpirationDaemon + Pleroma.Daemons.ActivityExpirationDaemon, + Pleroma.Plugs.RateLimiter.Supervisor ] ++ cachex_children() ++ hackney_pool_children() ++ diff --git a/lib/pleroma/plugs/rate_limiter.ex b/lib/pleroma/plugs/rate_limiter.ex deleted file mode 100644 index 31388f574..000000000 --- a/lib/pleroma/plugs/rate_limiter.ex +++ /dev/null @@ -1,131 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Plugs.RateLimiter do - @moduledoc """ - - ## Configuration - - A keyword list of rate limiters where a key is a limiter name and value is the limiter configuration. The basic configuration is a tuple where: - - * The first element: `scale` (Integer). The time scale in milliseconds. - * The second element: `limit` (Integer). How many requests to limit in the time scale provided. - - It is also possible to have different limits for unauthenticated and authenticated users: the keyword value must be a list of two tuples where the first one is a config for unauthenticated users and the second one is for authenticated. - - To disable a limiter set its value to `nil`. - - ### Example - - config :pleroma, :rate_limit, - one: {1000, 10}, - two: [{10_000, 10}, {10_000, 50}], - foobar: nil - - Here we have three limiters: - - * `one` which is not over 10req/1s - * `two` which has two limits: 10req/10s for unauthenticated users and 50req/10s for authenticated users - * `foobar` which is disabled - - ## Usage - - AllowedSyntax: - - plug(Pleroma.Plugs.RateLimiter, :limiter_name) - plug(Pleroma.Plugs.RateLimiter, {:limiter_name, options}) - - Allowed options: - - * `bucket_name` overrides bucket name (e.g. to have a separate limit for a set of actions) - * `params` appends values of specified request params (e.g. ["id"]) to bucket name - - Inside a controller: - - plug(Pleroma.Plugs.RateLimiter, :one when action == :one) - plug(Pleroma.Plugs.RateLimiter, :two when action in [:two, :three]) - - plug( - Pleroma.Plugs.RateLimiter, - {:status_id_action, bucket_name: "status_id_action:fav_unfav", params: ["id"]} - when action in ~w(fav_status unfav_status)a - ) - - or inside a router pipeline: - - pipeline :api do - ... - plug(Pleroma.Plugs.RateLimiter, :one) - ... - end - """ - import Pleroma.Web.TranslationHelpers - import Plug.Conn - - alias Pleroma.User - - def init(limiter_name) when is_atom(limiter_name) do - init({limiter_name, []}) - end - - def init({limiter_name, opts}) do - case Pleroma.Config.get([:rate_limit, limiter_name]) do - nil -> nil - config -> {limiter_name, config, opts} - end - end - - # Do not limit if there is no limiter configuration - def call(conn, nil), do: conn - - def call(conn, settings) do - case check_rate(conn, settings) do - {:ok, _count} -> - conn - - {:error, _count} -> - render_throttled_error(conn) - end - end - - defp bucket_name(conn, limiter_name, opts) do - bucket_name = opts[:bucket_name] || limiter_name - - if params_names = opts[:params] do - params_values = for p <- Enum.sort(params_names), do: conn.params[p] - Enum.join([bucket_name] ++ params_values, ":") - else - bucket_name - end - end - - defp check_rate( - %{assigns: %{user: %User{id: user_id}}} = conn, - {limiter_name, [_, {scale, limit}], opts} - ) do - bucket_name = bucket_name(conn, limiter_name, opts) - ExRated.check_rate("#{bucket_name}:#{user_id}", scale, limit) - end - - defp check_rate(conn, {limiter_name, [{scale, limit} | _], opts}) do - bucket_name = bucket_name(conn, limiter_name, opts) - ExRated.check_rate("#{bucket_name}:#{ip(conn)}", scale, limit) - end - - defp check_rate(conn, {limiter_name, {scale, limit}, opts}) do - check_rate(conn, {limiter_name, [{scale, limit}, {scale, limit}], opts}) - end - - def ip(%{remote_ip: remote_ip}) do - remote_ip - |> Tuple.to_list() - |> Enum.join(".") - end - - defp render_throttled_error(conn) do - conn - |> render_error(:too_many_requests, "Throttled") - |> halt() - end -end diff --git a/lib/pleroma/plugs/rate_limiter/limiter_supervisor.ex b/lib/pleroma/plugs/rate_limiter/limiter_supervisor.ex new file mode 100644 index 000000000..187582ede --- /dev/null +++ b/lib/pleroma/plugs/rate_limiter/limiter_supervisor.ex @@ -0,0 +1,44 @@ +defmodule Pleroma.Plugs.RateLimiter.LimiterSupervisor do + use DynamicSupervisor + + import Cachex.Spec + + def start_link(init_arg) do + DynamicSupervisor.start_link(__MODULE__, init_arg, name: __MODULE__) + end + + def add_limiter(limiter_name, expiration) do + {:ok, _pid} = + DynamicSupervisor.start_child( + __MODULE__, + %{ + id: String.to_atom("rl_#{limiter_name}"), + start: + {Cachex, :start_link, + [ + limiter_name, + [ + expiration: + expiration( + default: expiration, + interval: check_interval(expiration), + lazy: true + ) + ] + ]} + } + ) + end + + @impl true + def init(_init_arg) do + DynamicSupervisor.init(strategy: :one_for_one) + end + + defp check_interval(exp) do + (exp / 2) + |> Kernel.trunc() + |> Kernel.min(5000) + |> Kernel.max(1) + end +end diff --git a/lib/pleroma/plugs/rate_limiter/rate_limiter.ex b/lib/pleroma/plugs/rate_limiter/rate_limiter.ex new file mode 100644 index 000000000..d720508c8 --- /dev/null +++ b/lib/pleroma/plugs/rate_limiter/rate_limiter.ex @@ -0,0 +1,227 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Plugs.RateLimiter do + @moduledoc """ + + ## Configuration + + A keyword list of rate limiters where a key is a limiter name and value is the limiter configuration. The basic configuration is a tuple where: + + * The first element: `scale` (Integer). The time scale in milliseconds. + * The second element: `limit` (Integer). How many requests to limit in the time scale provided. + + It is also possible to have different limits for unauthenticated and authenticated users: the keyword value must be a list of two tuples where the first one is a config for unauthenticated users and the second one is for authenticated. + + To disable a limiter set its value to `nil`. + + ### Example + + config :pleroma, :rate_limit, + one: {1000, 10}, + two: [{10_000, 10}, {10_000, 50}], + foobar: nil + + Here we have three limiters: + + * `one` which is not over 10req/1s + * `two` which has two limits: 10req/10s for unauthenticated users and 50req/10s for authenticated users + * `foobar` which is disabled + + ## Usage + + AllowedSyntax: + + plug(Pleroma.Plugs.RateLimiter, name: :limiter_name) + plug(Pleroma.Plugs.RateLimiter, options) # :name is a required option + + Allowed options: + + * `name` required, always used to fetch the limit values from the config + * `bucket_name` overrides name for counting purposes (e.g. to have a separate limit for a set of actions) + * `params` appends values of specified request params (e.g. ["id"]) to bucket name + + Inside a controller: + + plug(Pleroma.Plugs.RateLimiter, [name: :one] when action == :one) + plug(Pleroma.Plugs.RateLimiter, [name: :two] when action in [:two, :three]) + + plug( + Pleroma.Plugs.RateLimiter, + [name: :status_id_action, bucket_name: "status_id_action:fav_unfav", params: ["id"]] + when action in ~w(fav_status unfav_status)a + ) + + or inside a router pipeline: + + pipeline :api do + ... + plug(Pleroma.Plugs.RateLimiter, name: :one) + ... + end + """ + import Pleroma.Web.TranslationHelpers + import Plug.Conn + + alias Pleroma.Plugs.RateLimiter.LimiterSupervisor + alias Pleroma.User + + def init(opts) do + limiter_name = Keyword.get(opts, :name) + + case Pleroma.Config.get([:rate_limit, limiter_name]) do + nil -> + nil + + config -> + name_root = Keyword.get(opts, :bucket_name, limiter_name) + + %{ + name: name_root, + limits: config, + opts: opts + } + end + end + + # Do not limit if there is no limiter configuration + def call(conn, nil), do: conn + + def call(conn, settings) do + settings + |> incorporate_conn_info(conn) + |> check_rate() + |> case do + {:ok, _count} -> + conn + + {:error, _count} -> + render_throttled_error(conn) + end + end + + def inspect_bucket(conn, name_root, settings) do + settings = + settings + |> incorporate_conn_info(conn) + + bucket_name = make_bucket_name(%{settings | name: name_root}) + key_name = make_key_name(settings) + limit = get_limits(settings) + + case Cachex.get(bucket_name, key_name) do + {:error, :no_cache} -> + {:err, :not_found} + + {:ok, nil} -> + {0, limit} + + {:ok, value} -> + {value, limit - value} + end + end + + defp check_rate(settings) do + bucket_name = make_bucket_name(settings) + key_name = make_key_name(settings) + limit = get_limits(settings) + + case Cachex.get_and_update(bucket_name, key_name, &increment_value(&1, limit)) do + {:commit, value} -> + {:ok, value} + + {:ignore, value} -> + {:error, value} + + {:error, :no_cache} -> + initialize_buckets(settings) + check_rate(settings) + end + end + + defp increment_value(nil, _limit), do: {:commit, 1} + + defp increment_value(val, limit) when val >= limit, do: {:ignore, val} + + defp increment_value(val, _limit), do: {:commit, val + 1} + + defp incorporate_conn_info(settings, %{assigns: %{user: %User{id: user_id}}, params: params}) do + Map.merge(settings, %{ + mode: :user, + conn_params: params, + conn_info: "#{user_id}" + }) + end + + defp incorporate_conn_info(settings, %{params: params} = conn) do + Map.merge(settings, %{ + mode: :anon, + conn_params: params, + conn_info: "#{ip(conn)}" + }) + end + + defp ip(%{remote_ip: remote_ip}) do + remote_ip + |> Tuple.to_list() + |> Enum.join(".") + end + + defp render_throttled_error(conn) do + conn + |> render_error(:too_many_requests, "Throttled") + |> halt() + end + + defp make_key_name(settings) do + "" + |> attach_params(settings) + |> attach_identity(settings) + end + + defp get_scale(_, {scale, _}), do: scale + + defp get_scale(:anon, [{scale, _}, {_, _}]), do: scale + + defp get_scale(:user, [{_, _}, {scale, _}]), do: scale + + defp get_limits(%{limits: {_scale, limit}}), do: limit + + defp get_limits(%{mode: :user, limits: [_, {_, limit}]}), do: limit + + defp get_limits(%{limits: [{_, limit}, _]}), do: limit + + defp make_bucket_name(%{mode: :user, name: name_root}), + do: user_bucket_name(name_root) + + defp make_bucket_name(%{mode: :anon, name: name_root}), + do: anon_bucket_name(name_root) + + defp attach_params(input, %{conn_params: conn_params, opts: opts}) do + param_string = + opts + |> Keyword.get(:params, []) + |> Enum.sort() + |> Enum.map(&Map.get(conn_params, &1, "")) + |> Enum.join(":") + + "#{input}#{param_string}" + end + + defp initialize_buckets(%{name: _name, limits: nil}), do: :ok + + defp initialize_buckets(%{name: name, limits: limits}) do + LimiterSupervisor.add_limiter(anon_bucket_name(name), get_scale(:anon, limits)) + LimiterSupervisor.add_limiter(user_bucket_name(name), get_scale(:user, limits)) + end + + defp attach_identity(base, %{mode: :user, conn_info: conn_info}), + do: "user:#{base}:#{conn_info}" + + defp attach_identity(base, %{mode: :anon, conn_info: conn_info}), + do: "ip:#{base}:#{conn_info}" + + defp user_bucket_name(name_root), do: "user:#{name_root}" |> String.to_atom() + defp anon_bucket_name(name_root), do: "anon:#{name_root}" |> String.to_atom() +end diff --git a/lib/pleroma/plugs/rate_limiter/supervisor.ex b/lib/pleroma/plugs/rate_limiter/supervisor.ex new file mode 100644 index 000000000..9672f7876 --- /dev/null +++ b/lib/pleroma/plugs/rate_limiter/supervisor.ex @@ -0,0 +1,16 @@ +defmodule Pleroma.Plugs.RateLimiter.Supervisor do + use Supervisor + + def start_link(opts) do + Supervisor.start_link(__MODULE__, opts, name: __MODULE__) + end + + def init(_args) do + children = [ + Pleroma.Plugs.RateLimiter.LimiterSupervisor + ] + + opts = [strategy: :one_for_one, name: Pleroma.Web.Streamer.Supervisor] + Supervisor.init(children, opts) + end +end diff --git a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex index 73fad519e..5b01b964b 100644 --- a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex @@ -66,9 +66,9 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do @relations [:follow, :unfollow] @needs_account ~W(followers following lists follow unfollow mute unmute block unblock)a - plug(RateLimiter, {:relations_id_action, params: ["id", "uri"]} when action in @relations) - plug(RateLimiter, :relations_actions when action in @relations) - plug(RateLimiter, :app_account_creation when action == :create) + plug(RateLimiter, [name: :relations_id_action, params: ["id", "uri"]] when action in @relations) + plug(RateLimiter, [name: :relations_actions] when action in @relations) + plug(RateLimiter, [name: :app_account_creation] when action == :create) plug(:assign_account_by_id when action in @needs_account) action_fallback(Pleroma.Web.MastodonAPI.FallbackController) diff --git a/lib/pleroma/web/mastodon_api/controllers/auth_controller.ex b/lib/pleroma/web/mastodon_api/controllers/auth_controller.ex index bfd5120ba..d9e51de7f 100644 --- a/lib/pleroma/web/mastodon_api/controllers/auth_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/auth_controller.ex @@ -15,7 +15,7 @@ defmodule Pleroma.Web.MastodonAPI.AuthController do @local_mastodon_name "Mastodon-Local" - plug(Pleroma.Plugs.RateLimiter, :password_reset when action == :password_reset) + plug(Pleroma.Plugs.RateLimiter, [name: :password_reset] when action == :password_reset) @doc "GET /web/login" def login(%{assigns: %{user: %User{}}} = conn, _params) do diff --git a/lib/pleroma/web/mastodon_api/controllers/search_controller.ex b/lib/pleroma/web/mastodon_api/controllers/search_controller.ex index 6cfd68a84..0a929f55b 100644 --- a/lib/pleroma/web/mastodon_api/controllers/search_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/search_controller.ex @@ -22,7 +22,7 @@ defmodule Pleroma.Web.MastodonAPI.SearchController do plug(Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug) - plug(RateLimiter, :search when action in [:search, :search2, :account_search]) + plug(RateLimiter, [name: :search] when action in [:search, :search2, :account_search]) def account_search(%{assigns: %{user: user}} = conn, %{"q" => query} = params) do accounts = User.search(query, search_options(params, user)) diff --git a/lib/pleroma/web/mastodon_api/controllers/status_controller.ex b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex index e5d016f63..74b223cf4 100644 --- a/lib/pleroma/web/mastodon_api/controllers/status_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex @@ -82,17 +82,17 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do plug( RateLimiter, - {:status_id_action, bucket_name: "status_id_action:reblog_unreblog", params: ["id"]} + [name: :status_id_action, bucket_name: "status_id_action:reblog_unreblog", params: ["id"]] when action in ~w(reblog unreblog)a ) plug( RateLimiter, - {:status_id_action, bucket_name: "status_id_action:fav_unfav", params: ["id"]} + [name: :status_id_action, bucket_name: "status_id_action:fav_unfav", params: ["id"]] when action in ~w(favourite unfavourite)a ) - plug(RateLimiter, :statuses_actions when action in @rate_limited_status_actions) + plug(RateLimiter, [name: :statuses_actions] when action in @rate_limited_status_actions) action_fallback(Pleroma.Web.MastodonAPI.FallbackController) diff --git a/lib/pleroma/web/mongooseim/mongoose_im_controller.ex b/lib/pleroma/web/mongooseim/mongoose_im_controller.ex index 6ed181cff..358600e7d 100644 --- a/lib/pleroma/web/mongooseim/mongoose_im_controller.ex +++ b/lib/pleroma/web/mongooseim/mongoose_im_controller.ex @@ -10,8 +10,8 @@ defmodule Pleroma.Web.MongooseIM.MongooseIMController do alias Pleroma.Repo alias Pleroma.User - plug(RateLimiter, :authentication when action in [:user_exists, :check_password]) - plug(RateLimiter, {:authentication, params: ["user"]} when action == :check_password) + plug(RateLimiter, [name: :authentication] when action in [:user_exists, :check_password]) + plug(RateLimiter, [name: :authentication, params: ["user"]] when action == :check_password) def user_exists(conn, %{"user" => username}) do with %User{} <- Repo.get_by(User, nickname: username, local: true) do diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex index fe71aca8c..1b1394787 100644 --- a/lib/pleroma/web/oauth/oauth_controller.ex +++ b/lib/pleroma/web/oauth/oauth_controller.ex @@ -6,6 +6,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do use Pleroma.Web, :controller alias Pleroma.Helpers.UriHelper + alias Pleroma.Plugs.RateLimiter alias Pleroma.Registration alias Pleroma.Repo alias Pleroma.User @@ -24,7 +25,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do plug(:fetch_session) plug(:fetch_flash) - plug(Pleroma.Plugs.RateLimiter, :authentication when action == :create_authorization) + plug(RateLimiter, [name: :authentication] when action == :create_authorization) action_fallback(Pleroma.Web.OAuth.FallbackController) diff --git a/lib/pleroma/web/ostatus/ostatus_controller.ex b/lib/pleroma/web/ostatus/ostatus_controller.ex index 6958519de..12a7c2365 100644 --- a/lib/pleroma/web/ostatus/ostatus_controller.ex +++ b/lib/pleroma/web/ostatus/ostatus_controller.ex @@ -8,6 +8,7 @@ defmodule Pleroma.Web.OStatus.OStatusController do alias Fallback.RedirectController alias Pleroma.Activity alias Pleroma.Object + alias Pleroma.Plugs.RateLimiter alias Pleroma.User alias Pleroma.Web.ActivityPub.ActivityPubController alias Pleroma.Web.ActivityPub.ObjectView @@ -17,8 +18,8 @@ defmodule Pleroma.Web.OStatus.OStatusController do alias Pleroma.Web.Router plug( - Pleroma.Plugs.RateLimiter, - {:ap_routes, params: ["uuid"]} when action in [:object, :activity] + RateLimiter, + [name: :ap_routes, params: ["uuid"]] when action in [:object, :activity] ) plug( diff --git a/lib/pleroma/web/pleroma_api/controllers/account_controller.ex b/lib/pleroma/web/pleroma_api/controllers/account_controller.ex index db6faac83..bc2f1017c 100644 --- a/lib/pleroma/web/pleroma_api/controllers/account_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/account_controller.ex @@ -42,7 +42,7 @@ defmodule Pleroma.Web.PleromaAPI.AccountController do when action != :confirmation_resend ) - plug(RateLimiter, :account_confirmation_resend when action == :confirmation_resend) + plug(RateLimiter, [name: :account_confirmation_resend] when action == :confirmation_resend) plug(:assign_account_by_id when action in [:favourites, :subscribe, :unsubscribe]) plug(:put_view, Pleroma.Web.MastodonAPI.AccountView) -- cgit v1.2.3 From b39b49cc146945ab86db272ae2cd1fe8fad3d9d5 Mon Sep 17 00:00:00 2001 From: href Date: Mon, 11 Nov 2019 19:03:43 +0100 Subject: report federating status in nodeinfo --- lib/pleroma/web/nodeinfo/nodeinfo_controller.ex | 1 + 1 file changed, 1 insertion(+) (limited to 'lib') diff --git a/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex b/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex index d7ae503f6..486b9f6a4 100644 --- a/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex +++ b/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex @@ -46,6 +46,7 @@ defmodule Pleroma.Web.Nodeinfo.NodeinfoController do data |> Map.merge(%{quarantined_instances: quarantined}) + |> Map.put(:enabled, Config.get([:instance, :federating])) else %{} end -- cgit v1.2.3 From 7d101bc9c5f8ffc1d78c8d5e22f630ad0a7d7e1b Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Mon, 11 Nov 2019 18:29:55 -0600 Subject: Fix rendering conversations when there's a malformed status --- lib/pleroma/web/mastodon_api/views/conversation_view.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/mastodon_api/views/conversation_view.ex b/lib/pleroma/web/mastodon_api/views/conversation_view.ex index c5998e661..51d6c0898 100644 --- a/lib/pleroma/web/mastodon_api/views/conversation_view.ex +++ b/lib/pleroma/web/mastodon_api/views/conversation_view.ex @@ -12,7 +12,7 @@ defmodule Pleroma.Web.MastodonAPI.ConversationView do alias Pleroma.Web.MastodonAPI.StatusView def render("participations.json", %{participations: participations, for: user}) do - render_many(participations, __MODULE__, "participation.json", as: :participation, for: user) + safe_render_many(participations, __MODULE__, "participation.json", %{as: :participation, for: user}) end def render("participation.json", %{participation: participation, for: user}) do -- cgit v1.2.3 From e835cd97f6988522dae8f60a0381f0f93c6abb2d Mon Sep 17 00:00:00 2001 From: lain Date: Tue, 12 Nov 2019 12:07:17 +0100 Subject: Containment: Add a catch-all clause to contain_origin. --- lib/pleroma/object/containment.ex | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/object/containment.ex b/lib/pleroma/object/containment.ex index a1f9c1250..25aa32f60 100644 --- a/lib/pleroma/object/containment.ex +++ b/lib/pleroma/object/containment.ex @@ -64,6 +64,8 @@ defmodule Pleroma.Object.Containment do def contain_origin(id, %{"attributedTo" => actor} = params), do: contain_origin(id, Map.put(params, "actor", actor)) + def contain_origin(_id, _data), do: :error + def contain_origin_from_id(id, %{"id" => other_id} = _params) when is_binary(other_id) do id_uri = URI.parse(id) other_uri = URI.parse(other_id) -- cgit v1.2.3 From e6d7e27bd603806e96dfc2774f90cadb3cf73a8c Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Tue, 12 Nov 2019 18:36:50 +0700 Subject: Add `allow_following_move` setting to User --- lib/pleroma/following_relationship.ex | 34 +++++++++------------- lib/pleroma/user.ex | 3 ++ .../mastodon_api/controllers/account_controller.ex | 1 + lib/pleroma/web/mastodon_api/views/account_view.ex | 7 +++++ 4 files changed, 25 insertions(+), 20 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/following_relationship.ex b/lib/pleroma/following_relationship.ex index 2f89eb4cf..40538f7bf 100644 --- a/lib/pleroma/following_relationship.ex +++ b/lib/pleroma/following_relationship.ex @@ -109,26 +109,20 @@ defmodule Pleroma.FollowingRelationship do end def move_following(origin, target) do - following_relationships = - __MODULE__ - |> where(following_id: ^origin.id) - |> preload([:follower]) - |> limit(50) - |> Repo.all() - - case following_relationships do - [] -> - :ok - - following_relationships -> - Enum.each(following_relationships, fn following_relationship -> - Repo.transaction(fn -> - Repo.delete(following_relationship) - User.follow(following_relationship.follower, target) - end) - end) - - move_following(origin, target) + __MODULE__ + |> join(:inner, [r], f in assoc(r, :follower)) + |> where(following_id: ^origin.id) + |> where([r, f], f.allow_following_move == true) + |> limit(50) + |> preload([:follower]) + |> Repo.all() + |> Enum.map(fn following_relationship -> + Repo.delete(following_relationship) + Pleroma.Web.CommonAPI.follow(following_relationship.follower, target) + end) + |> case do + [] -> :ok + _ -> move_following(origin, target) end end end diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 8715b37de..d40f6ed08 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -104,6 +104,7 @@ defmodule Pleroma.User do field(:raw_fields, {:array, :map}, default: []) field(:discoverable, :boolean, default: false) field(:invisible, :boolean, default: false) + field(:allow_following_move, :boolean, default: true) field(:skip_thread_containment, :boolean, default: false) field(:also_known_as, {:array, :string}, default: []) @@ -314,6 +315,7 @@ defmodule Pleroma.User do :hide_followers_count, :hide_follows_count, :hide_favorites, + :allow_following_move, :background, :show_role, :skip_thread_containment, @@ -359,6 +361,7 @@ defmodule Pleroma.User do :hide_follows, :fields, :hide_followers, + :allow_following_move, :discoverable, :hide_followers_count, :hide_follows_count, diff --git a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex index 73fad519e..7df7dc097 100644 --- a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex @@ -152,6 +152,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do :hide_favorites, :show_role, :skip_thread_containment, + :allow_following_move, :discoverable ] |> Enum.reduce(%{}, fn key, acc -> diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index e30fed610..7aae7d188 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -163,6 +163,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do |> maybe_put_chat_token(user, opts[:for], opts) |> maybe_put_activation_status(user, opts[:for]) |> maybe_put_follow_requests_count(user, opts[:for]) + |> maybe_put_allow_following_move(user, opts[:for]) |> maybe_put_unread_conversation_count(user, opts[:for]) end @@ -239,6 +240,12 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do defp maybe_put_notification_settings(data, _, _), do: data + defp maybe_put_allow_following_move(data, %User{id: user_id} = user, %User{id: user_id}) do + Kernel.put_in(data, [:pleroma, :allow_following_move], user.allow_following_move) + end + + defp maybe_put_allow_following_move(data, _, _), do: data + defp maybe_put_activation_status(data, user, %User{is_admin: true}) do Kernel.put_in(data, [:pleroma, :deactivated], user.deactivated) end -- cgit v1.2.3 From 27cd1374e3c1768a1a0b8abb40d5b56e6e021d2d Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Tue, 12 Nov 2019 18:48:14 +0700 Subject: Add a notification for Move activities --- lib/pleroma/notification.ex | 33 ++++++++++++++++----------------- lib/pleroma/web/common_api/utils.ex | 21 +++++++++++++++------ 2 files changed, 31 insertions(+), 23 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex index b7ecf51e4..f37e7ec67 100644 --- a/lib/pleroma/notification.ex +++ b/lib/pleroma/notification.ex @@ -251,10 +251,13 @@ defmodule Pleroma.Notification do end end - def create_notifications(%Activity{data: %{"to" => _, "type" => type}} = activity) - when type in ["Like", "Announce", "Follow"] do - users = get_notified_from_activity(activity) - notifications = Enum.map(users, fn user -> create_notification(activity, user) end) + def create_notifications(%Activity{data: %{"type" => type}} = activity) + when type in ["Like", "Announce", "Follow", "Move"] do + notifications = + activity + |> get_notified_from_activity() + |> Enum.map(&create_notification(activity, &1)) + {:ok, notifications} end @@ -276,19 +279,15 @@ defmodule Pleroma.Notification do def get_notified_from_activity(activity, local_only \\ true) - def get_notified_from_activity( - %Activity{data: %{"to" => _, "type" => type} = _data} = activity, - local_only - ) - when type in ["Create", "Like", "Announce", "Follow"] do - recipients = - [] - |> Utils.maybe_notify_to_recipients(activity) - |> Utils.maybe_notify_mentioned_recipients(activity) - |> Utils.maybe_notify_subscribers(activity) - |> Enum.uniq() - - User.get_users_from_set(recipients, local_only) + def get_notified_from_activity(%Activity{data: %{"type" => type}} = activity, local_only) + when type in ["Create", "Like", "Announce", "Follow", "Move"] do + [] + |> Utils.maybe_notify_to_recipients(activity) + |> Utils.maybe_notify_mentioned_recipients(activity) + |> Utils.maybe_notify_subscribers(activity) + |> Utils.maybe_notify_followers(activity) + |> Enum.uniq() + |> User.get_users_from_set(local_only) end def get_notified_from_activity(_, _local_only), do: [] diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex index 88a5f434a..43b67d0f0 100644 --- a/lib/pleroma/web/common_api/utils.ex +++ b/lib/pleroma/web/common_api/utils.ex @@ -451,6 +451,8 @@ defmodule Pleroma.Web.CommonAPI.Utils do recipients ++ to end + def maybe_notify_to_recipients(recipients, _), do: recipients + def maybe_notify_mentioned_recipients( recipients, %Activity{data: %{"to" => _to, "type" => type} = data} = activity @@ -484,12 +486,8 @@ defmodule Pleroma.Web.CommonAPI.Utils do recipients end - def maybe_notify_subscribers( - recipients, - %Activity{data: %{"actor" => actor, "type" => type}} = activity - ) - when type == "Create" do - with %User{} = user <- User.get_cached_by_ap_id(actor) do + def maybe_notify_subscribers(recipients, %Activity{data: %{"type" => "Create"}} = activity) do + with %User{} = user <- User.get_cached_by_ap_id(activity.actor) do subscriber_ids = user |> User.subscribers() @@ -502,6 +500,17 @@ defmodule Pleroma.Web.CommonAPI.Utils do def maybe_notify_subscribers(recipients, _), do: recipients + def maybe_notify_followers(recipients, %Activity{data: %{"type" => "Move"}} = activity) do + with %User{} = user <- User.get_cached_by_ap_id(activity.actor) do + user + |> User.get_followers() + |> Enum.map(& &1.ap_id) + |> Enum.concat(recipients) + end + end + + def maybe_notify_followers(recipients, _), do: recipients + def maybe_extract_mentions(%{"tag" => tag}) do tag |> Enum.filter(fn x -> is_map(x) && x["type"] == "Mention" end) -- cgit v1.2.3 From 768c1a5de172151beb34e6dda13d4fb05e05ed87 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Tue, 12 Nov 2019 19:13:19 +0700 Subject: Fix tests --- lib/pleroma/web/common_api/utils.ex | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex index 43b67d0f0..cbb64f8d2 100644 --- a/lib/pleroma/web/common_api/utils.ex +++ b/lib/pleroma/web/common_api/utils.ex @@ -486,8 +486,12 @@ defmodule Pleroma.Web.CommonAPI.Utils do recipients end - def maybe_notify_subscribers(recipients, %Activity{data: %{"type" => "Create"}} = activity) do - with %User{} = user <- User.get_cached_by_ap_id(activity.actor) do + def maybe_notify_subscribers( + recipients, + %Activity{data: %{"actor" => actor, "type" => type}} = activity + ) + when type == "Create" do + with %User{} = user <- User.get_cached_by_ap_id(actor) do subscriber_ids = user |> User.subscribers() -- cgit v1.2.3 From 62f3a93049649dee0ccd7b883887be2fd343fb3e Mon Sep 17 00:00:00 2001 From: Phil Hagelberg Date: Mon, 11 Nov 2019 17:16:44 -0800 Subject: For remote notices, redirect to the original instead of 404. We shouldn't treat these like local statuses, but I don't think a 404 is the right choice either here, because within pleroma-fe, these are valid URLs. So with remote notices you have the awkward situation where clicking a link will behave differently depending on whether you open it in a new tab or not; the new tab will 404 if it hits static-fe. This new redirecting behavior should improve that situation. --- lib/pleroma/web/static_fe/static_fe_controller.ex | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/web/static_fe/static_fe_controller.ex b/lib/pleroma/web/static_fe/static_fe_controller.ex index 5e60c82b0..ba44b8a4f 100644 --- a/lib/pleroma/web/static_fe/static_fe_controller.ex +++ b/lib/pleroma/web/static_fe/static_fe_controller.ex @@ -77,6 +77,11 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do render(conn, "conversation.html", %{activities: timeline, meta: meta}) else + %Activity{object: %Object{data: data}} -> + conn + |> put_status(:found) + |> redirect(external: data["url"] || data["external_url"] || data["id"]) + _ -> conn |> put_status(404) -- cgit v1.2.3 From 0867cb083eb469ae10cd48d424a51efb2fae4018 Mon Sep 17 00:00:00 2001 From: Phil Hagelberg Date: Tue, 12 Nov 2019 17:19:46 -0800 Subject: Support redirecting by object ID in static FE. This matches the behavior of pleroma-fe better. Fixes #1412. --- lib/pleroma/web/static_fe/static_fe_controller.ex | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/web/static_fe/static_fe_controller.ex b/lib/pleroma/web/static_fe/static_fe_controller.ex index ba44b8a4f..b45d82c2d 100644 --- a/lib/pleroma/web/static_fe/static_fe_controller.ex +++ b/lib/pleroma/web/static_fe/static_fe_controller.ex @@ -119,11 +119,26 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do end end + def show(%{assigns: %{object_id: _}} = conn, _params) do + url = Helpers.url(conn) <> conn.request_path + case Activity.get_create_by_object_ap_id_with_object(url) do + %Activity{} = activity -> + redirect(conn, to: "/notice/#{activity.id}") + _ -> + conn + |> put_status(404) + |> render("error.html", %{message: "Post not found.", meta: ""}) + end + end + def assign_id(%{path_info: ["notice", notice_id]} = conn, _opts), do: assign(conn, :notice_id, notice_id) def assign_id(%{path_info: ["users", user_id]} = conn, _opts), do: assign(conn, :username_or_id, user_id) + def assign_id(%{path_info: ["objects", object_id]} = conn, _opts), + do: assign(conn, :object_id, object_id) + def assign_id(conn, _opts), do: conn end -- cgit v1.2.3 From 3c60adbc1f773c732458d68b4becaf9bb36d7062 Mon Sep 17 00:00:00 2001 From: Phil Hagelberg Date: Tue, 12 Nov 2019 17:33:54 -0800 Subject: Support redirecting by activity UUID in static FE as well. --- lib/pleroma/web/static_fe/static_fe_controller.ex | 41 +++++++++++++++++------ 1 file changed, 30 insertions(+), 11 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/static_fe/static_fe_controller.ex b/lib/pleroma/web/static_fe/static_fe_controller.ex index b45d82c2d..8ccf15f4b 100644 --- a/lib/pleroma/web/static_fe/static_fe_controller.ex +++ b/lib/pleroma/web/static_fe/static_fe_controller.ex @@ -27,6 +27,12 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do defp get_title(_), do: nil + defp not_found(conn, message) do + conn + |> put_status(404) + |> render("error.html", %{message: message, meta: ""}) + end + def get_counts(%Activity{} = activity) do %Object{data: data} = Object.normalize(activity) @@ -83,9 +89,7 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do |> redirect(external: data["url"] || data["external_url"] || data["id"]) _ -> - conn - |> put_status(404) - |> render("error.html", %{message: "Post not found.", meta: ""}) + not_found(conn, "Post not found.") end end @@ -113,21 +117,33 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do }) _ -> - conn - |> put_status(404) - |> render("error.html", %{message: "User not found.", meta: ""}) + not_found(conn, "User not found.") end end def show(%{assigns: %{object_id: _}} = conn, _params) do url = Helpers.url(conn) <> conn.request_path + case Activity.get_create_by_object_ap_id_with_object(url) do %Activity{} = activity -> - redirect(conn, to: "/notice/#{activity.id}") - _ -> - conn - |> put_status(404) - |> render("error.html", %{message: "Post not found.", meta: ""}) + to = Helpers.o_status_path(Pleroma.Web.Endpoint, :notice, activity) + redirect(conn, to: to) + + _ -> + not_found(conn, "Post not found.") + end + end + + def show(%{assigns: %{activity_id: _}} = conn, _params) do + url = Helpers.url(conn) <> conn.request_path + + case Activity.get_by_ap_id(url) do + %Activity{} = activity -> + to = Helpers.o_status_path(Pleroma.Web.Endpoint, :notice, activity) + redirect(conn, to: to) + + _ -> + not_found(conn, "Post not found.") end end @@ -140,5 +156,8 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do def assign_id(%{path_info: ["objects", object_id]} = conn, _opts), do: assign(conn, :object_id, object_id) + def assign_id(%{path_info: ["activities", activity_id]} = conn, _opts), + do: assign(conn, :activity_id, activity_id) + def assign_id(conn, _opts), do: conn end -- cgit v1.2.3 From 94f1cfced872924592eff39b00781989a9e2f96f Mon Sep 17 00:00:00 2001 From: rinpatch Date: Thu, 14 Nov 2019 17:26:59 +0300 Subject: format the code --- lib/pleroma/web/mastodon_api/views/conversation_view.ex | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/mastodon_api/views/conversation_view.ex b/lib/pleroma/web/mastodon_api/views/conversation_view.ex index 51d6c0898..2220fbcb1 100644 --- a/lib/pleroma/web/mastodon_api/views/conversation_view.ex +++ b/lib/pleroma/web/mastodon_api/views/conversation_view.ex @@ -12,7 +12,10 @@ defmodule Pleroma.Web.MastodonAPI.ConversationView do alias Pleroma.Web.MastodonAPI.StatusView def render("participations.json", %{participations: participations, for: user}) do - safe_render_many(participations, __MODULE__, "participation.json", %{as: :participation, for: user}) + safe_render_many(participations, __MODULE__, "participation.json", %{ + as: :participation, + for: user + }) end def render("participation.json", %{participation: participation, for: user}) do -- cgit v1.2.3 From 30af5da33043192dff626e869f2628ffc709f836 Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Thu, 14 Nov 2019 23:44:07 +0900 Subject: Admin API: list all statuses from a given instance --- lib/pleroma/web/activity_pub/activity_pub.ex | 26 +++++++++++++++++++++++ lib/pleroma/web/admin_api/admin_api_controller.ex | 15 +++++++++++++ lib/pleroma/web/router.ex | 2 ++ 3 files changed, 43 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 65dd251f3..8b5bd83e2 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -708,6 +708,17 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do |> Enum.reverse() end + def fetch_instance_activities(params) do + params = + params + |> Map.put("type", ["Create", "Announce"]) + |> Map.put("instance", params["instance"]) + |> Map.put("whole_db", true) + + fetch_activities([Pleroma.Constants.as_public()], params, :offset) + |> Enum.reverse() + end + defp user_activities_recipients(%{"godmode" => true}) do [] end @@ -935,6 +946,20 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do defp restrict_muted_reblogs(query, _), do: query + defp restrict_instance(query, %{"instance" => instance}) do + users = + from( + u in User, + select: u.ap_id, + where: fragment("? LIKE ?", u.nickname, ^"%@#{instance}") + ) + |> Repo.all() + + from(activity in query, where: activity.actor in ^users) + end + + defp restrict_instance(query, _), do: query + defp exclude_poll_votes(query, %{"include_poll_votes" => true}), do: query defp exclude_poll_votes(query, _) do @@ -1015,6 +1040,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do |> restrict_reblogs(opts) |> restrict_pinned(opts) |> restrict_muted_reblogs(opts) + |> restrict_instance(opts) |> Activity.restrict_deactivated_users() |> exclude_poll_votes(opts) |> exclude_visibility(opts) diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index 30fc01755..2f43f018b 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -226,6 +226,21 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do end end + def list_instance_statuses(conn, %{"instance" => instance} = params) do + {page, page_size} = page_params(params) + + activities = + ActivityPub.fetch_instance_activities(%{ + "instance" => instance, + "limit" => page_size, + "offset" => (page - 1) * page_size + }) + + conn + |> put_view(StatusView) + |> render("index.json", %{activities: activities, as: :activity}) + end + def list_user_statuses(conn, %{"nickname" => nickname} = params) do godmode = params["godmode"] == "true" || params["godmode"] == true diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 8fb4aec13..1e2982b67 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -177,6 +177,8 @@ defmodule Pleroma.Web.Router do get("/users/:nickname", AdminAPIController, :user_show) get("/users/:nickname/statuses", AdminAPIController, :list_user_statuses) + get("/instances/:instance/statuses", AdminAPIController, :list_instance_statuses) + get("/reports", AdminAPIController, :list_reports) get("/reports/:id", AdminAPIController, :report_show) put("/reports/:id", AdminAPIController, :report_update_state) -- cgit v1.2.3 From 5705cf0e3e675c142442a6183d5613ae936f3276 Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Thu, 14 Nov 2019 19:48:10 -0600 Subject: MRF: add ObjectAgePolicy which deals with old posts being imported --- .../web/activity_pub/mrf/object_age_policy.ex | 103 +++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 lib/pleroma/web/activity_pub/mrf/object_age_policy.ex (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/mrf/object_age_policy.ex b/lib/pleroma/web/activity_pub/mrf/object_age_policy.ex new file mode 100644 index 000000000..f6c6f31cb --- /dev/null +++ b/lib/pleroma/web/activity_pub/mrf/object_age_policy.ex @@ -0,0 +1,103 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicy do + alias Pleroma.Config + alias Pleroma.User + alias Pleroma.Web.ActivityPub.MRF + + require Logger + require Pleroma.Constants + + @moduledoc "Filter activities depending on their age" + @behaviour MRF + + defp check_date(%{"published" => published} = message) do + with %DateTime{} = now <- DateTime.utc_now(), + {:ok, %DateTime{} = then, _} <- DateTime.from_iso8601(published), + max_ttl <- Config.get([:mrf_object_age, :threshold]), + {:ttl, false} <- {:ttl, DateTime.diff(now, then) > max_ttl} do + {:ok, message} + else + {:ttl, true} -> + {:reject, nil} + + e -> + {:error, e} + end + end + + defp check_reject(message, actions) do + if :reject in actions do + {:reject, nil} + else + {:ok, message} + end + end + + defp check_delist(message, actions) do + if :delist in actions do + with %User{} = user <- User.get_cached_by_ap_id(message["actor"]) do + to = List.delete(message["to"], Pleroma.Constants.as_public()) ++ [user.follower_address] + cc = List.delete(message["cc"], user.follower_address) ++ [Pleroma.Constants.as_public()] + + message = + message + |> Map.put("to", to) + |> Map.put("cc", cc) + + {:ok, message} + else + # Unhandleable error: somebody is messing around, just drop the message. + e -> + Logger.error("ERROR: #{inspect(e)}") + {:reject, nil} + end + else + {:ok, message} + end + end + + defp check_strip_followers(message, actions) do + if :strip_followers in actions do + with %User{} = user <- User.get_cached_by_ap_id(message["actor"]) do + to = List.delete(message["to"], user.follower_address) + cc = List.delete(message["cc"], user.follower_address) + + message = + message + |> Map.put("to", to) + |> Map.put("cc", cc) + + {:ok, message} + else + # Unhandleable error: somebody is messing around, just drop the message. + _e -> + {:reject, nil} + end + else + {:ok, message} + end + end + + @impl true + def filter(%{"type" => "Create", "published" => _} = message) do + with actions <- Config.get([:mrf_object_age, :actions]), + {:reject, _} <- check_date(message), + {:ok, message} <- check_reject(message, actions), + {:ok, message} <- check_delist(message, actions), + {:ok, message} <- check_strip_followers(message, actions) do + {:ok, message} + else + # check_date() is allowed to short-circuit the pipeline + e -> e + end + end + + @impl true + def filter(message), do: {:ok, message} + + @impl true + def describe, do: {:ok, %{}} +end -- cgit v1.2.3 From eecd64cc0786a22d1ba90214e6c6bd5fb5829ec0 Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Thu, 14 Nov 2019 19:56:14 -0600 Subject: object age policy: remove debug logging --- lib/pleroma/web/activity_pub/mrf/object_age_policy.ex | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/mrf/object_age_policy.ex b/lib/pleroma/web/activity_pub/mrf/object_age_policy.ex index f6c6f31cb..8b36c1021 100644 --- a/lib/pleroma/web/activity_pub/mrf/object_age_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/object_age_policy.ex @@ -7,7 +7,6 @@ defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicy do alias Pleroma.User alias Pleroma.Web.ActivityPub.MRF - require Logger require Pleroma.Constants @moduledoc "Filter activities depending on their age" @@ -50,8 +49,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicy do {:ok, message} else # Unhandleable error: somebody is messing around, just drop the message. - e -> - Logger.error("ERROR: #{inspect(e)}") + _e -> {:reject, nil} end else -- cgit v1.2.3 From 72d2557e11265f13eedc8f4ad11640abdd6d7158 Mon Sep 17 00:00:00 2001 From: kPherox Date: Fri, 15 Nov 2019 18:51:55 +0900 Subject: Add fieldsLimit to metadata of nodeinfo --- lib/pleroma/web/nodeinfo/nodeinfo_controller.ex | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex b/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex index 486b9f6a4..abcf46034 100644 --- a/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex +++ b/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex @@ -120,6 +120,12 @@ defmodule Pleroma.Web.Nodeinfo.NodeinfoController do banner: Config.get([:instance, :banner_upload_limit]), background: Config.get([:instance, :background_upload_limit]) }, + fieldsLimits: %{ + maxFields: Config.get([:instance, :max_account_fields]), + maxRemoteFields: Config.get([:instance, :max_remote_account_fields]), + nameLength: Config.get([:instance, :account_field_name_length]), + valueLength: Config.get([:instance, :account_field_value_length]) + }, accountActivationRequired: Config.get([:instance, :account_activation_required], false), invitesEnabled: Config.get([:instance, :invites_enabled], false), mailerEnabled: Config.get([Pleroma.Emails.Mailer, :enabled], false), -- cgit v1.2.3 From f17e0f8e4f8f6249d1de9ad8a21953cca4963045 Mon Sep 17 00:00:00 2001 From: lain Date: Fri, 15 Nov 2019 14:13:21 +0100 Subject: OAuthPlug, Router: Handle deactivated users in the UserEnabledPlug --- lib/pleroma/plugs/oauth_plug.ex | 2 +- lib/pleroma/web/router.ex | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/plugs/oauth_plug.ex b/lib/pleroma/plugs/oauth_plug.ex index fd004fcd2..11a5b7642 100644 --- a/lib/pleroma/plugs/oauth_plug.ex +++ b/lib/pleroma/plugs/oauth_plug.ex @@ -71,7 +71,7 @@ defmodule Pleroma.Plugs.OAuthPlug do ) # credo:disable-for-next-line Credo.Check.Readability.MaxLineLength - with %Token{user: %{deactivated: false} = user} = token_record <- Repo.one(query) do + with %Token{user: user} = token_record <- Repo.one(query) do {:ok, user, token_record} end end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 8fb4aec13..af7c0e289 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -13,6 +13,7 @@ defmodule Pleroma.Web.Router do pipeline :oauth do plug(:fetch_session) plug(Pleroma.Plugs.OAuthPlug) + plug(Pleroma.Plugs.UserEnabledPlug) end pipeline :api do -- cgit v1.2.3 From c506cc48ef230da30d5786285806de904b725981 Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Sat, 16 Nov 2019 18:44:48 +0900 Subject: Admin API: Error when trying to update reports in the "old" format --- lib/pleroma/web/activity_pub/utils.ex | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index c45662359..01aacbde3 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -903,7 +903,13 @@ defmodule Pleroma.Web.ActivityPub.Utils do def strip_report_status_data(activity) do [actor | reported_activities] = activity.data["object"] - stripped_activities = Enum.map(reported_activities, & &1["id"]) + + stripped_activities = + Enum.map(reported_activities, fn + act when is_map(act) -> act["id"] + act when is_binary(act) -> act + end) + new_data = put_in(activity.data, ["object"], [actor | stripped_activities]) {:ok, %{activity | data: new_data}} -- cgit v1.2.3 From 36686f52457454841c6b9c85a137eabeb1e739fc Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Tue, 19 Nov 2019 15:58:20 +0700 Subject: Support authentication via `x-admin-token` HTTP header --- .../plugs/admin_secret_authentication_plug.ex | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/plugs/admin_secret_authentication_plug.ex b/lib/pleroma/plugs/admin_secret_authentication_plug.ex index fdadd476e..49dea452d 100644 --- a/lib/pleroma/plugs/admin_secret_authentication_plug.ex +++ b/lib/pleroma/plugs/admin_secret_authentication_plug.ex @@ -16,14 +16,28 @@ defmodule Pleroma.Plugs.AdminSecretAuthenticationPlug do def call(%{assigns: %{user: %User{}}} = conn, _), do: conn - def call(%{params: %{"admin_token" => admin_token}} = conn, _) do - if secret_token() && admin_token == secret_token() do + def call(conn, _) do + if secret_token() do + authenticate(conn) + else conn - |> assign(:user, %User{is_admin: true}) + end + end + + def authenticate(%{params: %{"admin_token" => admin_token}} = conn) do + if admin_token == secret_token() do + assign(conn, :user, %User{is_admin: true}) else conn end end - def call(conn, _), do: conn + def authenticate(conn) do + token = secret_token() + + case get_req_header(conn, "x-admin-token") do + [^token] -> assign(conn, :user, %User{is_admin: true}) + _ -> conn + end + end end -- cgit v1.2.3 From 46eb160135cf408fee87bb76fc46acfc51af901d Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Tue, 19 Nov 2019 20:14:02 +0900 Subject: AdminAPI: Confirm user account, resend confirmation email --- lib/pleroma/moderation_log.ex | 26 +++++++++++++- lib/pleroma/user.ex | 9 +++++ lib/pleroma/web/admin_api/admin_api_controller.ex | 41 +++++++++++++++++++---- lib/pleroma/web/admin_api/views/account_view.ex | 3 +- lib/pleroma/web/router.ex | 3 ++ 5 files changed, 74 insertions(+), 8 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/moderation_log.ex b/lib/pleroma/moderation_log.ex index ffa5dc25d..706f089dc 100644 --- a/lib/pleroma/moderation_log.ex +++ b/lib/pleroma/moderation_log.ex @@ -624,7 +624,31 @@ defmodule Pleroma.ModerationLog do "subject" => subjects } }) do - "@#{actor_nickname} force password reset for users: #{users_to_nicknames_string(subjects)}" + "@#{actor_nickname} forced password reset for users: #{users_to_nicknames_string(subjects)}" + end + + @spec get_log_entry_message(ModerationLog) :: String.t() + def get_log_entry_message(%ModerationLog{ + data: %{ + "actor" => %{"nickname" => actor_nickname}, + "action" => "confirm_email", + "subject" => subjects + } + }) do + "@#{actor_nickname} confirmed email for users: #{users_to_nicknames_string(subjects)}" + end + + @spec get_log_entry_message(ModerationLog) :: String.t() + def get_log_entry_message(%ModerationLog{ + data: %{ + "actor" => %{"nickname" => actor_nickname}, + "action" => "resend_confirmation_email", + "subject" => subjects + } + }) do + "@#{actor_nickname} re-sent confirmation email for users: #{ + users_to_nicknames_string(subjects) + }" end defp nicknames_to_string(nicknames) do diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index f8c2db1e1..f031d2179 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -489,6 +489,10 @@ defmodule Pleroma.User do end end + def try_send_confirmation_email(users) do + Enum.map(users, &try_send_confirmation_email/1) + end + def needs_update?(%User{local: true}), do: false def needs_update?(%User{local: false, last_refreshed_at: nil}), do: true @@ -1572,6 +1576,11 @@ defmodule Pleroma.User do |> update_and_set_cache() end + @spec toggle_confirmation([User.t()]) :: [{:ok, User.t()} | {:error, Changeset.t()}] + def toggle_confirmation(users) do + Enum.map(users, &toggle_confirmation/1) + end + def get_mascot(%{mascot: %{} = mascot}) when not is_nil(mascot) do mascot end diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index 8c1318d1b..c46ce76da 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -335,7 +335,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do } with {:ok, users, count} <- Search.user(Map.merge(search_params, filters)), - {:ok, users, count} <- filter_relay_user(users, count), + {:ok, users, count} <- filter_service_users(users, count), do: conn |> json( @@ -347,15 +347,16 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do ) end - defp filter_relay_user(users, count) do - filtered_users = Enum.reject(users, &relay_user?/1) - count = if Enum.any?(users, &relay_user?/1), do: length(filtered_users), else: count + defp filter_service_users(users, count) do + filtered_users = Enum.reject(users, &service_user?/1) + count = if Enum.any?(users, &service_user?/1), do: length(filtered_users), else: count {:ok, filtered_users, count} end - defp relay_user?(user) do - user.ap_id == Relay.relay_ap_id() + defp service_user?(user) do + String.match?(user.ap_id, ~r/.*\/relay$/) or + String.match?(user.ap_id, ~r/.*\/internal\/fetch$/) end @filters ~w(local external active deactivated is_admin is_moderator) @@ -799,6 +800,34 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do conn |> json("ok") end + def confirm_email(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) do + users = nicknames |> Enum.map(&User.get_cached_by_nickname/1) + + User.toggle_confirmation(users) + + ModerationLog.insert_log(%{ + actor: admin, + subject: users, + action: "confirm_email" + }) + + conn |> json("") + end + + def resend_confirmation_email(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) do + users = nicknames |> Enum.map(&User.get_cached_by_nickname/1) + + User.try_send_confirmation_email(users) + + ModerationLog.insert_log(%{ + actor: admin, + subject: users, + action: "resend_confirmation_email" + }) + + conn |> json("") + end + def errors(conn, {:error, :not_found}) do conn |> put_status(:not_found) diff --git a/lib/pleroma/web/admin_api/views/account_view.ex b/lib/pleroma/web/admin_api/views/account_view.ex index 6aa7257ce..d9dba5c51 100644 --- a/lib/pleroma/web/admin_api/views/account_view.ex +++ b/lib/pleroma/web/admin_api/views/account_view.ex @@ -36,7 +36,8 @@ defmodule Pleroma.Web.AdminAPI.AccountView do "deactivated" => user.deactivated, "local" => user.local, "roles" => User.roles(user), - "tags" => user.tags || [] + "tags" => user.tags || [], + "confirmation_pending" => user.confirmation_pending } end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 9b8b373b8..b654d00c7 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -177,6 +177,9 @@ defmodule Pleroma.Web.Router do get("/users/:nickname", AdminAPIController, :user_show) get("/users/:nickname/statuses", AdminAPIController, :list_user_statuses) + patch("/users/confirm_email", AdminAPIController, :confirm_email) + patch("/users/resend_confirmation_email", AdminAPIController, :resend_confirmation_email) + get("/reports", AdminAPIController, :list_reports) get("/grouped_reports", AdminAPIController, :list_grouped_reports) get("/reports/:id", AdminAPIController, :report_show) -- cgit v1.2.3 From ff9133b978edb637081882e7efd49e2f538e9e15 Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Tue, 19 Nov 2019 16:01:17 -0600 Subject: Allow mix tasks to always run with debug logging --- lib/mix/pleroma.ex | 1 + 1 file changed, 1 insertion(+) (limited to 'lib') diff --git a/lib/mix/pleroma.ex b/lib/mix/pleroma.ex index faeb30e1d..94eeb7d68 100644 --- a/lib/mix/pleroma.ex +++ b/lib/mix/pleroma.ex @@ -6,6 +6,7 @@ defmodule Mix.Pleroma do @doc "Common functions to be reused in mix tasks" def start_pleroma do Application.put_env(:phoenix, :serve_endpoints, false, persistent: true) + Application.put_env(:logger, :console, level: :debug) {:ok, _} = Application.ensure_all_started(:pleroma) end -- cgit v1.2.3 From edaae845afc63d558c22019b3b3f87bc510a3bdf Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Wed, 20 Nov 2019 11:55:30 -0600 Subject: Some tasks try to set log level in test environment, but we were stripping logs belog :warn. Ensure console backend logs in test environment are :warn, but mix tasks run in test env do not run with :debug because it's far too verbose. --- lib/mix/pleroma.ex | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/mix/pleroma.ex b/lib/mix/pleroma.ex index 94eeb7d68..73a076a53 100644 --- a/lib/mix/pleroma.ex +++ b/lib/mix/pleroma.ex @@ -6,7 +6,11 @@ defmodule Mix.Pleroma do @doc "Common functions to be reused in mix tasks" def start_pleroma do Application.put_env(:phoenix, :serve_endpoints, false, persistent: true) - Application.put_env(:logger, :console, level: :debug) + + if Pleroma.Config.get(:env) != :test do + Application.put_env(:logger, :console, level: :debug) + end + {:ok, _} = Application.ensure_all_started(:pleroma) end -- cgit v1.2.3 From d38ab4bb89299f643d8529d46e02521a525b84e6 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Thu, 21 Nov 2019 16:31:13 +0700 Subject: Fix user.following_count --- lib/pleroma/user.ex | 56 ++++++++++++++++++++++++++++------------------------- 1 file changed, 30 insertions(+), 26 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index fcb1d5143..34370be20 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -67,8 +67,7 @@ defmodule Pleroma.User do field(:source_data, :map, default: %{}) field(:note_count, :integer, default: 0) field(:follower_count, :integer, default: 0) - # Should be filled in only for remote users - field(:following_count, :integer, default: nil) + field(:following_count, :integer, default: 0) field(:locked, :boolean, default: false) field(:confirmation_pending, :boolean, default: false) field(:password_reset_pending, :boolean, default: false) @@ -177,19 +176,17 @@ defmodule Pleroma.User do def ap_following(%User{} = user), do: "#{ap_id(user)}/following" def user_info(%User{} = user, args \\ %{}) do - following_count = - Map.get(args, :following_count, user.following_count || following_count(user)) - + following_count = Map.get(args, :following_count, user.following_count) follower_count = Map.get(args, :follower_count, user.follower_count) %{ note_count: user.note_count, locked: user.locked, confirmation_pending: user.confirmation_pending, - default_scope: user.default_scope + default_scope: user.default_scope, + follower_count: follower_count, + following_count: following_count } - |> Map.put(:following_count, following_count) - |> Map.put(:follower_count, follower_count) end def follow_state(%User{} = user, %User{} = target) do @@ -522,14 +519,9 @@ defmodule Pleroma.User do @doc "A mass follow for local users. Respects blocks in both directions but does not create activities." @spec follow_all(User.t(), list(User.t())) :: {atom(), User.t()} def follow_all(follower, followeds) do - followeds = - Enum.reject(followeds, fn followed -> - blocks?(follower, followed) || blocks?(followed, follower) - end) - - Enum.each(followeds, &follow(follower, &1, "accept")) - - Enum.each(followeds, &update_follower_count/1) + followeds + |> Enum.reject(fn followed -> blocks?(follower, followed) || blocks?(followed, follower) end) + |> Enum.each(&follow(follower, &1, "accept")) set_cache(follower) end @@ -549,11 +541,11 @@ defmodule Pleroma.User do true -> FollowingRelationship.follow(follower, followed, state) - follower = maybe_update_following_count(follower) - {:ok, _} = update_follower_count(followed) - set_cache(follower) + follower + |> update_following_count() + |> set_cache() end end @@ -561,11 +553,12 @@ defmodule Pleroma.User do if following?(follower, followed) and follower.ap_id != followed.ap_id do FollowingRelationship.unfollow(follower, followed) - follower = maybe_update_following_count(follower) - {:ok, followed} = update_follower_count(followed) - set_cache(follower) + {:ok, follower} = + follower + |> update_following_count() + |> set_cache() {:ok, follower, Utils.fetch_latest_follow(follower, followed)} else @@ -895,8 +888,8 @@ defmodule Pleroma.User do end end - @spec maybe_update_following_count(User.t()) :: User.t() - def maybe_update_following_count(%User{local: false} = user) do + @spec update_following_count(User.t()) :: User.t() + def update_following_count(%User{local: false} = user) do if Pleroma.Config.get([:instance, :external_user_synchronization]) do maybe_fetch_follow_information(user) else @@ -904,7 +897,13 @@ defmodule Pleroma.User do end end - def maybe_update_following_count(user), do: user + def update_following_count(%User{local: true} = user) do + following_count = FollowingRelationship.following_count(user) + + user + |> follow_information_changeset(%{following_count: following_count}) + |> Repo.update!() + end def set_unread_conversation_count(%User{local: true} = user) do unread_query = Participation.unread_conversation_count_for_user(user) @@ -1097,7 +1096,12 @@ defmodule Pleroma.User do def deactivate(%User{} = user, status) do with {:ok, user} <- set_activation_status(user, status) do - Enum.each(get_followers(user), &invalidate_cache/1) + user + |> get_followers() + |> Enum.filter(& &1.local) + |> Enum.each(fn follower -> + follower |> update_following_count() |> set_cache() + end) # Only update local user counts, remote will be update during the next pull. user -- cgit v1.2.3 From 320690f7a5bf1622e25114b6ad4c0b0c5a252748 Mon Sep 17 00:00:00 2001 From: lain Date: Thu, 21 Nov 2019 14:03:01 +0100 Subject: Object: Use inspect to log missing preload. --- lib/pleroma/object.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex index d9b41d710..cde0eddd9 100644 --- a/lib/pleroma/object.ex +++ b/lib/pleroma/object.ex @@ -63,7 +63,7 @@ defmodule Pleroma.Object do end defp warn_on_no_object_preloaded(ap_id) do - "Object.normalize() called without preloaded object (#{ap_id}). Consider preloading the object" + "Object.normalize() called without preloaded object (#{inspect(ap_id)}). Consider preloading the object" |> Logger.debug() Logger.debug("Backtrace: #{inspect(Process.info(:erlang.self(), :current_stacktrace))}") -- cgit v1.2.3 From fbc379d68990b166e1034cfff252f975f793eba1 Mon Sep 17 00:00:00 2001 From: Alex Schroeder Date: Sun, 17 Nov 2019 21:58:30 +0100 Subject: Add CLI list users command --- lib/mix/tasks/pleroma/user.ex | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/user.ex b/lib/mix/tasks/pleroma/user.ex index 4e3b80db3..bc8eacda8 100644 --- a/lib/mix/tasks/pleroma/user.ex +++ b/lib/mix/tasks/pleroma/user.ex @@ -364,6 +364,24 @@ defmodule Mix.Tasks.Pleroma.User do end end + def run(["list"]) do + start_pleroma() + + Pleroma.User.Query.build(%{local: true}) + |> Pleroma.RepoStreamer.chunk_stream(500) + |> Stream.each(fn users -> + users + |> Enum.each(fn user -> + shell_info( + "#{user.nickname} moderator: #{user.info.is_moderator}, admin: #{user.info.is_admin}, locked: #{ + user.info.locked + }, deactivated: #{user.info.deactivated}" + ) + end) + end) + |> Stream.run() + end + defp set_moderator(user, value) do {:ok, user} = user -- cgit v1.2.3 From b64c7b35d429546695550b37ca1e690b46c86f5d Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Fri, 22 Nov 2019 09:11:36 +0900 Subject: Swap map with each --- lib/pleroma/user.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index f031d2179..f1830509c 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -490,7 +490,7 @@ defmodule Pleroma.User do end def try_send_confirmation_email(users) do - Enum.map(users, &try_send_confirmation_email/1) + Enum.each(users, &try_send_confirmation_email/1) end def needs_update?(%User{local: true}), do: false -- cgit v1.2.3 From 1636cc5b7e2ad324c828c993d5fb39ac9cdb40cc Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Sat, 23 Nov 2019 14:06:19 +0300 Subject: Removed users.info and remaining usages. --- lib/pleroma/user.ex | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index fcb1d5143..e4656af3d 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -119,8 +119,6 @@ defmodule Pleroma.User do has_many(:registrations, Registration) has_many(:deliveries, Delivery) - field(:info, :map, default: %{}) - timestamps() end @@ -244,7 +242,6 @@ defmodule Pleroma.User do params = params - |> Map.put(:info, params[:info] || %{}) |> truncate_if_exists(:name, name_limit) |> truncate_if_exists(:bio, bio_limit) |> truncate_fields_param() @@ -1226,7 +1223,7 @@ defmodule Pleroma.User do def external_users(opts \\ []) do query = external_users_query() - |> select([u], struct(u, [:id, :ap_id, :info])) + |> select([u], struct(u, [:id, :ap_id])) query = if opts[:max_id], -- cgit v1.2.3 From 9f2993044098ced1585c8886c16da19dd046b5fd Mon Sep 17 00:00:00 2001 From: rinpatch Date: Sat, 23 Nov 2019 22:55:41 +0300 Subject: fetcher: move local object checking into a reusable function --- lib/pleroma/object.ex | 4 ++++ lib/pleroma/object/fetcher.ex | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex index cde0eddd9..b4ed3a9b2 100644 --- a/lib/pleroma/object.ex +++ b/lib/pleroma/object.ex @@ -255,4 +255,8 @@ defmodule Pleroma.Object do |> Object.change(%{data: Map.merge(data || %{}, attrs)}) |> Repo.update() end + + def local?(%Object{data: %{"id" => id}}) do + String.starts_with?(id, Pleroma.Web.base_url() <> "/") + end end diff --git a/lib/pleroma/object/fetcher.ex b/lib/pleroma/object/fetcher.ex index 9a9a46550..4d71c91a8 100644 --- a/lib/pleroma/object/fetcher.ex +++ b/lib/pleroma/object/fetcher.ex @@ -49,7 +49,7 @@ defmodule Pleroma.Object.Fetcher do end def refetch_object(%Object{data: %{"id" => id}} = object) do - with {:local, false} <- {:local, String.starts_with?(id, Pleroma.Web.base_url() <> "/")}, + with {:local, false} <- {:local, Object.local?(object)}, {:ok, data} <- fetch_and_contain_remote_object_from_id(id), {:ok, object} <- reinject_object(object, data) do {:ok, object} -- cgit v1.2.3 From d3656c2725fa80ea66dd9de2d74893fe9888ef57 Mon Sep 17 00:00:00 2001 From: Sadposter Date: Mon, 25 Nov 2019 09:53:11 +0000 Subject: add ability to set a custom user-agent string --- lib/pleroma/application.ex | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index 2b6a55f98..9dbd1e26b 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -17,8 +17,14 @@ defmodule Pleroma.Application do def repository, do: @repository def user_agent do - info = "#{Pleroma.Web.base_url()} <#{Pleroma.Config.get([:instance, :email], "")}>" - named_version() <> "; " <> info + case Pleroma.Config.get([:http, :user_agent], :default) do + :default -> + info = "#{Pleroma.Web.base_url()} <#{Pleroma.Config.get([:instance, :email], "")}>" + named_version() <> "; " <> info + + custom -> + custom + end end # See http://elixir-lang.org/docs/stable/elixir/Application.html -- cgit v1.2.3 From 02f7383891ff0a8dd17f00d6d00ec3495116e38a Mon Sep 17 00:00:00 2001 From: rinpatch Date: Mon, 25 Nov 2019 17:19:33 +0300 Subject: ActivityPub controller: do not render remote users --- lib/pleroma/web/activity_pub/activity_pub_controller.ex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/activity_pub_controller.ex b/lib/pleroma/web/activity_pub/activity_pub_controller.ex index b2cd965fe..dec5da0d3 100644 --- a/lib/pleroma/web/activity_pub/activity_pub_controller.ex +++ b/lib/pleroma/web/activity_pub/activity_pub_controller.ex @@ -45,7 +45,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do end def user(conn, %{"nickname" => nickname}) do - with %User{} = user <- User.get_cached_by_nickname(nickname), + with %User{local: true} = user <- User.get_cached_by_nickname(nickname), {:ok, user} <- User.ensure_keys_present(user) do conn |> put_resp_content_type("application/activity+json") @@ -53,6 +53,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do |> render("user.json", %{user: user}) else nil -> {:error, :not_found} + %{local: false} -> {:error, :not_found} end end -- cgit v1.2.3 From 4b10804f21b80b74f9f9f85c9ecd6e1ec791255d Mon Sep 17 00:00:00 2001 From: rinpatch Date: Mon, 25 Nov 2019 17:55:17 +0300 Subject: OStatus controller: don't serve json at /notice/, redirect instead --- lib/pleroma/web/ostatus/ostatus_controller.ex | 46 ++++++++------------------- 1 file changed, 14 insertions(+), 32 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/ostatus/ostatus_controller.ex b/lib/pleroma/web/ostatus/ostatus_controller.ex index 12a7c2365..01ec7941e 100644 --- a/lib/pleroma/web/ostatus/ostatus_controller.ex +++ b/lib/pleroma/web/ostatus/ostatus_controller.ex @@ -11,7 +11,6 @@ defmodule Pleroma.Web.OStatus.OStatusController do alias Pleroma.Plugs.RateLimiter alias Pleroma.User alias Pleroma.Web.ActivityPub.ActivityPubController - alias Pleroma.Web.ActivityPub.ObjectView alias Pleroma.Web.ActivityPub.Visibility alias Pleroma.Web.Endpoint alias Pleroma.Web.Metadata.PlayerView @@ -38,11 +37,9 @@ defmodule Pleroma.Web.OStatus.OStatusController do with id <- o_status_url(conn, :object, uuid), {_, %Activity{} = activity} <- {:activity, Activity.get_create_by_object_ap_id_with_object(id)}, - {_, true} <- {:public?, Visibility.is_public?(activity)}, - %User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do + {_, true} <- {:public?, Visibility.is_public?(activity)} do case format do - "html" -> redirect(conn, to: "/notice/#{activity.id}") - _ -> represent_activity(conn, nil, activity, user) + _ -> redirect(conn, to: "/notice/#{activity.id}") end else reason when reason in [{:public?, false}, {:activity, nil}] -> @@ -61,11 +58,9 @@ defmodule Pleroma.Web.OStatus.OStatusController do def activity(%{assigns: %{format: format}} = conn, %{"uuid" => uuid}) do with id <- o_status_url(conn, :activity, uuid), {_, %Activity{} = activity} <- {:activity, Activity.normalize(id)}, - {_, true} <- {:public?, Visibility.is_public?(activity)}, - %User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do + {_, true} <- {:public?, Visibility.is_public?(activity)} do case format do - "html" -> redirect(conn, to: "/notice/#{activity.id}") - _ -> represent_activity(conn, format, activity, user) + _ -> redirect(conn, to: "/notice/#{activity.id}") end else reason when reason in [{:public?, false}, {:activity, nil}] -> @@ -81,7 +76,15 @@ defmodule Pleroma.Web.OStatus.OStatusController do {_, true} <- {:public?, Visibility.is_public?(activity)}, %User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do cond do - format == "html" && activity.data["type"] == "Create" -> + format in ["json", "activity+json"] -> + if activity.local do + %{data: %{"id" => redirect_url}} = Object.normalize(activity) + redirect(conn, external: redirect_url) + else + {:error, :not_found} + end + + activity.data["type"] == "Create" -> %Object{} = object = Object.normalize(activity) RedirectController.redirector_with_meta( @@ -94,11 +97,8 @@ defmodule Pleroma.Web.OStatus.OStatusController do } ) - format == "html" -> - RedirectController.redirector(conn, nil) - true -> - represent_activity(conn, format, activity, user) + RedirectController.redirector(conn, nil) end else reason when reason in [{:public?, false}, {:activity, nil}] -> @@ -135,24 +135,6 @@ defmodule Pleroma.Web.OStatus.OStatusController do end end - defp represent_activity( - conn, - "activity+json", - %Activity{data: %{"type" => "Create"}} = activity, - _user - ) do - object = Object.normalize(activity) - - conn - |> put_resp_header("content-type", "application/activity+json") - |> put_view(ObjectView) - |> render("object.json", %{object: object}) - end - - defp represent_activity(_conn, _, _, _) do - {:error, :not_found} - end - def errors(conn, {:error, :not_found}) do render_error(conn, :not_found, "Not found") end -- cgit v1.2.3 From 80ededc04f4d4ba8318290976025b645a0ba3f95 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Tue, 26 Nov 2019 19:53:43 +0700 Subject: Add `direct_conversation_id` to web push payload --- lib/pleroma/activity.ex | 13 +++++++++++++ lib/pleroma/web/mastodon_api/views/status_view.ex | 10 ++-------- lib/pleroma/web/push/impl.ex | 6 +++++- 3 files changed, 20 insertions(+), 9 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex index 7e283df32..cd7a5aae9 100644 --- a/lib/pleroma/activity.ex +++ b/lib/pleroma/activity.ex @@ -303,4 +303,17 @@ defmodule Pleroma.Activity do end defdelegate search(user, query, options \\ []), to: Pleroma.Activity.Search + + def direct_conversation_id(activity, for_user) do + alias Pleroma.Conversation.Participation + + with %{data: %{"context" => context}} when is_binary(context) <- activity, + %Pleroma.Conversation{} = conversation <- Pleroma.Conversation.get_for_ap_id(context), + %Participation{id: participation_id} <- + Participation.for_user_and_conversation(for_user, conversation) do + participation_id + else + _ -> nil + end + end end diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index baff54151..a0257dfa6 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -9,8 +9,6 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do alias Pleroma.Activity alias Pleroma.ActivityExpiration - alias Pleroma.Conversation - alias Pleroma.Conversation.Participation alias Pleroma.HTML alias Pleroma.Object alias Pleroma.Repo @@ -245,12 +243,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do direct_conversation_id = with {_, nil} <- {:direct_conversation_id, opts[:direct_conversation_id]}, {_, true} <- {:include_id, opts[:with_direct_conversation_id]}, - {_, %User{} = for_user} <- {:for_user, opts[:for]}, - %{data: %{"context" => context}} when is_binary(context) <- activity, - %Conversation{} = conversation <- Conversation.get_for_ap_id(context), - %Participation{id: participation_id} <- - Participation.for_user_and_conversation(for_user, conversation) do - participation_id + {_, %User{} = for_user} <- {:for_user, opts[:for]} do + Activity.direct_conversation_id(activity, for_user) else {:direct_conversation_id, participation_id} when is_integer(participation_id) -> participation_id diff --git a/lib/pleroma/web/push/impl.ex b/lib/pleroma/web/push/impl.ex index dd445e8bf..b01ae0f80 100644 --- a/lib/pleroma/web/push/impl.ex +++ b/lib/pleroma/web/push/impl.ex @@ -33,6 +33,8 @@ defmodule Pleroma.Web.Push.Impl do gcm_api_key = Application.get_env(:web_push_encryption, :gcm_api_key) avatar_url = User.avatar_url(actor) object = Object.normalize(activity) + user = User.get_cached_by_id(user_id) + direct_conversation_id = Activity.direct_conversation_id(activity, user) for subscription <- fetch_subsriptions(user_id), get_in(subscription.data, ["alerts", type]) do @@ -45,7 +47,9 @@ defmodule Pleroma.Web.Push.Impl do icon: avatar_url, preferred_locale: "en", pleroma: %{ - activity_id: activity_id + activity_id: activity_id, + direct_conversation_id: direct_conversation_id, + account: user.ap_id } } |> Jason.encode!() -- cgit v1.2.3 From 4af69f047db815a2349cadc757d5cff39174d83d Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Wed, 27 Nov 2019 02:32:55 +0700 Subject: Remove `account` field from web push payload --- lib/pleroma/web/push/impl.ex | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/push/impl.ex b/lib/pleroma/web/push/impl.ex index b01ae0f80..3de7af708 100644 --- a/lib/pleroma/web/push/impl.ex +++ b/lib/pleroma/web/push/impl.ex @@ -48,8 +48,7 @@ defmodule Pleroma.Web.Push.Impl do preferred_locale: "en", pleroma: %{ activity_id: activity_id, - direct_conversation_id: direct_conversation_id, - account: user.ap_id + direct_conversation_id: direct_conversation_id } } |> Jason.encode!() -- cgit v1.2.3 From 1fc28a4b441fdc0de8b2b43e2b045da38ee50b0a Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Tue, 26 Nov 2019 18:48:56 +0700 Subject: Add a view for the move notification --- lib/pleroma/activity.ex | 3 +- .../web/mastodon_api/views/notification_view.ex | 38 +++++++++------------- lib/pleroma/web/push/impl.ex | 2 +- 3 files changed, 18 insertions(+), 25 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex index c1065611b..992298c2d 100644 --- a/lib/pleroma/activity.ex +++ b/lib/pleroma/activity.ex @@ -28,7 +28,8 @@ defmodule Pleroma.Activity do "Create" => "mention", "Follow" => "follow", "Announce" => "reblog", - "Like" => "favourite" + "Like" => "favourite", + "Move" => "move" } @mastodon_to_ap_notification_types for {k, v} <- @mastodon_notification_types, diff --git a/lib/pleroma/web/mastodon_api/views/notification_view.ex b/lib/pleroma/web/mastodon_api/views/notification_view.ex index 5e3dbe728..ddd7f5318 100644 --- a/lib/pleroma/web/mastodon_api/views/notification_view.ex +++ b/lib/pleroma/web/mastodon_api/views/notification_view.ex @@ -37,32 +37,24 @@ defmodule Pleroma.Web.MastodonAPI.NotificationView do } case mastodon_type do - "mention" -> - response - |> Map.merge(%{ - status: StatusView.render("show.json", %{activity: activity, for: user}) - }) - - "favourite" -> - response - |> Map.merge(%{ - status: StatusView.render("show.json", %{activity: parent_activity, for: user}) - }) - - "reblog" -> - response - |> Map.merge(%{ - status: StatusView.render("show.json", %{activity: parent_activity, for: user}) - }) - - "follow" -> - response - - _ -> - nil + "mention" -> put_status(response, activity, user) + "favourite" -> put_status(response, parent_activity, user) + "reblog" -> put_status(response, parent_activity, user) + "move" -> put_target(response, activity, user) + "follow" -> response + _ -> nil end else _ -> nil end end + + defp put_status(response, activity, user) do + Map.put(response, :status, StatusView.render("show.json", %{activity: activity, for: user})) + end + + defp put_target(response, activity, user) do + target = User.get_cached_by_ap_id(activity.data["target"]) + Map.put(response, :target, AccountView.render("show.json", %{user: target, for: user})) + end end diff --git a/lib/pleroma/web/push/impl.ex b/lib/pleroma/web/push/impl.ex index dd445e8bf..8c131409d 100644 --- a/lib/pleroma/web/push/impl.ex +++ b/lib/pleroma/web/push/impl.ex @@ -16,7 +16,7 @@ defmodule Pleroma.Web.Push.Impl do require Logger import Ecto.Query - @types ["Create", "Follow", "Announce", "Like"] + @types ["Create", "Follow", "Announce", "Like", "Move"] @doc "Performs sending notifications for user subscriptions" @spec perform(Notification.t()) :: list(any) | :error -- cgit v1.2.3 From f595cfe6230715681e8ba93f73480bf695b3a243 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Wed, 27 Nov 2019 19:43:47 +0700 Subject: Remove User.user_info/2 --- lib/pleroma/user.ex | 25 ---------------------- lib/pleroma/web/mastodon_api/views/account_view.ex | 11 +++++----- 2 files changed, 5 insertions(+), 31 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 3010fe87f..b18a4c6a5 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -177,20 +177,6 @@ defmodule Pleroma.User do def ap_following(%User{following_address: fa}) when is_binary(fa), do: fa def ap_following(%User{} = user), do: "#{ap_id(user)}/following" - def user_info(%User{} = user, args \\ %{}) do - following_count = Map.get(args, :following_count, user.following_count) - follower_count = Map.get(args, :follower_count, user.follower_count) - - %{ - note_count: user.note_count, - locked: user.locked, - confirmation_pending: user.confirmation_pending, - default_scope: user.default_scope, - follower_count: follower_count, - following_count: following_count - } - end - def follow_state(%User{} = user, %User{} = target) do case Utils.fetch_latest_follow(user, target) do %{data: %{"state" => state}} -> state @@ -209,10 +195,6 @@ defmodule Pleroma.User do Cachex.put(:user_cache, "follow_state:#{user_ap_id}|#{target_ap_id}", state) end - def set_info_cache(user, args) do - Cachex.put(:user_cache, "user_info:#{user.id}", user_info(user, args)) - end - @spec restrict_deactivated(Ecto.Query.t()) :: Ecto.Query.t() def restrict_deactivated(query) do from(u in query, where: u.deactivated != ^true) @@ -614,7 +596,6 @@ defmodule Pleroma.User do def set_cache(%User{} = user) do Cachex.put(:user_cache, "ap_id:#{user.ap_id}", user) Cachex.put(:user_cache, "nickname:#{user.nickname}", user) - Cachex.put(:user_cache, "user_info:#{user.id}", user_info(user)) {:ok, user} end @@ -633,7 +614,6 @@ defmodule Pleroma.User do def invalidate_cache(user) do Cachex.del(:user_cache, "ap_id:#{user.ap_id}") Cachex.del(:user_cache, "nickname:#{user.nickname}") - Cachex.del(:user_cache, "user_info:#{user.id}") end def get_cached_by_ap_id(ap_id) do @@ -701,11 +681,6 @@ defmodule Pleroma.User do get_by_nickname(nickname_or_email) || get_by_email(nickname_or_email) end - def get_cached_user_info(user) do - key = "user_info:#{user.id}" - Cachex.fetch!(:user_cache, key, fn -> user_info(user) end) - end - def fetch_by_nickname(nickname), do: ActivityPub.make_user_from_nickname(nickname) def get_or_fetch_by_nickname(nickname) do diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index e30fed610..7f50f3aa6 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -71,18 +71,17 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do image = User.avatar_url(user) |> MediaProxy.url() header = User.banner_url(user) |> MediaProxy.url() - user_info = User.get_cached_user_info(user) following_count = if !user.hide_follows_count or !user.hide_follows or opts[:for] == user do - user_info.following_count + user.following_count else 0 end followers_count = if !user.hide_followers_count or !user.hide_followers or opts[:for] == user do - user_info.follower_count + user.follower_count else 0 end @@ -144,7 +143,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do # Pleroma extension pleroma: %{ - confirmation_pending: user_info.confirmation_pending, + confirmation_pending: user.confirmation_pending, tags: user.tags, hide_followers_count: user.hide_followers_count, hide_follows_count: user.hide_follows_count, @@ -157,7 +156,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do } } |> maybe_put_role(user, opts[:for]) - |> maybe_put_settings(user, opts[:for], user_info) + |> maybe_put_settings(user, opts[:for], opts) |> maybe_put_notification_settings(user, opts[:for]) |> maybe_put_settings_store(user, opts[:for], opts) |> maybe_put_chat_token(user, opts[:for], opts) @@ -191,7 +190,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do data, %User{id: user_id} = user, %User{id: user_id}, - _user_info + _opts ) do data |> Kernel.put_in([:source, :privacy], user.default_scope) -- cgit v1.2.3 From f36724efb1fc0806e11b4c0c32a03d1aeee13da6 Mon Sep 17 00:00:00 2001 From: lain Date: Wed, 27 Nov 2019 14:13:36 +0100 Subject: User: Never return nil for user follower counts. --- lib/pleroma/user.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 3010fe87f..16d0889c4 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -178,8 +178,8 @@ defmodule Pleroma.User do def ap_following(%User{} = user), do: "#{ap_id(user)}/following" def user_info(%User{} = user, args \\ %{}) do - following_count = Map.get(args, :following_count, user.following_count) - follower_count = Map.get(args, :follower_count, user.follower_count) + following_count = Map.get(args, :following_count, user.following_count) || 0 + follower_count = Map.get(args, :follower_count, user.follower_count) || 0 %{ note_count: user.note_count, -- cgit v1.2.3 From a98cda77580ead154dd2cb020c6d4ebc1e719d86 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Fri, 29 Nov 2019 15:49:35 +0700 Subject: Fix Pleroma.HTML.extract_first_external_url/2 --- lib/pleroma/html.ex | 1 + 1 file changed, 1 insertion(+) (limited to 'lib') diff --git a/lib/pleroma/html.ex b/lib/pleroma/html.ex index 997e965f0..4acd46253 100644 --- a/lib/pleroma/html.ex +++ b/lib/pleroma/html.ex @@ -91,6 +91,7 @@ defmodule Pleroma.HTML do Cachex.fetch!(:scrubber_cache, key, fn _key -> result = content + |> HtmlEntities.decode() |> Floki.filter_out("a.mention,a.hashtag,a[rel~=\"tag\"]") |> Floki.attribute("a", "href") |> Enum.at(0) -- cgit v1.2.3 From 0326683932800c20dcec2b7d3500bff149cf091b Mon Sep 17 00:00:00 2001 From: kPherox Date: Sat, 30 Nov 2019 04:26:45 +0900 Subject: hide follower/following for friendica --- lib/pleroma/web/activity_pub/activity_pub.ex | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index f25314ff6..f32d04175 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -1233,13 +1233,13 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do end end - defp collection_private(data) do - if is_map(data["first"]) and - data["first"]["type"] in ["CollectionPage", "OrderedCollectionPage"] do + defp collection_private(%{"first" => first}) do + if is_map(first) and + first["type"] in ["CollectionPage", "OrderedCollectionPage"] do {:ok, false} else with {:ok, %{"type" => type}} when type in ["CollectionPage", "OrderedCollectionPage"] <- - Fetcher.fetch_and_contain_remote_object_from_id(data["first"]) do + Fetcher.fetch_and_contain_remote_object_from_id(first) do {:ok, false} else {:error, {:ok, %{status: code}}} when code in [401, 403] -> @@ -1254,6 +1254,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do end end + defp collection_private(_data), do: {:ok, true} + def user_data_from_user_object(data) do with {:ok, data} <- MRF.filter(data), {:ok, data} <- object_to_user_data(data) do -- cgit v1.2.3 From cf52106e059560afb50de5ae8044d0a51278fae1 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Mon, 2 Dec 2019 13:38:35 +0700 Subject: Update Floki dependency --- lib/pleroma/html.ex | 1 - 1 file changed, 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/html.ex b/lib/pleroma/html.ex index 4acd46253..997e965f0 100644 --- a/lib/pleroma/html.ex +++ b/lib/pleroma/html.ex @@ -91,7 +91,6 @@ defmodule Pleroma.HTML do Cachex.fetch!(:scrubber_cache, key, fn _key -> result = content - |> HtmlEntities.decode() |> Floki.filter_out("a.mention,a.hashtag,a[rel~=\"tag\"]") |> Floki.attribute("a", "href") |> Enum.at(0) -- cgit v1.2.3