aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorRoman Chvanikov <chvanikoff@gmail.com>2019-04-30 20:17:52 +0700
committerRoman Chvanikov <chvanikoff@gmail.com>2019-04-30 20:17:52 +0700
commit0f0cc2703b7ffb99c58e72782925ea4dd61db41d (patch)
treef640d180d16797a6da98a7d1e1cb7c6fb6350392 /lib
parentb87ad13803df59d88feb736c3d0ff9cf514989d7 (diff)
parent32a4501d2d1cdfef68cbde236482e0c84cce3a7a (diff)
downloadpleroma-0f0cc2703b7ffb99c58e72782925ea4dd61db41d.tar.gz
Merge develop
Diffstat (limited to 'lib')
-rw-r--r--lib/healthcheck.ex60
-rw-r--r--lib/mix/tasks/pleroma/emoji.ex293
-rw-r--r--lib/mix/tasks/pleroma/user.ex20
-rw-r--r--lib/pleroma/PasswordResetToken.ex2
-rw-r--r--lib/pleroma/bookmark.ex60
-rw-r--r--lib/pleroma/emoji.ex165
-rw-r--r--lib/pleroma/gopher/server.ex2
-rw-r--r--lib/pleroma/html.ex29
-rw-r--r--lib/pleroma/list.ex2
-rw-r--r--lib/pleroma/notification.ex2
-rw-r--r--lib/pleroma/object/fetcher.ex2
-rw-r--r--lib/pleroma/user.ex60
-rw-r--r--lib/pleroma/user/info.ex10
-rw-r--r--lib/pleroma/web/activity_pub/activity_pub.ex6
-rw-r--r--lib/pleroma/web/activity_pub/transmogrifier.ex38
-rw-r--r--lib/pleroma/web/admin_api/admin_api_controller.ex24
-rw-r--r--lib/pleroma/web/channels/user_socket.ex2
-rw-r--r--lib/pleroma/web/common_api/common_api.ex12
-rw-r--r--lib/pleroma/web/common_api/utils.ex16
-rw-r--r--lib/pleroma/web/federator/federator.ex2
-rw-r--r--lib/pleroma/web/mastodon_api/mastodon_api.ex28
-rw-r--r--lib/pleroma/web/mastodon_api/mastodon_api_controller.ex148
-rw-r--r--lib/pleroma/web/mastodon_api/views/account_view.ex60
-rw-r--r--lib/pleroma/web/mastodon_api/views/status_view.ex16
-rw-r--r--lib/pleroma/web/mastodon_api/websocket_handler.ex2
-rw-r--r--lib/pleroma/web/media_proxy/media_proxy.ex50
-rw-r--r--lib/pleroma/web/oauth/oauth_controller.ex27
-rw-r--r--lib/pleroma/web/oauth/token.ex2
-rw-r--r--lib/pleroma/web/ostatus/activity_representer.ex2
-rw-r--r--lib/pleroma/web/ostatus/ostatus.ex2
-rw-r--r--lib/pleroma/web/push/impl.ex25
-rw-r--r--lib/pleroma/web/router.ex3
-rw-r--r--lib/pleroma/web/streamer.ex2
-rw-r--r--lib/pleroma/web/twitter_api/controllers/util_controller.ex28
-rw-r--r--lib/pleroma/web/twitter_api/twitter_api.ex2
-rw-r--r--lib/pleroma/web/twitter_api/twitter_api_controller.ex8
-rw-r--r--lib/pleroma/web/twitter_api/views/user_view.ex117
-rw-r--r--lib/pleroma/web/web_finger/web_finger.ex2
38 files changed, 982 insertions, 349 deletions
diff --git a/lib/healthcheck.ex b/lib/healthcheck.ex
new file mode 100644
index 000000000..646fb3b9d
--- /dev/null
+++ b/lib/healthcheck.ex
@@ -0,0 +1,60 @@
+defmodule Pleroma.Healthcheck do
+ @moduledoc """
+ Module collects metrics about app and assign healthy status.
+ """
+ alias Pleroma.Healthcheck
+ alias Pleroma.Repo
+
+ defstruct pool_size: 0,
+ active: 0,
+ idle: 0,
+ memory_used: 0,
+ healthy: true
+
+ @type t :: %__MODULE__{
+ pool_size: non_neg_integer(),
+ active: non_neg_integer(),
+ idle: non_neg_integer(),
+ memory_used: number(),
+ healthy: boolean()
+ }
+
+ @spec system_info() :: t()
+ def system_info do
+ %Healthcheck{
+ memory_used: Float.round(:erlang.memory(:total) / 1024 / 1024, 2)
+ }
+ |> assign_db_info()
+ |> check_health()
+ end
+
+ defp assign_db_info(healthcheck) do
+ database = Application.get_env(:pleroma, Repo)[:database]
+
+ query =
+ "select state, count(pid) from pg_stat_activity where datname = '#{database}' group by state;"
+
+ result = Repo.query!(query)
+ pool_size = Application.get_env(:pleroma, Repo)[:pool_size]
+
+ db_info =
+ Enum.reduce(result.rows, %{active: 0, idle: 0}, fn [state, cnt], states ->
+ if state == "active" do
+ Map.put(states, :active, states.active + cnt)
+ else
+ Map.put(states, :idle, states.idle + cnt)
+ end
+ end)
+ |> Map.put(:pool_size, pool_size)
+
+ Map.merge(healthcheck, db_info)
+ end
+
+ @spec check_health(Healthcheck.t()) :: Healthcheck.t()
+ def check_health(%{pool_size: pool_size, active: active} = check)
+ when active >= pool_size do
+ %{check | healthy: false}
+ end
+
+ def check_health(check), do: check
+end
diff --git a/lib/mix/tasks/pleroma/emoji.ex b/lib/mix/tasks/pleroma/emoji.ex
new file mode 100644
index 000000000..cced73226
--- /dev/null
+++ b/lib/mix/tasks/pleroma/emoji.ex
@@ -0,0 +1,293 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Mix.Tasks.Pleroma.Emoji do
+ use Mix.Task
+
+ @shortdoc "Manages emoji packs"
+ @moduledoc """
+ Manages emoji packs
+
+ ## ls-packs
+
+ mix pleroma.emoji ls-packs [OPTION...]
+
+ Lists the emoji packs and metadata specified in the manifest.
+
+ ### Options
+
+ - `-m, --manifest PATH/URL` - path to a custom manifest, it can
+ either be an URL starting with `http`, in that case the
+ manifest will be fetched from that address, or a local path
+
+ ## get-packs
+
+ mix pleroma.emoji get-packs [OPTION...] PACKS
+
+ Fetches, verifies and installs the specified PACKS from the
+ manifest into the `STATIC-DIR/emoji/PACK-NAME`
+
+ ### Options
+
+ - `-m, --manifest PATH/URL` - same as ls-packs
+
+ ## gen-pack
+
+ mix pleroma.emoji gen-pack PACK-URL
+
+ Creates a new manifest entry and a file list from the specified
+ remote pack file. Currently, only .zip archives are recognized
+ as remote pack files and packs are therefore assumed to be zip
+ archives. This command is intended to run interactively and will
+ first ask you some basic questions about the pack, then download
+ the remote file and generate an SHA256 checksum for it, then
+ generate an emoji file list for you.
+
+ The manifest entry will either be written to a newly created
+ `index.json` file or appended to the existing one, *replacing*
+ the old pack with the same name if it was in the file previously.
+
+ The file list will be written to the file specified previously,
+ *replacing* that file. You _should_ check that the file list doesn't
+ contain anything you don't need in the pack, that is, anything that is
+ not an emoji (the whole pack is downloaded, but only emoji files
+ are extracted).
+ """
+
+ @default_manifest Pleroma.Config.get!([:emoji, :default_manifest])
+
+ def run(["ls-packs" | args]) do
+ Application.ensure_all_started(:hackney)
+
+ {options, [], []} = parse_global_opts(args)
+
+ manifest =
+ fetch_manifest(if options[:manifest], do: options[:manifest], else: @default_manifest)
+
+ Enum.each(manifest, fn {name, info} ->
+ to_print = [
+ {"Name", name},
+ {"Homepage", info["homepage"]},
+ {"Description", info["description"]},
+ {"License", info["license"]},
+ {"Source", info["src"]}
+ ]
+
+ for {param, value} <- to_print do
+ IO.puts(IO.ANSI.format([:bright, param, :normal, ": ", value]))
+ end
+
+ # A newline
+ IO.puts("")
+ end)
+ end
+
+ def run(["get-packs" | args]) do
+ Application.ensure_all_started(:hackney)
+
+ {options, pack_names, []} = parse_global_opts(args)
+
+ manifest_url = if options[:manifest], do: options[:manifest], else: @default_manifest
+
+ manifest = fetch_manifest(manifest_url)
+
+ for pack_name <- pack_names do
+ if Map.has_key?(manifest, pack_name) do
+ pack = manifest[pack_name]
+ src_url = pack["src"]
+
+ IO.puts(
+ IO.ANSI.format([
+ "Downloading ",
+ :bright,
+ pack_name,
+ :normal,
+ " from ",
+ :underline,
+ src_url
+ ])
+ )
+
+ binary_archive = Tesla.get!(src_url).body
+ archive_sha = :crypto.hash(:sha256, binary_archive) |> Base.encode16()
+
+ sha_status_text = ["SHA256 of ", :bright, pack_name, :normal, " source file is ", :bright]
+
+ if archive_sha == String.upcase(pack["src_sha256"]) do
+ IO.puts(IO.ANSI.format(sha_status_text ++ [:green, "OK"]))
+ else
+ IO.puts(IO.ANSI.format(sha_status_text ++ [:red, "BAD"]))
+
+ raise "Bad SHA256 for #{pack_name}"
+ end
+
+ # The url specified in files should be in the same directory
+ files_url = Path.join(Path.dirname(manifest_url), pack["files"])
+
+ IO.puts(
+ IO.ANSI.format([
+ "Fetching the file list for ",
+ :bright,
+ pack_name,
+ :normal,
+ " from ",
+ :underline,
+ files_url
+ ])
+ )
+
+ files = Tesla.get!(files_url).body |> Poison.decode!()
+
+ IO.puts(IO.ANSI.format(["Unpacking ", :bright, pack_name]))
+
+ pack_path =
+ Path.join([
+ Pleroma.Config.get!([:instance, :static_dir]),
+ "emoji",
+ pack_name
+ ])
+
+ files_to_unzip =
+ Enum.map(
+ files,
+ fn {_, f} -> to_charlist(f) end
+ )
+
+ {:ok, _} =
+ :zip.unzip(binary_archive,
+ cwd: pack_path,
+ file_list: files_to_unzip
+ )
+
+ IO.puts(IO.ANSI.format(["Writing emoji.txt for ", :bright, pack_name]))
+
+ emoji_txt_str =
+ Enum.map(
+ files,
+ fn {shortcode, path} ->
+ emojo_path = Path.join("/emoji/#{pack_name}", path)
+ "#{shortcode}, #{emojo_path}"
+ end
+ )
+ |> Enum.join("\n")
+
+ File.write!(Path.join(pack_path, "emoji.txt"), emoji_txt_str)
+ else
+ IO.puts(IO.ANSI.format([:bright, :red, "No pack named \"#{pack_name}\" found"]))
+ end
+ end
+ end
+
+ def run(["gen-pack", src]) do
+ Application.ensure_all_started(:hackney)
+
+ proposed_name = Path.basename(src) |> Path.rootname()
+ name = String.trim(IO.gets("Pack name [#{proposed_name}]: "))
+ # If there's no name, use the default one
+ name = if String.length(name) > 0, do: name, else: proposed_name
+
+ license = String.trim(IO.gets("License: "))
+ homepage = String.trim(IO.gets("Homepage: "))
+ description = String.trim(IO.gets("Description: "))
+
+ proposed_files_name = "#{name}.json"
+ files_name = String.trim(IO.gets("Save file list to [#{proposed_files_name}]: "))
+ files_name = if String.length(files_name) > 0, do: files_name, else: proposed_files_name
+
+ default_exts = [".png", ".gif"]
+ default_exts_str = Enum.join(default_exts, " ")
+
+ exts =
+ String.trim(
+ IO.gets("Emoji file extensions (separated with spaces) [#{default_exts_str}]: ")
+ )
+
+ exts =
+ if String.length(exts) > 0 do
+ String.split(exts, " ")
+ |> Enum.filter(fn e -> e |> String.trim() |> String.length() > 0 end)
+ else
+ default_exts
+ end
+
+ IO.puts("Downloading the pack and generating SHA256")
+
+ binary_archive = Tesla.get!(src).body
+ archive_sha = :crypto.hash(:sha256, binary_archive) |> Base.encode16()
+
+ IO.puts("SHA256 is #{archive_sha}")
+
+ pack_json = %{
+ name => %{
+ license: license,
+ homepage: homepage,
+ description: description,
+ src: src,
+ src_sha256: archive_sha,
+ files: files_name
+ }
+ }
+
+ tmp_pack_dir = Path.join(System.tmp_dir!(), "emoji-pack-#{name}")
+
+ {:ok, _} =
+ :zip.unzip(
+ binary_archive,
+ cwd: tmp_pack_dir
+ )
+
+ emoji_map = Pleroma.Emoji.make_shortcode_to_file_map(tmp_pack_dir, exts)
+
+ File.write!(files_name, Poison.encode!(emoji_map, pretty: true))
+
+ IO.puts("""
+
+ #{files_name} has been created and contains the list of all found emojis in the pack.
+ Please review the files in the remove those not needed.
+ """)
+
+ if File.exists?("index.json") do
+ existing_data = File.read!("index.json") |> Poison.decode!()
+
+ File.write!(
+ "index.json",
+ Poison.encode!(
+ Map.merge(
+ existing_data,
+ pack_json
+ ),
+ pretty: true
+ )
+ )
+
+ IO.puts("index.json file has been update with the #{name} pack")
+ else
+ File.write!("index.json", Poison.encode!(pack_json, pretty: true))
+
+ IO.puts("index.json has been created with the #{name} pack")
+ end
+ end
+
+ defp fetch_manifest(from) do
+ Poison.decode!(
+ if String.starts_with?(from, "http") do
+ Tesla.get!(from).body
+ else
+ File.read!(from)
+ end
+ )
+ end
+
+ defp parse_global_opts(args) do
+ OptionParser.parse(
+ args,
+ strict: [
+ manifest: :string
+ ],
+ aliases: [
+ m: :manifest
+ ]
+ )
+ end
+end
diff --git a/lib/mix/tasks/pleroma/user.ex b/lib/mix/tasks/pleroma/user.ex
index 441168df2..b396ff0de 100644
--- a/lib/mix/tasks/pleroma/user.ex
+++ b/lib/mix/tasks/pleroma/user.ex
@@ -162,7 +162,7 @@ defmodule Mix.Tasks.Pleroma.User do
def run(["rm", nickname]) do
Common.start_pleroma()
- with %User{local: true} = user <- User.get_by_nickname(nickname) do
+ with %User{local: true} = user <- User.get_cached_by_nickname(nickname) do
User.delete(user)
Mix.shell().info("User #{nickname} deleted.")
else
@@ -174,7 +174,7 @@ defmodule Mix.Tasks.Pleroma.User do
def run(["toggle_activated", nickname]) do
Common.start_pleroma()
- with %User{} = user <- User.get_by_nickname(nickname) do
+ with %User{} = user <- User.get_cached_by_nickname(nickname) do
{:ok, user} = User.deactivate(user, !user.info.deactivated)
Mix.shell().info(
@@ -189,7 +189,7 @@ defmodule Mix.Tasks.Pleroma.User do
def run(["reset_password", nickname]) do
Common.start_pleroma()
- with %User{local: true} = user <- User.get_by_nickname(nickname),
+ with %User{local: true} = user <- User.get_cached_by_nickname(nickname),
{:ok, token} <- Pleroma.PasswordResetToken.create_token(user) do
Mix.shell().info("Generated password reset token for #{user.nickname}")
@@ -211,14 +211,14 @@ defmodule Mix.Tasks.Pleroma.User do
def run(["unsubscribe", nickname]) do
Common.start_pleroma()
- with %User{} = user <- User.get_by_nickname(nickname) do
+ with %User{} = user <- User.get_cached_by_nickname(nickname) do
Mix.shell().info("Deactivating #{user.nickname}")
User.deactivate(user)
{:ok, friends} = User.get_friends(user)
Enum.each(friends, fn friend ->
- user = User.get_by_id(user.id)
+ user = User.get_cached_by_id(user.id)
Mix.shell().info("Unsubscribing #{friend.nickname} from #{user.nickname}")
User.unfollow(user, friend)
@@ -226,7 +226,7 @@ defmodule Mix.Tasks.Pleroma.User do
:timer.sleep(500)
- user = User.get_by_id(user.id)
+ user = User.get_cached_by_id(user.id)
if Enum.empty?(user.following) do
Mix.shell().info("Successfully unsubscribed all followers from #{user.nickname}")
@@ -250,7 +250,7 @@ defmodule Mix.Tasks.Pleroma.User do
]
)
- with %User{local: true} = user <- User.get_by_nickname(nickname) do
+ with %User{local: true} = user <- User.get_cached_by_nickname(nickname) do
user =
case Keyword.get(options, :moderator) do
nil -> user
@@ -277,7 +277,7 @@ defmodule Mix.Tasks.Pleroma.User do
def run(["tag", nickname | tags]) do
Common.start_pleroma()
- with %User{} = user <- User.get_by_nickname(nickname) do
+ with %User{} = user <- User.get_cached_by_nickname(nickname) do
user = user |> User.tag(tags)
Mix.shell().info("Tags of #{user.nickname}: #{inspect(tags)}")
@@ -290,7 +290,7 @@ defmodule Mix.Tasks.Pleroma.User do
def run(["untag", nickname | tags]) do
Common.start_pleroma()
- with %User{} = user <- User.get_by_nickname(nickname) do
+ with %User{} = user <- User.get_cached_by_nickname(nickname) do
user = user |> User.untag(tags)
Mix.shell().info("Tags of #{user.nickname}: #{inspect(tags)}")
@@ -379,7 +379,7 @@ defmodule Mix.Tasks.Pleroma.User do
def run(["delete_activities", nickname]) do
Common.start_pleroma()
- with %User{local: true} = user <- User.get_by_nickname(nickname) do
+ with %User{local: true} = user <- User.get_cached_by_nickname(nickname) do
User.delete_user_activities(user)
Mix.shell().info("User #{nickname} statuses deleted.")
else
diff --git a/lib/pleroma/PasswordResetToken.ex b/lib/pleroma/PasswordResetToken.ex
index 7afbc8751..f31ea5bc5 100644
--- a/lib/pleroma/PasswordResetToken.ex
+++ b/lib/pleroma/PasswordResetToken.ex
@@ -39,7 +39,7 @@ defmodule Pleroma.PasswordResetToken do
def reset_password(token, data) do
with %{used: false} = token <- Repo.get_by(PasswordResetToken, %{token: token}),
- %User{} = user <- User.get_by_id(token.user_id),
+ %User{} = user <- User.get_cached_by_id(token.user_id),
{:ok, _user} <- User.reset_password(user, data),
{:ok, token} <- Repo.update(used_changeset(token)) do
{:ok, token}
diff --git a/lib/pleroma/bookmark.ex b/lib/pleroma/bookmark.ex
new file mode 100644
index 000000000..7f8fd43b6
--- /dev/null
+++ b/lib/pleroma/bookmark.ex
@@ -0,0 +1,60 @@
+defmodule Pleroma.Bookmark do
+ use Ecto.Schema
+
+ import Ecto.Changeset
+ import Ecto.Query
+
+ alias Pleroma.Activity
+ alias Pleroma.Bookmark
+ alias Pleroma.FlakeId
+ alias Pleroma.Repo
+ alias Pleroma.User
+
+ @type t :: %__MODULE__{}
+
+ schema "bookmarks" do
+ belongs_to(:user, User, type: FlakeId)
+ belongs_to(:activity, Activity, type: FlakeId)
+
+ timestamps()
+ end
+
+ @spec create(FlakeId.t(), FlakeId.t()) :: {:ok, Bookmark.t()} | {:error, Changeset.t()}
+ def create(user_id, activity_id) do
+ attrs = %{
+ user_id: user_id,
+ activity_id: activity_id
+ }
+
+ %Bookmark{}
+ |> cast(attrs, [:user_id, :activity_id])
+ |> validate_required([:user_id, :activity_id])
+ |> unique_constraint(:activity_id, name: :bookmarks_user_id_activity_id_index)
+ |> Repo.insert()
+ end
+
+ @spec for_user_query(FlakeId.t()) :: Ecto.Query.t()
+ def for_user_query(user_id) do
+ Bookmark
+ |> where(user_id: ^user_id)
+ |> join(:inner, [b], activity in assoc(b, :activity))
+ |> preload([b, a], activity: a)
+ end
+
+ def get(user_id, activity_id) do
+ Bookmark
+ |> where(user_id: ^user_id)
+ |> where(activity_id: ^activity_id)
+ |> Repo.one()
+ end
+
+ @spec destroy(FlakeId.t(), FlakeId.t()) :: {:ok, Bookmark.t()} | {:error, Changeset.t()}
+ def destroy(user_id, activity_id) do
+ from(b in Bookmark,
+ where: b.user_id == ^user_id,
+ where: b.activity_id == ^activity_id
+ )
+ |> Repo.one()
+ |> Repo.delete()
+ end
+end
diff --git a/lib/pleroma/emoji.ex b/lib/pleroma/emoji.ex
index 87c7f2cec..6390cce4c 100644
--- a/lib/pleroma/emoji.ex
+++ b/lib/pleroma/emoji.ex
@@ -6,7 +6,7 @@ defmodule Pleroma.Emoji do
@moduledoc """
The emojis are loaded from:
- * the built-in Finmojis (if enabled in configuration),
+ * emoji packs in INSTANCE-DIR/emoji
* the files: `config/emoji.txt` and `config/custom_emoji.txt`
* glob paths, nested folder is used as tag name for grouping e.g. priv/static/emoji/custom/nested_folder
@@ -14,6 +14,8 @@ defmodule Pleroma.Emoji do
"""
use GenServer
+ require Logger
+
@type pattern :: Regex.t() | module() | String.t()
@type patterns :: pattern() | [pattern()]
@type group_patterns :: keyword(patterns())
@@ -79,95 +81,94 @@ defmodule Pleroma.Emoji do
end
defp load do
- finmoji_enabled = Keyword.get(Application.get_env(:pleroma, :instance), :finmoji_enabled)
+ emoji_dir_path =
+ Path.join(
+ Pleroma.Config.get!([:instance, :static_dir]),
+ "emoji"
+ )
+
+ case File.ls(emoji_dir_path) do
+ {:error, :enoent} ->
+ # The custom emoji directory doesn't exist,
+ # don't do anything
+ nil
+
+ {:error, e} ->
+ # There was some other error
+ Logger.error("Could not access the custom emoji directory #{emoji_dir_path}: #{e}")
+
+ {:ok, packs} ->
+ # Print the packs we've found
+ Logger.info("Found emoji packs: #{Enum.join(packs, ", ")}")
+
+ emojis =
+ Enum.flat_map(
+ packs,
+ fn pack -> load_pack(Path.join(emoji_dir_path, pack)) end
+ )
+
+ true = :ets.insert(@ets, emojis)
+ end
+
+ # Compat thing for old custom emoji handling & default emoji,
+ # it should run even if there are no emoji packs
shortcode_globs = Application.get_env(:pleroma, :emoji)[:shortcode_globs] || []
emojis =
- (load_finmoji(finmoji_enabled) ++
- load_from_file("config/emoji.txt") ++
+ (load_from_file("config/emoji.txt") ++
load_from_file("config/custom_emoji.txt") ++
load_from_globs(shortcode_globs))
|> Enum.reject(fn value -> value == nil end)
true = :ets.insert(@ets, emojis)
+
:ok
end
- @finmoji [
- "a_trusted_friend",
- "alandislands",
- "association",
- "auroraborealis",
- "baby_in_a_box",
- "bear",
- "black_gold",
- "christmasparty",
- "crosscountryskiing",
- "cupofcoffee",
- "education",
- "fashionista_finns",
- "finnishlove",
- "flag",
- "forest",
- "four_seasons_of_bbq",
- "girlpower",
- "handshake",
- "happiness",
- "headbanger",
- "icebreaker",
- "iceman",
- "joulutorttu",
- "kaamos",
- "kalsarikannit_f",
- "kalsarikannit_m",
- "karjalanpiirakka",
- "kicksled",
- "kokko",
- "lavatanssit",
- "losthopes_f",
- "losthopes_m",
- "mattinykanen",
- "meanwhileinfinland",
- "moominmamma",
- "nordicfamily",
- "out_of_office",
- "peacemaker",
- "perkele",
- "pesapallo",
- "polarbear",
- "pusa_hispida_saimensis",
- "reindeer",
- "sami",
- "sauna_f",
- "sauna_m",
- "sauna_whisk",
- "sisu",
- "stuck",
- "suomimainittu",
- "superfood",
- "swan",
- "the_cap",
- "the_conductor",
- "the_king",
- "the_voice",
- "theoriginalsanta",
- "tomoffinland",
- "torillatavataan",
- "unbreakable",
- "waiting",
- "white_nights",
- "woollysocks"
- ]
-
- defp load_finmoji(true) do
- Enum.map(@finmoji, fn finmoji ->
- file_name = "/finmoji/128px/#{finmoji}-128.png"
- group = match_extra(@groups, file_name)
- {finmoji, file_name, to_string(group)}
- end)
+ defp load_pack(pack_dir) do
+ pack_name = Path.basename(pack_dir)
+
+ emoji_txt = Path.join(pack_dir, "emoji.txt")
+
+ if File.exists?(emoji_txt) do
+ load_from_file(emoji_txt)
+ else
+ Logger.info(
+ "No emoji.txt found for pack \"#{pack_name}\", assuming all .png files are emoji"
+ )
+
+ make_shortcode_to_file_map(pack_dir, [".png"])
+ |> Enum.map(fn {shortcode, rel_file} ->
+ filename = Path.join("/emoji/#{pack_name}", rel_file)
+
+ {shortcode, filename, [to_string(match_extra(@groups, filename))]}
+ end)
+ end
+ end
+
+ def make_shortcode_to_file_map(pack_dir, exts) do
+ find_all_emoji(pack_dir, exts)
+ |> Enum.map(&Path.relative_to(&1, pack_dir))
+ |> Enum.map(fn f -> {f |> Path.basename() |> Path.rootname(), f} end)
+ |> Enum.into(%{})
end
- defp load_finmoji(_), do: []
+ def find_all_emoji(dir, exts) do
+ Enum.reduce(
+ File.ls!(dir),
+ [],
+ fn f, acc ->
+ filepath = Path.join(dir, f)
+
+ if File.dir?(filepath) do
+ acc ++ find_all_emoji(filepath, exts)
+ else
+ acc ++ [filepath]
+ end
+ end
+ )
+ |> Enum.filter(fn f -> Path.extname(f) in exts end)
+ end
defp load_from_file(file) do
if File.exists?(file) do
@@ -182,11 +183,11 @@ defmodule Pleroma.Emoji do
|> Stream.map(&String.trim/1)
|> Stream.map(fn line ->
case String.split(line, ~r/,\s*/) do
- [name, file, tags] ->
- {name, file, tags}
-
[name, file] ->
- {name, file, to_string(match_extra(@groups, file))}
+ {name, file, [to_string(match_extra(@groups, file))]}
+
+ [name, file | tags] ->
+ {name, file, tags}
_ ->
nil
@@ -209,7 +210,7 @@ defmodule Pleroma.Emoji do
tag = match_extra(@groups, Path.join("/", Path.relative_to(path, static_path)))
shortcode = Path.basename(path, Path.extname(path))
external_path = Path.join("/", Path.relative_to(path, static_path))
- {shortcode, external_path, to_string(tag)}
+ {shortcode, external_path, [to_string(tag)]}
end)
end
diff --git a/lib/pleroma/gopher/server.ex b/lib/pleroma/gopher/server.ex
index 2ebc5d5f7..1d2e0785c 100644
--- a/lib/pleroma/gopher/server.ex
+++ b/lib/pleroma/gopher/server.ex
@@ -76,7 +76,7 @@ defmodule Pleroma.Gopher.Server.ProtocolHandler do
|> Enum.map(fn activity ->
user = User.get_cached_by_ap_id(activity.data["actor"])
- object = Object.normalize(activity.data["object"])
+ object = Object.normalize(activity)
like_count = object["like_count"] || 0
announcement_count = object["announcement_count"] || 0
diff --git a/lib/pleroma/html.ex b/lib/pleroma/html.ex
index 4b42d8c9b..cf6c0ee0a 100644
--- a/lib/pleroma/html.ex
+++ b/lib/pleroma/html.ex
@@ -106,7 +106,14 @@ defmodule Pleroma.HTML.Scrubber.TwitterText do
# links
Meta.allow_tag_with_uri_attributes("a", ["href", "data-user", "data-tag"], @valid_schemes)
- Meta.allow_tag_with_these_attributes("a", ["name", "title", "class"])
+
+ Meta.allow_tag_with_this_attribute_values("a", "class", [
+ "hashtag",
+ "u-url",
+ "mention",
+ "u-url mention",
+ "mention u-url"
+ ])
Meta.allow_tag_with_this_attribute_values("a", "rel", [
"tag",
@@ -115,12 +122,15 @@ defmodule Pleroma.HTML.Scrubber.TwitterText do
"noreferrer"
])
+ Meta.allow_tag_with_these_attributes("a", ["name", "title"])
+
# paragraphs and linebreaks
Meta.allow_tag_with_these_attributes("br", [])
Meta.allow_tag_with_these_attributes("p", [])
# microformats
- Meta.allow_tag_with_these_attributes("span", ["class"])
+ Meta.allow_tag_with_this_attribute_values("span", "class", ["h-card"])
+ Meta.allow_tag_with_these_attributes("span", [])
# allow inline images for custom emoji
@allow_inline_images Keyword.get(@markup, :allow_inline_images)
@@ -155,7 +165,14 @@ defmodule Pleroma.HTML.Scrubber.Default do
Meta.strip_comments()
Meta.allow_tag_with_uri_attributes("a", ["href", "data-user", "data-tag"], @valid_schemes)
- Meta.allow_tag_with_these_attributes("a", ["name", "title", "class"])
+
+ Meta.allow_tag_with_this_attribute_values("a", "class", [
+ "hashtag",
+ "u-url",
+ "mention",
+ "u-url mention",
+ "mention u-url"
+ ])
Meta.allow_tag_with_this_attribute_values("a", "rel", [
"tag",
@@ -164,6 +181,8 @@ defmodule Pleroma.HTML.Scrubber.Default do
"noreferrer"
])
+ Meta.allow_tag_with_these_attributes("a", ["name", "title"])
+
Meta.allow_tag_with_these_attributes("abbr", ["title"])
Meta.allow_tag_with_these_attributes("b", [])
@@ -177,11 +196,13 @@ defmodule Pleroma.HTML.Scrubber.Default do
Meta.allow_tag_with_these_attributes("ol", [])
Meta.allow_tag_with_these_attributes("p", [])
Meta.allow_tag_with_these_attributes("pre", [])
- Meta.allow_tag_with_these_attributes("span", ["class"])
Meta.allow_tag_with_these_attributes("strong", [])
Meta.allow_tag_with_these_attributes("u", [])
Meta.allow_tag_with_these_attributes("ul", [])
+ Meta.allow_tag_with_this_attribute_values("span", "class", ["h-card"])
+ Meta.allow_tag_with_these_attributes("span", [])
+
@allow_inline_images Keyword.get(@markup, :allow_inline_images)
if @allow_inline_images do
diff --git a/lib/pleroma/list.ex b/lib/pleroma/list.ex
index 110be8355..a5b1cad68 100644
--- a/lib/pleroma/list.ex
+++ b/lib/pleroma/list.ex
@@ -80,7 +80,7 @@ defmodule Pleroma.List do
# Get lists to which the account belongs.
def get_lists_account_belongs(%User{} = owner, account_id) do
- user = User.get_by_id(account_id)
+ user = User.get_cached_by_id(account_id)
query =
from(
diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex
index d79f0f563..bf45be961 100644
--- a/lib/pleroma/notification.ex
+++ b/lib/pleroma/notification.ex
@@ -220,7 +220,7 @@ defmodule Pleroma.Notification do
def skip?(:follows, activity, %{info: %{notification_settings: %{"follows" => false}}} = user) do
actor = activity.data["actor"]
- followed = User.get_by_ap_id(actor)
+ followed = User.get_cached_by_ap_id(actor)
User.following?(user, followed)
end
diff --git a/lib/pleroma/object/fetcher.ex b/lib/pleroma/object/fetcher.ex
index 138e7866f..8d4bcc95e 100644
--- a/lib/pleroma/object/fetcher.ex
+++ b/lib/pleroma/object/fetcher.ex
@@ -39,7 +39,7 @@ defmodule Pleroma.Object.Fetcher do
Logger.info("Couldn't get object via AP, trying out OStatus fetching...")
case OStatus.fetch_activity_from_url(id) do
- {:ok, [activity | _]} -> {:ok, Object.normalize(activity.data["object"], false)}
+ {:ok, [activity | _]} -> {:ok, Object.normalize(activity, false)}
e -> e
end
end
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index 2509d2366..4417a12dd 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -10,6 +10,7 @@ defmodule Pleroma.User do
alias Comeonin.Pbkdf2
alias Pleroma.Activity
+ alias Pleroma.Bookmark
alias Pleroma.Formatter
alias Pleroma.Notification
alias Pleroma.Object
@@ -53,9 +54,9 @@ defmodule Pleroma.User do
field(:search_rank, :float, virtual: true)
field(:search_type, :integer, virtual: true)
field(:tags, {:array, :string}, default: [])
- field(:bookmarks, {:array, :string}, default: [])
field(:last_refreshed_at, :naive_datetime_usec)
field(:last_digest_emailed_at, :naive_datetime)
+ has_many(:bookmarks, Bookmark)
has_many(:notifications, Notification)
has_many(:registrations, Registration)
embeds_one(:info, Pleroma.User.Info)
@@ -270,6 +271,7 @@ defmodule Pleroma.User do
def register(%Ecto.Changeset{} = changeset) do
with {:ok, user} <- Repo.insert(changeset),
{:ok, user} <- autofollow_users(user),
+ {:ok, user} <- set_cache(user),
{:ok, _} <- Pleroma.User.WelcomeMessage.post_welcome_message_to_user(user),
{:ok, _} <- try_send_confirmation_email(user) do
{:ok, user}
@@ -454,10 +456,13 @@ defmodule Pleroma.User do
name = List.last(String.split(ap_id, "/"))
nickname = "#{name}@#{domain}"
- get_by_nickname(nickname)
+ get_cached_by_nickname(nickname)
end
- def set_cache(user) do
+ def set_cache({:ok, user}), do: set_cache(user)
+ def set_cache({:error, err}), do: {:error, err}
+
+ 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))
@@ -545,6 +550,7 @@ defmodule Pleroma.User do
with [_nick, _domain] <- String.split(nickname, "@"),
{:ok, user} <- fetch_by_nickname(nickname) do
if Pleroma.Config.get([:fetch_initial_posts, :enabled]) do
+ # TODO turn into job
{:ok, _} = Task.start(__MODULE__, :fetch_initial_posts, [user])
end
@@ -1003,7 +1009,7 @@ defmodule Pleroma.User do
# helper to handle the block given only an actor's AP id
def block(blocker, %{ap_id: ap_id}) do
- block(blocker, User.get_by_ap_id(ap_id))
+ block(blocker, get_cached_by_ap_id(ap_id))
end
def unblock(blocker, %{ap_id: ap_id}) do
@@ -1033,7 +1039,7 @@ defmodule Pleroma.User do
end
def subscribed_to?(user, %{ap_id: ap_id}) do
- with %User{} = target <- User.get_by_ap_id(ap_id) do
+ with %User{} = target <- get_cached_by_ap_id(ap_id) do
Enum.member?(target.info.subscribers, user.ap_id)
end
end
@@ -1208,7 +1214,7 @@ defmodule Pleroma.User do
end
def get_or_fetch_by_ap_id(ap_id) do
- user = get_by_ap_id(ap_id)
+ user = get_cached_by_ap_id(ap_id)
if !is_nil(user) and !User.needs_update?(user) do
user
@@ -1231,7 +1237,7 @@ defmodule Pleroma.User do
def get_or_create_instance_user do
relay_uri = "#{Pleroma.Web.Endpoint.url()}/relay"
- if user = get_by_ap_id(relay_uri) do
+ if user = get_cached_by_ap_id(relay_uri) do
user
else
changes =
@@ -1278,13 +1284,11 @@ defmodule Pleroma.User do
defp blank?(n), do: n
def insert_or_update_user(data) do
- data =
- data
- |> Map.put(:name, blank?(data[:name]) || data[:nickname])
-
- cs = User.remote_user_creation(data)
-
- Repo.insert(cs, on_conflict: :replace_all, conflict_target: :nickname)
+ data
+ |> Map.put(:name, blank?(data[:name]) || data[:nickname])
+ |> remote_user_creation()
+ |> Repo.insert(on_conflict: :replace_all, conflict_target: :nickname)
+ |> set_cache()
end
def ap_enabled?(%User{local: true}), do: true
@@ -1300,8 +1304,8 @@ defmodule Pleroma.User do
# this is because we have synchronous follow APIs and need to simulate them
# with an async handshake
def wait_and_refresh(_, %User{local: true} = a, %User{local: true} = b) do
- with %User{} = a <- User.get_by_id(a.id),
- %User{} = b <- User.get_by_id(b.id) do
+ with %User{} = a <- User.get_cached_by_id(a.id),
+ %User{} = b <- User.get_cached_by_id(b.id) do
{:ok, a, b}
else
_e ->
@@ -1311,8 +1315,8 @@ defmodule Pleroma.User do
def wait_and_refresh(timeout, %User{} = a, %User{} = b) do
with :ok <- :timer.sleep(timeout),
- %User{} = a <- User.get_by_id(a.id),
- %User{} = b <- User.get_by_id(b.id) do
+ %User{} = a <- User.get_cached_by_id(a.id),
+ %User{} = b <- User.get_cached_by_id(b.id) do
{:ok, a, b}
else
_e ->
@@ -1351,7 +1355,7 @@ defmodule Pleroma.User do
end
def tag(nickname, tags) when is_binary(nickname),
- do: tag(User.get_by_nickname(nickname), tags)
+ do: tag(get_by_nickname(nickname), tags)
def tag(%User{} = user, tags),
do: update_tags(user, Enum.uniq((user.tags || []) ++ normalize_tags(tags)))
@@ -1363,7 +1367,7 @@ defmodule Pleroma.User do
end
def untag(nickname, tags) when is_binary(nickname),
- do: untag(User.get_by_nickname(nickname), tags)
+ do: untag(get_by_nickname(nickname), tags)
def untag(%User{} = user, tags),
do: update_tags(user, (user.tags || []) -- normalize_tags(tags))
@@ -1377,22 +1381,6 @@ defmodule Pleroma.User do
updated_user
end
- def bookmark(%User{} = user, status_id) do
- bookmarks = Enum.uniq(user.bookmarks ++ [status_id])
- update_bookmarks(user, bookmarks)
- end
-
- def unbookmark(%User{} = user, status_id) do
- bookmarks = Enum.uniq(user.bookmarks -- [status_id])
- update_bookmarks(user, bookmarks)
- end
-
- def update_bookmarks(%User{} = user, bookmarks) do
- user
- |> change(%{bookmarks: bookmarks})
- |> update_and_set_cache
- end
-
defp normalize_tags(tags) do
[tags]
|> List.flatten()
diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex
index d827293b8..2d360d650 100644
--- a/lib/pleroma/user/info.ex
+++ b/lib/pleroma/user/info.ex
@@ -40,6 +40,7 @@ defmodule Pleroma.User.Info do
field(:salmon, :string, default: nil)
field(:hide_followers, :boolean, default: false)
field(:hide_follows, :boolean, default: false)
+ field(:hide_favorites, :boolean, default: true)
field(:pinned_activities, {:array, :string}, default: [])
field(:flavour, :string, default: nil)
field(:email_notifications, :map, default: %{"digest" => false})
@@ -229,6 +230,7 @@ defmodule Pleroma.User.Info do
:banner,
:hide_follows,
:hide_followers,
+ :hide_favorites,
:background,
:show_role
])
@@ -252,14 +254,6 @@ defmodule Pleroma.User.Info do
cast(info, params, [:confirmation_pending, :confirmation_token])
end
- def mastodon_profile_update(info, params) do
- info
- |> cast(params, [
- :locked,
- :banner
- ])
- end
-
def mastodon_settings_update(info, settings) do
params = %{settings: settings}
diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex
index e77b2b72d..604ffae7b 100644
--- a/lib/pleroma/web/activity_pub/activity_pub.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub.ex
@@ -168,7 +168,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
public = "https://www.w3.org/ns/activitystreams#Public"
if activity.data["type"] in ["Create", "Announce", "Delete"] do
- object = Object.normalize(activity.data["object"])
+ object = Object.normalize(activity)
Pleroma.Web.Streamer.stream("user", activity)
Pleroma.Web.Streamer.stream("list", activity)
@@ -197,7 +197,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
if !Enum.member?(activity.data["cc"] || [], public) &&
!Enum.member?(
activity.data["to"],
- User.get_by_ap_id(activity.data["actor"]).follower_address
+ User.get_cached_by_ap_id(activity.data["actor"]).follower_address
),
do: Pleroma.Web.Streamer.stream("direct", activity)
end
@@ -889,7 +889,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
end
def make_user_from_ap_id(ap_id) do
- if _user = User.get_by_ap_id(ap_id) do
+ if _user = User.get_cached_by_ap_id(ap_id) do
Transmogrifier.upgrade_user_from_ap_id(ap_id)
else
with {:ok, data} <- fetch_and_prepare_user_from_ap_id(ap_id) do
diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex
index a80aa52c6..b1e859d7c 100644
--- a/lib/pleroma/web/activity_pub/transmogrifier.ex
+++ b/lib/pleroma/web/activity_pub/transmogrifier.ex
@@ -438,20 +438,46 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
with %User{local: true} = followed <- User.get_cached_by_ap_id(followed),
%User{} = follower <- User.get_or_fetch_by_ap_id(follower),
{:ok, activity} <- ActivityPub.follow(follower, followed, id, false) do
- if not User.locked?(followed) do
+ with deny_follow_blocked <- Pleroma.Config.get([:user, :deny_follow_blocked]),
+ {:user_blocked, false} <-
+ {:user_blocked, User.blocks?(followed, follower) && deny_follow_blocked},
+ {:user_locked, false} <- {:user_locked, User.locked?(followed)},
+ {:follow, {:ok, follower}} <- {:follow, User.follow(follower, followed)} do
ActivityPub.accept(%{
to: [follower.ap_id],
actor: followed,
object: data,
local: true
})
-
- User.follow(follower, followed)
+ else
+ {:user_blocked, true} ->
+ {:ok, _} = Utils.update_follow_state(activity, "reject")
+
+ ActivityPub.reject(%{
+ to: [follower.ap_id],
+ actor: followed,
+ object: data,
+ local: true
+ })
+
+ {:follow, {:error, _}} ->
+ {:ok, _} = Utils.update_follow_state(activity, "reject")
+
+ ActivityPub.reject(%{
+ to: [follower.ap_id],
+ actor: followed,
+ object: data,
+ local: true
+ })
+
+ {:user_locked, true} ->
+ :noop
end
{:ok, activity}
else
- _e -> :error
+ _e ->
+ :error
end
end
@@ -537,7 +563,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
data
)
when object_type in ["Person", "Application", "Service", "Organization"] do
- with %User{ap_id: ^actor_id} = actor <- User.get_by_ap_id(object["id"]) do
+ with %User{ap_id: ^actor_id} = actor <- User.get_cached_by_ap_id(object["id"]) do
{:ok, new_user_data} = ActivityPub.user_data_from_user_object(object)
banner = new_user_data[:info]["banner"]
@@ -964,7 +990,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
end
def upgrade_user_from_ap_id(ap_id) do
- with %User{local: false} = user <- User.get_by_ap_id(ap_id),
+ with %User{local: false} = user <- User.get_cached_by_ap_id(ap_id),
{:ok, data} <- ActivityPub.fetch_and_prepare_user_from_ap_id(ap_id),
already_ap <- User.ap_enabled?(user),
{:ok, user} <- user |> User.upgrade_changeset(data) |> User.update_and_set_cache() do
diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex
index c436715d5..711f233a6 100644
--- a/lib/pleroma/web/admin_api/admin_api_controller.ex
+++ b/lib/pleroma/web/admin_api/admin_api_controller.ex
@@ -19,7 +19,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
action_fallback(:errors)
def user_delete(conn, %{"nickname" => nickname}) do
- User.get_by_nickname(nickname)
+ User.get_cached_by_nickname(nickname)
|> User.delete()
conn
@@ -27,8 +27,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
end
def user_follow(conn, %{"follower" => follower_nick, "followed" => followed_nick}) do
- with %User{} = follower <- User.get_by_nickname(follower_nick),
- %User{} = followed <- User.get_by_nickname(followed_nick) do
+ with %User{} = follower <- User.get_cached_by_nickname(follower_nick),
+ %User{} = followed <- User.get_cached_by_nickname(followed_nick) do
User.follow(follower, followed)
end
@@ -37,8 +37,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
end
def user_unfollow(conn, %{"follower" => follower_nick, "followed" => followed_nick}) do
- with %User{} = follower <- User.get_by_nickname(follower_nick),
- %User{} = followed <- User.get_by_nickname(followed_nick) do
+ with %User{} = follower <- User.get_cached_by_nickname(follower_nick),
+ %User{} = followed <- User.get_cached_by_nickname(followed_nick) do
User.unfollow(follower, followed)
end
@@ -67,7 +67,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
end
def user_show(conn, %{"nickname" => nickname}) do
- with %User{} = user <- User.get_by_nickname(nickname) do
+ with %User{} = user <- User.get_cached_by_nickname(nickname) do
conn
|> json(AccountView.render("show.json", %{user: user}))
else
@@ -76,7 +76,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
end
def user_toggle_activation(conn, %{"nickname" => nickname}) do
- user = User.get_by_nickname(nickname)
+ user = User.get_cached_by_nickname(nickname)
{:ok, updated_user} = User.deactivate(user, !user.info.deactivated)
@@ -131,7 +131,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
def right_add(conn, %{"permission_group" => permission_group, "nickname" => nickname})
when permission_group in ["moderator", "admin"] do
- user = User.get_by_nickname(nickname)
+ user = User.get_cached_by_nickname(nickname)
info =
%{}
@@ -156,7 +156,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
end
def right_get(conn, %{"nickname" => nickname}) do
- user = User.get_by_nickname(nickname)
+ user = User.get_cached_by_nickname(nickname)
conn
|> json(%{
@@ -178,7 +178,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
|> put_status(403)
|> json(%{error: "You can't revoke your own admin status."})
else
- user = User.get_by_nickname(nickname)
+ user = User.get_cached_by_nickname(nickname)
info =
%{}
@@ -204,7 +204,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
def set_activation_status(conn, %{"nickname" => nickname, "status" => status}) do
with {:ok, status} <- Ecto.Type.cast(:boolean, status),
- %User{} = user <- User.get_by_nickname(nickname),
+ %User{} = user <- User.get_cached_by_nickname(nickname),
{:ok, _} <- User.deactivate(user, !status),
do: json_response(conn, :no_content, "")
end
@@ -277,7 +277,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
@doc "Get a password reset token (base64 string) for given nickname"
def get_password_reset(conn, %{"nickname" => nickname}) do
- (%User{local: true} = user) = User.get_by_nickname(nickname)
+ (%User{local: true} = user) = User.get_cached_by_nickname(nickname)
{:ok, token} = Pleroma.PasswordResetToken.create_token(user)
conn
diff --git a/lib/pleroma/web/channels/user_socket.ex b/lib/pleroma/web/channels/user_socket.ex
index 6503979a1..8e2759e3b 100644
--- a/lib/pleroma/web/channels/user_socket.ex
+++ b/lib/pleroma/web/channels/user_socket.ex
@@ -24,7 +24,7 @@ defmodule Pleroma.Web.UserSocket do
def connect(%{"token" => token}, socket) do
with true <- Pleroma.Config.get([:chat, :enabled]),
{:ok, user_id} <- Phoenix.Token.verify(socket, "user socket", token, max_age: 84_600),
- %User{} = user <- Pleroma.User.get_by_id(user_id) do
+ %User{} = user <- Pleroma.User.get_cached_by_id(user_id) do
{:ok, assign(socket, :user_name, user.nickname)}
else
_e -> :error
diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex
index 6458a3449..ecd183110 100644
--- a/lib/pleroma/web/common_api/common_api.ex
+++ b/lib/pleroma/web/common_api/common_api.ex
@@ -4,6 +4,7 @@
defmodule Pleroma.Web.CommonAPI do
alias Pleroma.Activity
+ alias Pleroma.Bookmark
alias Pleroma.Formatter
alias Pleroma.Object
alias Pleroma.ThreadMute
@@ -282,9 +283,18 @@ defmodule Pleroma.Web.CommonAPI do
end
end
+ def bookmarked?(user, activity) do
+ with %Bookmark{} <- Bookmark.get(user.id, activity.id) do
+ true
+ else
+ _ ->
+ false
+ end
+ end
+
def report(user, data) do
with {:account_id, %{"account_id" => account_id}} <- {:account_id, data},
- {:account, %User{} = account} <- {:account, User.get_by_id(account_id)},
+ {:account, %User{} = account} <- {:account, User.get_cached_by_id(account_id)},
{:ok, {content_html, _, _}} <- make_report_content_html(data["comment"]),
{:ok, statuses} <- get_report_statuses(account, data),
{:ok, activity} <-
diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex
index 25f498fcb..1dfe50b40 100644
--- a/lib/pleroma/web/common_api/utils.ex
+++ b/lib/pleroma/web/common_api/utils.ex
@@ -183,6 +183,18 @@ defmodule Pleroma.Web.CommonAPI.Utils do
end
@doc """
+ Formatting text as BBCode.
+ """
+ def format_input(text, "text/bbcode", options) do
+ text
+ |> String.replace(~r/\r/, "")
+ |> Formatter.html_escape("text/plain")
+ |> BBCode.to_html()
+ |> (fn {:ok, html} -> html end).()
+ |> Formatter.linkify(options)
+ end
+
+ @doc """
Formatting text to html.
"""
def format_input(text, "text/html", options) do
@@ -226,7 +238,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do
}
if in_reply_to do
- in_reply_to_object = Object.normalize(in_reply_to.data["object"])
+ in_reply_to_object = Object.normalize(in_reply_to)
object
|> Map.put("inReplyTo", in_reply_to_object.data["id"])
@@ -284,7 +296,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do
end
def confirm_current_password(user, password) do
- with %User{local: true} = db_user <- User.get_by_id(user.id),
+ with %User{local: true} = db_user <- User.get_cached_by_id(user.id),
true <- Pbkdf2.checkpw(password, db_user.password_hash) do
{:ok, db_user}
else
diff --git a/lib/pleroma/web/federator/federator.ex b/lib/pleroma/web/federator/federator.ex
index 1b4deb6dc..29e178ba9 100644
--- a/lib/pleroma/web/federator/federator.ex
+++ b/lib/pleroma/web/federator/federator.ex
@@ -186,7 +186,7 @@ defmodule Pleroma.Web.Federator do
end
def ap_enabled_actor(id) do
- user = User.get_by_ap_id(id)
+ user = User.get_cached_by_ap_id(id)
if User.ap_enabled?(user) do
{:ok, user}
diff --git a/lib/pleroma/web/mastodon_api/mastodon_api.ex b/lib/pleroma/web/mastodon_api/mastodon_api.ex
index 382f07e6b..3a3ec7c2a 100644
--- a/lib/pleroma/web/mastodon_api/mastodon_api.ex
+++ b/lib/pleroma/web/mastodon_api/mastodon_api.ex
@@ -7,6 +7,31 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPI do
alias Pleroma.Pagination
alias Pleroma.ScheduledActivity
alias Pleroma.User
+ alias Pleroma.Web.CommonAPI
+
+ def follow(follower, followed, params \\ %{}) do
+ options = cast_params(params)
+ reblogs = options[:reblogs]
+
+ result =
+ if not User.following?(follower, followed) do
+ CommonAPI.follow(follower, followed)
+ else
+ {:ok, follower, followed, nil}
+ end
+
+ with {:ok, follower, followed, _} <- result do
+ reblogs
+ |> case do
+ false -> CommonAPI.hide_reblogs(follower, followed)
+ _ -> CommonAPI.show_reblogs(follower, followed)
+ end
+ |> case do
+ {:ok, follower} -> {:ok, follower}
+ _ -> {:ok, follower}
+ end
+ end
+ end
def get_followers(user, params \\ %{}) do
user
@@ -37,7 +62,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPI do
defp cast_params(params) do
param_types = %{
- exclude_types: {:array, :string}
+ exclude_types: {:array, :string},
+ reblogs: :boolean
}
changeset = cast({%{}, param_types}, params, Map.keys(param_types))
diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
index 3916d7c41..811a45c79 100644
--- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
+++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
@@ -6,6 +6,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
use Pleroma.Web, :controller
alias Ecto.Changeset
alias Pleroma.Activity
+ alias Pleroma.Bookmark
alias Pleroma.Config
alias Pleroma.Filter
alias Pleroma.Notification
@@ -35,7 +36,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
alias Pleroma.Web.OAuth.Authorization
alias Pleroma.Web.OAuth.Token
- import Pleroma.Web.ControllerHelper, only: [oauth_scopes: 2]
+ alias Pleroma.Web.ControllerHelper
import Ecto.Query
require Logger
@@ -46,7 +47,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
action_fallback(:errors)
def create_app(conn, params) do
- scopes = oauth_scopes(params, ["read"])
+ scopes = ControllerHelper.oauth_scopes(params, ["read"])
app_attrs =
params
@@ -96,8 +97,13 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end)
info_params =
- %{}
- |> add_if_present(params, "locked", :locked, fn value -> {:ok, value == "true"} end)
+ [:no_rich_text, :locked, :hide_followers, :hide_follows, :hide_favorites, :show_role]
+ |> Enum.reduce(%{}, fn key, acc ->
+ add_if_present(acc, params, to_string(key), key, fn value ->
+ {:ok, ControllerHelper.truthy_param?(value)}
+ end)
+ end)
+ |> add_if_present(params, "default_scope", :default_scope)
|> add_if_present(params, "header", :banner, fn value ->
with %Plug.Upload{} <- value,
{:ok, object} <- ActivityPub.upload(value, type: :banner) do
@@ -107,7 +113,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
end)
- info_cng = User.Info.mastodon_profile_update(user.info, info_params)
+ info_cng = User.Info.profile_update(user.info, info_params)
with changeset <- User.update_changeset(user, user_params),
changeset <- Ecto.Changeset.put_embed(changeset, :info, info_cng),
@@ -190,7 +196,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
"static_url" => url,
"visible_in_picker" => true,
"url" => url,
- "tags" => String.split(tags, ",")
+ "tags" => tags
}
end)
end
@@ -279,6 +285,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|> ActivityPub.contain_timeline(user)
|> Enum.reverse()
+ user = Repo.preload(user, bookmarks: :activity)
+
conn
|> add_link_headers(:home_timeline, activities)
|> put_view(StatusView)
@@ -297,6 +305,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|> ActivityPub.fetch_public_activities()
|> Enum.reverse()
+ user = Repo.preload(user, bookmarks: :activity)
+
conn
|> add_link_headers(:public_timeline, activities, false, %{"local" => local_only})
|> put_view(StatusView)
@@ -304,7 +314,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
def user_statuses(%{assigns: %{user: reading_user}} = conn, params) do
- with %User{} = user <- User.get_by_id(params["id"]) do
+ with %User{} = user <- User.get_cached_by_id(params["id"]),
+ reading_user <- Repo.preload(reading_user, :bookmarks) do
activities = ActivityPub.fetch_user_activities(user, reading_user, params)
conn
@@ -331,6 +342,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|> ActivityPub.fetch_activities_query(params)
|> Pagination.fetch_paginated(params)
+ user = Repo.preload(user, bookmarks: :activity)
+
conn
|> add_link_headers(:dm_timeline, activities)
|> put_view(StatusView)
@@ -338,8 +351,10 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
def get_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do
- with %Activity{} = activity <- Activity.get_by_id(id),
+ with %Activity{} = activity <- Activity.get_by_id_with_object(id),
true <- Visibility.visible_for_user?(activity, user) do
+ user = Repo.preload(user, bookmarks: :activity)
+
conn
|> put_view(StatusView)
|> try_render("status.json", %{activity: activity, for: user})
@@ -487,7 +502,10 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
def reblog_status(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do
- with {:ok, announce, _activity} <- CommonAPI.repeat(ap_id_or_id, user) do
+ with {:ok, announce, _activity} <- CommonAPI.repeat(ap_id_or_id, user),
+ %Activity{} = announce <- Activity.normalize(announce.data) do
+ user = Repo.preload(user, bookmarks: :activity)
+
conn
|> put_view(StatusView)
|> try_render("status.json", %{activity: announce, for: user, as: :activity})
@@ -496,7 +514,9 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
def unreblog_status(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do
with {:ok, _unannounce, %{data: %{"id" => id}}} <- CommonAPI.unrepeat(ap_id_or_id, user),
- %Activity{} = activity <- Activity.get_create_by_object_ap_id(id) do
+ %Activity{} = activity <- Activity.get_create_by_object_ap_id_with_object(id) do
+ user = Repo.preload(user, bookmarks: :activity)
+
conn
|> put_view(StatusView)
|> try_render("status.json", %{activity: activity, for: user, as: :activity})
@@ -544,10 +564,11 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
def bookmark_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do
with %Activity{} = activity <- Activity.get_by_id_with_object(id),
- %Object{} = object <- Object.normalize(activity),
- %User{} = user <- User.get_by_nickname(user.nickname),
+ %User{} = user <- User.get_cached_by_nickname(user.nickname),
true <- Visibility.visible_for_user?(activity, user),
- {:ok, user} <- User.bookmark(user, object.data["id"]) do
+ {:ok, _bookmark} <- Bookmark.create(user.id, activity.id) do
+ user = Repo.preload(user, bookmarks: :activity)
+
conn
|> put_view(StatusView)
|> try_render("status.json", %{activity: activity, for: user, as: :activity})
@@ -556,10 +577,11 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
def unbookmark_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do
with %Activity{} = activity <- Activity.get_by_id_with_object(id),
- %Object{} = object <- Object.normalize(activity),
- %User{} = user <- User.get_by_nickname(user.nickname),
+ %User{} = user <- User.get_cached_by_nickname(user.nickname),
true <- Visibility.visible_for_user?(activity, user),
- {:ok, user} <- User.unbookmark(user, object.data["id"]) do
+ {:ok, _bookmark} <- Bookmark.destroy(user.id, activity.id) do
+ user = Repo.preload(user, bookmarks: :activity)
+
conn
|> put_view(StatusView)
|> try_render("status.json", %{activity: activity, for: user, as: :activity})
@@ -749,7 +771,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
def followers(%{assigns: %{user: for_user}} = conn, %{"id" => id} = params) do
- with %User{} = user <- User.get_by_id(id),
+ with %User{} = user <- User.get_cached_by_id(id),
followers <- MastodonAPI.get_followers(user, params) do
followers =
cond do
@@ -766,7 +788,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
def following(%{assigns: %{user: for_user}} = conn, %{"id" => id} = params) do
- with %User{} = user <- User.get_by_id(id),
+ with %User{} = user <- User.get_cached_by_id(id),
followers <- MastodonAPI.get_friends(user, params) do
followers =
cond do
@@ -791,7 +813,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
def authorize_follow_request(%{assigns: %{user: followed}} = conn, %{"id" => id}) do
- with %User{} = follower <- User.get_by_id(id),
+ with %User{} = follower <- User.get_cached_by_id(id),
{:ok, follower} <- CommonAPI.accept_follow_request(follower, followed) do
conn
|> put_view(AccountView)
@@ -805,7 +827,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
def reject_follow_request(%{assigns: %{user: followed}} = conn, %{"id" => id}) do
- with %User{} = follower <- User.get_by_id(id),
+ with %User{} = follower <- User.get_cached_by_id(id),
{:ok, follower} <- CommonAPI.reject_follow_request(follower, followed) do
conn
|> put_view(AccountView)
@@ -821,8 +843,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
def follow(%{assigns: %{user: follower}} = conn, %{"id" => id}) do
with {_, %User{} = followed} <- {:followed, User.get_cached_by_id(id)},
{_, true} <- {:followed, follower.id != followed.id},
- false <- User.following?(follower, followed),
- {:ok, follower, followed, _} <- CommonAPI.follow(follower, followed) do
+ {:ok, follower} <- MastodonAPI.follow(follower, followed, conn.params) do
conn
|> put_view(AccountView)
|> render("relationship.json", %{user: follower, target: followed})
@@ -830,19 +851,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
{:followed, _} ->
{:error, :not_found}
- true ->
- followed = User.get_cached_by_id(id)
-
- {:ok, follower} =
- case conn.params["reblogs"] do
- true -> CommonAPI.show_reblogs(follower, followed)
- false -> CommonAPI.hide_reblogs(follower, followed)
- end
-
- conn
- |> put_view(AccountView)
- |> render("relationship.json", %{user: follower, target: followed})
-
{:error, message} ->
conn
|> put_resp_content_type("application/json")
@@ -885,7 +893,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
def mute(%{assigns: %{user: muter}} = conn, %{"id" => id}) do
- with %User{} = muted <- User.get_by_id(id),
+ with %User{} = muted <- User.get_cached_by_id(id),
{:ok, muter} <- User.mute(muter, muted) do
conn
|> put_view(AccountView)
@@ -899,7 +907,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
def unmute(%{assigns: %{user: muter}} = conn, %{"id" => id}) do
- with %User{} = muted <- User.get_by_id(id),
+ with %User{} = muted <- User.get_cached_by_id(id),
{:ok, muter} <- User.unmute(muter, muted) do
conn
|> put_view(AccountView)
@@ -920,7 +928,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
def block(%{assigns: %{user: blocker}} = conn, %{"id" => id}) do
- with %User{} = blocked <- User.get_by_id(id),
+ with %User{} = blocked <- User.get_cached_by_id(id),
{:ok, blocker} <- User.block(blocker, blocked),
{:ok, _activity} <- ActivityPub.block(blocker, blocked) do
conn
@@ -935,7 +943,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
def unblock(%{assigns: %{user: blocker}} = conn, %{"id" => id}) do
- with %User{} = blocked <- User.get_by_id(id),
+ with %User{} = blocked <- User.get_cached_by_id(id),
{:ok, blocker} <- User.unblock(blocker, blocked),
{:ok, _activity} <- ActivityPub.unblock(blocker, blocked) do
conn
@@ -1094,21 +1102,65 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
ActivityPub.fetch_activities([], params)
|> Enum.reverse()
+ user = Repo.preload(user, bookmarks: :activity)
+
conn
|> add_link_headers(:favourites, activities)
|> put_view(StatusView)
|> render("index.json", %{activities: activities, for: user, as: :activity})
end
- def bookmarks(%{assigns: %{user: user}} = conn, _) do
- user = User.get_by_id(user.id)
+ def user_favourites(%{assigns: %{user: for_user}} = conn, %{"id" => id} = params) do
+ with %User{} = user <- User.get_by_id(id),
+ false <- user.info.hide_favorites do
+ params =
+ params
+ |> Map.put("type", "Create")
+ |> Map.put("favorited_by", user.ap_id)
+ |> Map.put("blocking_user", for_user)
+
+ recipients =
+ if for_user do
+ ["https://www.w3.org/ns/activitystreams#Public"] ++
+ [for_user.ap_id | for_user.following]
+ else
+ ["https://www.w3.org/ns/activitystreams#Public"]
+ end
+
+ activities =
+ recipients
+ |> ActivityPub.fetch_activities(params)
+ |> Enum.reverse()
+
+ conn
+ |> add_link_headers(:favourites, activities)
+ |> put_view(StatusView)
+ |> render("index.json", %{activities: activities, for: for_user, as: :activity})
+ else
+ nil ->
+ {:error, :not_found}
+
+ true ->
+ conn
+ |> put_status(403)
+ |> json(%{error: "Can't get favorites"})
+ end
+ end
+
+ def bookmarks(%{assigns: %{user: user}} = conn, params) do
+ user = User.get_cached_by_id(user.id)
+ user = Repo.preload(user, bookmarks: :activity)
+
+ bookmarks =
+ Bookmark.for_user_query(user.id)
+ |> Pagination.fetch_paginated(params)
activities =
- user.bookmarks
- |> Enum.map(fn id -> Activity.get_create_by_object_ap_id(id) end)
- |> Enum.reverse()
+ bookmarks
+ |> Enum.map(fn b -> b.activity end)
conn
+ |> add_link_headers(:bookmarks, bookmarks)
|> put_view(StatusView)
|> render("index.json", %{activities: activities, for: user, as: :activity})
end
@@ -1158,7 +1210,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
accounts
|> Enum.each(fn account_id ->
with %Pleroma.List{} = list <- Pleroma.List.get(id, user),
- %User{} = followed <- User.get_by_id(account_id) do
+ %User{} = followed <- User.get_cached_by_id(account_id) do
Pleroma.List.follow(list, followed)
end
end)
@@ -1170,7 +1222,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
accounts
|> Enum.each(fn account_id ->
with %Pleroma.List{} = list <- Pleroma.List.get(id, user),
- %User{} = followed <- Pleroma.User.get_by_id(account_id) do
+ %User{} = followed <- Pleroma.User.get_cached_by_id(account_id) do
Pleroma.List.unfollow(list, followed)
end
end)
@@ -1214,6 +1266,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|> ActivityPub.fetch_activities_bounded(following, params)
|> Enum.reverse()
+ user = Repo.preload(user, bookmarks: :activity)
+
conn
|> put_view(StatusView)
|> render("index.json", %{activities: activities, for: user, as: :activity})
@@ -1463,7 +1517,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
def relationship_noop(%{assigns: %{user: user}} = conn, %{"id" => id}) do
Logger.debug("Unimplemented, returning unmodified relationship")
- with %User{} = target <- User.get_by_id(id) do
+ with %User{} = target <- User.get_cached_by_id(id) do
conn
|> put_view(AccountView)
|> render("relationship.json", %{user: user, target: target})
diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex
index af56c4149..779b9a382 100644
--- a/lib/pleroma/web/mastodon_api/views/account_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/account_view.ex
@@ -68,7 +68,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
defp do_render("account.json", %{user: user} = opts) do
image = User.avatar_url(user) |> MediaProxy.url()
header = User.banner_url(user) |> MediaProxy.url()
- user_info = User.user_info(user)
+ user_info = User.get_cached_user_info(user)
bot = (user.info.source_data["type"] || "Person") in ["Application", "Service"]
emojis =
@@ -113,21 +113,23 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
bot: bot,
source: %{
note: "",
- privacy: user_info.default_scope,
- sensitive: false
+ sensitive: false,
+ pleroma: %{}
},
# Pleroma extension
- pleroma:
- %{
- confirmation_pending: user_info.confirmation_pending,
- tags: user.tags,
- is_moderator: user.info.is_moderator,
- is_admin: user.info.is_admin,
- relationship: relationship
- }
- |> with_notification_settings(user, opts[:for])
+ pleroma: %{
+ confirmation_pending: user_info.confirmation_pending,
+ tags: user.tags,
+ hide_followers: user.info.hide_followers,
+ hide_follows: user.info.hide_follows,
+ hide_favorites: user.info.hide_favorites,
+ relationship: relationship
+ }
}
+ |> maybe_put_role(user, opts[:for])
+ |> maybe_put_settings(user, opts[:for], user_info)
+ |> maybe_put_notification_settings(user, opts[:for])
end
defp username_from_nickname(string) when is_binary(string) do
@@ -136,9 +138,37 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
defp username_from_nickname(_), do: nil
- defp with_notification_settings(data, %User{id: user_id} = user, %User{id: user_id}) do
- Map.put(data, :notification_settings, user.info.notification_settings)
+ defp maybe_put_settings(
+ data,
+ %User{id: user_id} = user,
+ %User{id: user_id},
+ user_info
+ ) do
+ data
+ |> Kernel.put_in([:source, :privacy], user_info.default_scope)
+ |> Kernel.put_in([:source, :pleroma, :show_role], user.info.show_role)
+ |> Kernel.put_in([:source, :pleroma, :no_rich_text], user.info.no_rich_text)
+ end
+
+ defp maybe_put_settings(data, _, _, _), do: data
+
+ defp maybe_put_role(data, %User{info: %{show_role: true}} = user, _) do
+ data
+ |> Kernel.put_in([:pleroma, :is_admin], user.info.is_admin)
+ |> Kernel.put_in([:pleroma, :is_moderator], user.info.is_moderator)
+ end
+
+ defp maybe_put_role(data, %User{id: user_id} = user, %User{id: user_id}) do
+ data
+ |> Kernel.put_in([:pleroma, :is_admin], user.info.is_admin)
+ |> Kernel.put_in([:pleroma, :is_moderator], user.info.is_moderator)
+ end
+
+ defp maybe_put_role(data, _, _), do: data
+
+ defp maybe_put_notification_settings(data, %User{id: user_id} = user, %User{id: user_id}) do
+ Kernel.put_in(data, [:pleroma, :notification_settings], user.info.notification_settings)
end
- defp with_notification_settings(data, _, _), do: data
+ defp maybe_put_notification_settings(data, _, _), do: data
end
diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex
index f8961eb6c..62d064d71 100644
--- a/lib/pleroma/web/mastodon_api/views/status_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/status_view.ex
@@ -31,7 +31,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
|> Activity.create_by_object_ap_id()
|> Repo.all()
|> Enum.reduce(%{}, fn activity, acc ->
- object = Object.normalize(activity.data["object"])
+ object = Object.normalize(activity)
Map.put(acc, object.data["id"], activity)
end)
end
@@ -83,6 +83,11 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
reblogged_activity = Activity.get_create_by_object_ap_id(object)
reblogged = render("status.json", Map.put(opts, :activity, reblogged_activity))
+ activity_object = Object.normalize(activity)
+ favorited = opts[:for] && opts[:for].ap_id in (activity_object.data["likes"] || [])
+
+ bookmarked = opts[:for] && CommonAPI.bookmarked?(opts[:for], reblogged_activity)
+
mentions =
activity.recipients
|> Enum.map(fn ap_id -> User.get_cached_by_ap_id(ap_id) end)
@@ -103,8 +108,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
replies_count: 0,
favourites_count: 0,
reblogged: reblogged?(reblogged_activity, opts[:for]),
- favourited: false,
- bookmarked: false,
+ favourited: present?(favorited),
+ bookmarked: present?(bookmarked),
muted: false,
pinned: pinned?(activity, user),
sensitive: false,
@@ -144,7 +149,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
favorited = opts[:for] && opts[:for].ap_id in (object.data["likes"] || [])
- bookmarked = opts[:for] && object.data["id"] in opts[:for].bookmarks
+ bookmarked = opts[:for] && CommonAPI.bookmarked?(opts[:for], activity)
attachment_data = object.data["attachment"] || []
attachments = render_many(attachment_data, StatusView, "attachment.json", as: :attachment)
@@ -234,6 +239,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
pleroma: %{
local: activity.local,
conversation_id: get_context_id(activity),
+ in_reply_to_account_acct: reply_to_user && reply_to_user.nickname,
content: %{"text/plain" => content_plaintext},
spoiler_text: %{"text/plain" => summary_plaintext}
}
@@ -312,7 +318,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
end
def get_reply_to(activity, %{replied_to_activities: replied_to_activities}) do
- object = Object.normalize(activity.data["object"])
+ object = Object.normalize(activity)
with nil <- replied_to_activities[object.data["inReplyTo"]] do
# If user didn't participate in the thread
diff --git a/lib/pleroma/web/mastodon_api/websocket_handler.ex b/lib/pleroma/web/mastodon_api/websocket_handler.ex
index 1b3721e2b..abfa26754 100644
--- a/lib/pleroma/web/mastodon_api/websocket_handler.ex
+++ b/lib/pleroma/web/mastodon_api/websocket_handler.ex
@@ -90,7 +90,7 @@ defmodule Pleroma.Web.MastodonAPI.WebsocketHandler do
# Authenticated streams.
defp allow_request(stream, {"access_token", access_token}) when stream in @streams do
with %Token{user_id: user_id} <- Repo.get_by(Token, token: access_token),
- user = %User{} <- User.get_by_id(user_id) do
+ user = %User{} <- User.get_cached_by_id(user_id) do
{:ok, user}
else
_ -> {:error, 403}
diff --git a/lib/pleroma/web/media_proxy/media_proxy.ex b/lib/pleroma/web/media_proxy/media_proxy.ex
index 3bd2affe9..5762e767b 100644
--- a/lib/pleroma/web/media_proxy/media_proxy.ex
+++ b/lib/pleroma/web/media_proxy/media_proxy.ex
@@ -13,32 +13,44 @@ defmodule Pleroma.Web.MediaProxy do
def url(url) do
config = Application.get_env(:pleroma, :media_proxy, [])
+ domain = URI.parse(url).host
- if !Keyword.get(config, :enabled, false) or String.starts_with?(url, Pleroma.Web.base_url()) do
- url
- else
- secret = Application.get_env(:pleroma, Pleroma.Web.Endpoint)[:secret_key_base]
-
- # Must preserve `%2F` for compatibility with S3
- # https://git.pleroma.social/pleroma/pleroma/issues/580
- replacement = get_replacement(url, ":2F:")
-
- # The URL is url-decoded and encoded again to ensure it is correctly encoded and not twice.
- base64 =
+ cond do
+ !Keyword.get(config, :enabled, false) or String.starts_with?(url, Pleroma.Web.base_url()) ->
url
- |> String.replace("%2F", replacement)
- |> URI.decode()
- |> URI.encode()
- |> String.replace(replacement, "%2F")
- |> Base.url_encode64(@base64_opts)
- sig = :crypto.hmac(:sha, secret, base64)
- sig64 = sig |> Base.url_encode64(@base64_opts)
+ Enum.any?(Pleroma.Config.get([:media_proxy, :whitelist]), fn pattern ->
+ String.equivalent?(domain, pattern)
+ end) ->
+ url
- build_url(sig64, base64, filename(url))
+ true ->
+ encode_url(url)
end
end
+ def encode_url(url) do
+ secret = Application.get_env(:pleroma, Pleroma.Web.Endpoint)[:secret_key_base]
+
+ # Must preserve `%2F` for compatibility with S3
+ # https://git.pleroma.social/pleroma/pleroma/issues/580
+ replacement = get_replacement(url, ":2F:")
+
+ # The URL is url-decoded and encoded again to ensure it is correctly encoded and not twice.
+ base64 =
+ url
+ |> String.replace("%2F", replacement)
+ |> URI.decode()
+ |> URI.encode()
+ |> String.replace(replacement, "%2F")
+ |> Base.url_encode64(@base64_opts)
+
+ sig = :crypto.hmac(:sha, secret, base64)
+ sig64 = sig |> Base.url_encode64(@base64_opts)
+
+ build_url(sig64, base64, filename(url))
+ end
+
def decode_url(sig, url) do
secret = Application.get_env(:pleroma, Pleroma.Web.Endpoint)[:secret_key_base]
sig = Base.url_decode64!(sig, @base64_opts)
diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex
index 9874bac23..688eaca11 100644
--- a/lib/pleroma/web/oauth/oauth_controller.ex
+++ b/lib/pleroma/web/oauth/oauth_controller.ex
@@ -23,6 +23,12 @@ defmodule Pleroma.Web.OAuth.OAuthController do
action_fallback(Pleroma.Web.OAuth.FallbackController)
+ # Note: this definition is only called from error-handling methods with `conn.params` as 2nd arg
+ def authorize(conn, %{"authorization" => _} = params) do
+ {auth_attrs, params} = Map.pop(params, "authorization")
+ authorize(conn, Map.merge(params, auth_attrs))
+ end
+
def authorize(%{assigns: %{token: %Token{} = token}} = conn, params) do
if ControllerHelper.truthy_param?(params["force_login"]) do
do_authorize(conn, params)
@@ -44,21 +50,20 @@ defmodule Pleroma.Web.OAuth.OAuthController do
def authorize(conn, params), do: do_authorize(conn, params)
- defp do_authorize(conn, %{"authorization" => auth_attrs}), do: do_authorize(conn, auth_attrs)
-
- defp do_authorize(conn, auth_attrs) do
- app = Repo.get_by(App, client_id: auth_attrs["client_id"])
+ defp do_authorize(conn, params) do
+ app = Repo.get_by(App, client_id: params["client_id"])
available_scopes = (app && app.scopes) || []
- scopes = oauth_scopes(auth_attrs, nil) || available_scopes
+ scopes = oauth_scopes(params, nil) || available_scopes
+ # Note: `params` might differ from `conn.params`; use `@params` not `@conn.params` in template
render(conn, Authenticator.auth_template(), %{
- response_type: auth_attrs["response_type"],
- client_id: auth_attrs["client_id"],
+ response_type: params["response_type"],
+ client_id: params["client_id"],
available_scopes: available_scopes,
scopes: scopes,
- redirect_uri: auth_attrs["redirect_uri"],
- state: auth_attrs["state"],
- params: auth_attrs
+ redirect_uri: params["redirect_uri"],
+ state: params["state"],
+ params: params
})
end
@@ -138,7 +143,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do
fixed_token = fix_padding(params["code"]),
%Authorization{} = auth <-
Repo.get_by(Authorization, token: fixed_token, app_id: app.id),
- %User{} = user <- User.get_by_id(auth.user_id),
+ %User{} = user <- User.get_cached_by_id(auth.user_id),
{:ok, token} <- Token.exchange_token(app, auth),
{:ok, inserted_at} <- DateTime.from_naive(token.inserted_at, "Etc/UTC") do
response = %{
diff --git a/lib/pleroma/web/oauth/token.ex b/lib/pleroma/web/oauth/token.ex
index 2b5ad9b94..399140003 100644
--- a/lib/pleroma/web/oauth/token.ex
+++ b/lib/pleroma/web/oauth/token.ex
@@ -27,7 +27,7 @@ defmodule Pleroma.Web.OAuth.Token do
def exchange_token(app, auth) do
with {:ok, auth} <- Authorization.use_token(auth),
true <- auth.app_id == app.id do
- create_token(app, User.get_by_id(auth.user_id), auth.scopes)
+ create_token(app, User.get_cached_by_id(auth.user_id), auth.scopes)
end
end
diff --git a/lib/pleroma/web/ostatus/activity_representer.ex b/lib/pleroma/web/ostatus/activity_representer.ex
index b11a2b5ce..166691a09 100644
--- a/lib/pleroma/web/ostatus/activity_representer.ex
+++ b/lib/pleroma/web/ostatus/activity_representer.ex
@@ -84,7 +84,7 @@ defmodule Pleroma.Web.OStatus.ActivityRepresenter do
def to_simple_form(%{data: %{"type" => "Create"}} = activity, user, with_author) do
h = fn str -> [to_charlist(str)] end
- object = Object.normalize(activity.data["object"])
+ object = Object.normalize(activity)
updated_at = object.data["published"]
inserted_at = object.data["published"]
diff --git a/lib/pleroma/web/ostatus/ostatus.ex b/lib/pleroma/web/ostatus/ostatus.ex
index 9a34d7ad5..4744c6d83 100644
--- a/lib/pleroma/web/ostatus/ostatus.ex
+++ b/lib/pleroma/web/ostatus/ostatus.ex
@@ -294,7 +294,7 @@ defmodule Pleroma.Web.OStatus do
}
with false <- update,
- %User{} = user <- User.get_by_ap_id(data.ap_id) do
+ %User{} = user <- User.get_cached_by_ap_id(data.ap_id) do
{:ok, user}
else
_e -> User.insert_or_update_user(data)
diff --git a/lib/pleroma/web/push/impl.ex b/lib/pleroma/web/push/impl.ex
index 2233480c5..35d3ff07c 100644
--- a/lib/pleroma/web/push/impl.ex
+++ b/lib/pleroma/web/push/impl.ex
@@ -21,8 +21,10 @@ defmodule Pleroma.Web.Push.Impl do
@doc "Performs sending notifications for user subscriptions"
@spec perform(Notification.t()) :: list(any) | :error
def perform(
- %{activity: %{data: %{"type" => activity_type}, id: activity_id}, user_id: user_id} =
- notif
+ %{
+ activity: %{data: %{"type" => activity_type}, id: activity_id} = activity,
+ user_id: user_id
+ } = notif
)
when activity_type in @types do
actor = User.get_cached_by_ap_id(notif.activity.data["actor"])
@@ -30,13 +32,14 @@ defmodule Pleroma.Web.Push.Impl do
type = Activity.mastodon_notification_type(notif.activity)
gcm_api_key = Application.get_env(:web_push_encryption, :gcm_api_key)
avatar_url = User.avatar_url(actor)
+ object = Object.normalize(activity)
for subscription <- fetch_subsriptions(user_id),
get_in(subscription.data, ["alerts", type]) do
%{
title: format_title(notif),
access_token: subscription.token.token,
- body: format_body(notif, actor),
+ body: format_body(notif, actor, object),
notification_id: notif.id,
notification_type: type,
icon: avatar_url,
@@ -95,25 +98,25 @@ defmodule Pleroma.Web.Push.Impl do
end
def format_body(
- %{activity: %{data: %{"type" => "Create", "object" => %{"content" => content}}}},
- actor
+ %{activity: %{data: %{"type" => "Create"}}},
+ actor,
+ %{data: %{"content" => content}}
) do
"@#{actor.nickname}: #{Utils.scrub_html_and_truncate(content, 80)}"
end
def format_body(
- %{activity: %{data: %{"type" => "Announce", "object" => activity_id}}},
- actor
+ %{activity: %{data: %{"type" => "Announce"}}},
+ actor,
+ %{data: %{"content" => content}}
) do
- %Activity{data: %{"object" => %{"id" => object_id}}} = Activity.get_by_ap_id(activity_id)
- %Object{data: %{"content" => content}} = Object.get_by_ap_id(object_id)
-
"@#{actor.nickname} repeated: #{Utils.scrub_html_and_truncate(content, 80)}"
end
def format_body(
%{activity: %{data: %{"type" => type}}},
- actor
+ actor,
+ _object
)
when type in ["Follow", "Like"] do
case type do
diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index 09e51e602..9b833bc48 100644
--- a/lib/pleroma/web/router.ex
+++ b/lib/pleroma/web/router.ex
@@ -135,6 +135,7 @@ defmodule Pleroma.Web.Router do
post("/password_reset", UtilController, :password_reset)
get("/emoji", UtilController, :emoji)
get("/captcha", UtilController, :captcha)
+ get("/healthcheck", UtilController, :healthcheck)
end
scope "/api/pleroma", Pleroma.Web do
@@ -394,6 +395,8 @@ defmodule Pleroma.Web.Router do
get("/accounts/:id", MastodonAPIController, :user)
get("/search", MastodonAPIController, :search)
+
+ get("/pleroma/accounts/:id/favourites", MastodonAPIController, :user_favourites)
end
end
diff --git a/lib/pleroma/web/streamer.ex b/lib/pleroma/web/streamer.ex
index a82109f92..72eaf2084 100644
--- a/lib/pleroma/web/streamer.ex
+++ b/lib/pleroma/web/streamer.ex
@@ -81,7 +81,7 @@ defmodule Pleroma.Web.Streamer do
_ ->
Pleroma.List.get_lists_from_activity(item)
|> Enum.filter(fn list ->
- owner = User.get_by_id(list.user_id)
+ owner = User.get_cached_by_id(list.user_id)
Visibility.visible_for_user?(item, owner)
end)
diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex
index 9441984c7..1122e6c5d 100644
--- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex
+++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex
@@ -22,7 +22,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
def show_password_reset(conn, %{"token" => token}) do
with %{used: false} = token <- Repo.get_by(PasswordResetToken, %{token: token}),
- %User{} = user <- User.get_by_id(token.user_id) do
+ %User{} = user <- User.get_cached_by_id(token.user_id) do
render(conn, "password_reset.html", %{
token: token,
user: user
@@ -113,13 +113,13 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
def do_remote_follow(conn, %{
"authorization" => %{"name" => username, "password" => password, "id" => id}
}) do
- followee = User.get_by_id(id)
+ followee = User.get_cached_by_id(id)
avatar = User.avatar_url(followee)
name = followee.nickname
with %User{} = user <- User.get_cached_by_nickname(username),
true <- Pbkdf2.checkpw(password, user.password_hash),
- %User{} = _followed <- User.get_by_id(id),
+ %User{} = _followed <- User.get_cached_by_id(id),
{:ok, follower} <- User.follow(user, followee),
{:ok, _activity} <- ActivityPub.follow(follower, followee) do
conn
@@ -141,7 +141,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
end
def do_remote_follow(%{assigns: %{user: user}} = conn, %{"user" => %{"id" => id}}) do
- with %User{} = followee <- User.get_by_id(id),
+ with %User{} = followee <- User.get_cached_by_id(id),
{:ok, follower} <- User.follow(user, followee),
{:ok, _activity} <- ActivityPub.follow(follower, followee) do
conn
@@ -286,7 +286,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
emoji =
Emoji.get_all()
|> Enum.map(fn {short_code, path, tags} ->
- {short_code, %{image_url: path, tags: String.split(tags, ",")}}
+ {short_code, %{image_url: path, tags: tags}}
end)
|> Enum.into(%{})
@@ -363,4 +363,22 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
def captcha(conn, _params) do
json(conn, Pleroma.Captcha.new())
end
+
+ def healthcheck(conn, _params) do
+ info =
+ if Pleroma.Config.get([:instance, :healthcheck]) do
+ Pleroma.Healthcheck.system_info()
+ else
+ %{}
+ end
+
+ conn =
+ if info[:healthy] do
+ conn
+ else
+ Plug.Conn.put_status(conn, :service_unavailable)
+ end
+
+ json(conn, info)
+ end
end
diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex
index 8e44dbeb8..adeac6f3c 100644
--- a/lib/pleroma/web/twitter_api/twitter_api.ex
+++ b/lib/pleroma/web/twitter_api/twitter_api.ex
@@ -240,7 +240,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
end
%{"screen_name" => nickname} ->
- case User.get_by_nickname(nickname) do
+ case User.get_cached_by_nickname(nickname) do
nil -> {:error, "No user with such screen_name"}
target -> {:ok, target}
end
diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex
index a7ec9949c..79ed9dad2 100644
--- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex
+++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex
@@ -434,7 +434,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
end
def confirm_email(conn, %{"user_id" => uid, "token" => token}) do
- with %User{} = user <- User.get_by_id(uid),
+ with %User{} = user <- User.get_cached_by_id(uid),
true <- user.local,
true <- user.info.confirmation_pending,
true <- user.info.confirmation_token == token,
@@ -587,7 +587,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
def approve_friend_request(conn, %{"user_id" => uid} = _params) do
with followed <- conn.assigns[:user],
- %User{} = follower <- User.get_by_id(uid),
+ %User{} = follower <- User.get_cached_by_id(uid),
{:ok, follower} <- CommonAPI.accept_follow_request(follower, followed) do
conn
|> put_view(UserView)
@@ -599,7 +599,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
def deny_friend_request(conn, %{"user_id" => uid} = _params) do
with followed <- conn.assigns[:user],
- %User{} = follower <- User.get_by_id(uid),
+ %User{} = follower <- User.get_cached_by_id(uid),
{:ok, follower} <- CommonAPI.reject_follow_request(follower, followed) do
conn
|> put_view(UserView)
@@ -632,7 +632,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
defp build_info_cng(user, params) do
info_params =
- ["no_rich_text", "locked", "hide_followers", "hide_follows", "show_role"]
+ ["no_rich_text", "locked", "hide_followers", "hide_follows", "hide_favorites", "show_role"]
|> Enum.reduce(%{}, fn key, res ->
if value = params[key] do
Map.put(res, key, value == "true")
diff --git a/lib/pleroma/web/twitter_api/views/user_view.ex b/lib/pleroma/web/twitter_api/views/user_view.ex
index 0791ed760..ea015b8f0 100644
--- a/lib/pleroma/web/twitter_api/views/user_view.ex
+++ b/lib/pleroma/web/twitter_api/views/user_view.ex
@@ -74,58 +74,49 @@ defmodule Pleroma.Web.TwitterAPI.UserView do
|> Enum.filter(fn %{"type" => t} -> t == "PropertyValue" end)
|> Enum.map(fn fields -> Map.take(fields, ["name", "value"]) end)
- data = %{
- "created_at" => user.inserted_at |> Utils.format_naive_asctime(),
- "description" => HTML.strip_tags((user.bio || "") |> String.replace("<br>", "\n")),
- "description_html" => HTML.filter_tags(user.bio, User.html_filter_policy(for_user)),
- "favourites_count" => 0,
- "followers_count" => user_info[:follower_count],
- "following" => following,
- "follows_you" => follows_you,
- "statusnet_blocking" => statusnet_blocking,
- "friends_count" => user_info[:following_count],
- "id" => user.id,
- "name" => user.name || user.nickname,
- "name_html" =>
- if(user.name,
- do: HTML.strip_tags(user.name) |> Formatter.emojify(emoji),
- else: user.nickname
- ),
- "profile_image_url" => image,
- "profile_image_url_https" => image,
- "profile_image_url_profile_size" => image,
- "profile_image_url_original" => image,
- "rights" => %{
- "delete_others_notice" => !!user.info.is_moderator,
- "admin" => !!user.info.is_admin
- },
- "screen_name" => user.nickname,
- "statuses_count" => user_info[:note_count],
- "statusnet_profile_url" => user.ap_id,
- "cover_photo" => User.banner_url(user) |> MediaProxy.url(),
- "background_image" => image_url(user.info.background) |> MediaProxy.url(),
- "is_local" => user.local,
- "locked" => user.info.locked,
- "default_scope" => user.info.default_scope,
- "no_rich_text" => user.info.no_rich_text,
- "hide_followers" => user.info.hide_followers,
- "hide_follows" => user.info.hide_follows,
- "fields" => fields,
-
- # Pleroma extension
- "pleroma" =>
- %{
- "confirmation_pending" => user_info.confirmation_pending,
- "tags" => user.tags
- }
- |> maybe_with_activation_status(user, for_user)
- }
-
data =
- if(user.info.is_admin || user.info.is_moderator,
- do: maybe_with_role(data, user, for_user),
- else: data
- )
+ %{
+ "created_at" => user.inserted_at |> Utils.format_naive_asctime(),
+ "description" => HTML.strip_tags((user.bio || "") |> String.replace("<br>", "\n")),
+ "description_html" => HTML.filter_tags(user.bio, User.html_filter_policy(for_user)),
+ "favourites_count" => 0,
+ "followers_count" => user_info[:follower_count],
+ "following" => following,
+ "follows_you" => follows_you,
+ "statusnet_blocking" => statusnet_blocking,
+ "friends_count" => user_info[:following_count],
+ "id" => user.id,
+ "name" => user.name || user.nickname,
+ "name_html" =>
+ if(user.name,
+ do: HTML.strip_tags(user.name) |> Formatter.emojify(emoji),
+ else: user.nickname
+ ),
+ "profile_image_url" => image,
+ "profile_image_url_https" => image,
+ "profile_image_url_profile_size" => image,
+ "profile_image_url_original" => image,
+ "screen_name" => user.nickname,
+ "statuses_count" => user_info[:note_count],
+ "statusnet_profile_url" => user.ap_id,
+ "cover_photo" => User.banner_url(user) |> MediaProxy.url(),
+ "background_image" => image_url(user.info.background) |> MediaProxy.url(),
+ "is_local" => user.local,
+ "locked" => user.info.locked,
+ "hide_followers" => user.info.hide_followers,
+ "hide_follows" => user.info.hide_follows,
+ "fields" => fields,
+
+ # Pleroma extension
+ "pleroma" =>
+ %{
+ "confirmation_pending" => user_info.confirmation_pending,
+ "tags" => user.tags
+ }
+ |> maybe_with_activation_status(user, for_user)
+ }
+ |> maybe_with_user_settings(user, for_user)
+ |> maybe_with_role(user, for_user)
if assigns[:token] do
Map.put(data, "token", token_string(assigns[:token]))
@@ -141,15 +132,35 @@ defmodule Pleroma.Web.TwitterAPI.UserView do
defp maybe_with_activation_status(data, _, _), do: data
defp maybe_with_role(data, %User{id: id} = user, %User{id: id}) do
- Map.merge(data, %{"role" => role(user), "show_role" => user.info.show_role})
+ Map.merge(data, %{
+ "role" => role(user),
+ "show_role" => user.info.show_role,
+ "rights" => %{
+ "delete_others_notice" => !!user.info.is_moderator,
+ "admin" => !!user.info.is_admin
+ }
+ })
end
defp maybe_with_role(data, %User{info: %{show_role: true}} = user, _user) do
- Map.merge(data, %{"role" => role(user)})
+ Map.merge(data, %{
+ "role" => role(user),
+ "rights" => %{
+ "delete_others_notice" => !!user.info.is_moderator,
+ "admin" => !!user.info.is_admin
+ }
+ })
end
defp maybe_with_role(data, _, _), do: data
+ defp maybe_with_user_settings(data, %User{info: info, id: id} = _user, %User{id: id}) do
+ data
+ |> Kernel.put_in(["default_scope"], info.default_scope)
+ |> Kernel.put_in(["no_rich_text"], info.no_rich_text)
+ end
+
+ defp maybe_with_user_settings(data, _, _), do: data
defp role(%User{info: %{:is_admin => true}}), do: "admin"
defp role(%User{info: %{:is_moderator => true}}), do: "moderator"
defp role(_), do: "member"
diff --git a/lib/pleroma/web/web_finger/web_finger.ex b/lib/pleroma/web/web_finger/web_finger.ex
index 32c3455f5..a3b0bf999 100644
--- a/lib/pleroma/web/web_finger/web_finger.ex
+++ b/lib/pleroma/web/web_finger/web_finger.ex
@@ -37,7 +37,7 @@ defmodule Pleroma.Web.WebFinger do
regex = ~r/(acct:)?(?<username>\w+)@#{host}/
with %{"username" => username} <- Regex.named_captures(regex, resource),
- %User{} = user <- User.get_by_nickname(username) do
+ %User{} = user <- User.get_cached_by_nickname(username) do
{:ok, represent_user(user, fmt)}
else
_e ->