aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/pleroma/application.ex36
-rw-r--r--lib/pleroma/config/deprecation_warnings.ex20
-rw-r--r--lib/pleroma/html.ex2
-rw-r--r--lib/pleroma/http/connection.ex3
-rw-r--r--lib/pleroma/instances.ex36
-rw-r--r--lib/pleroma/instances/instance.ex102
-rw-r--r--lib/pleroma/plugs/instance_static.ex2
-rw-r--r--lib/pleroma/uploaders/mdii.ex3
-rw-r--r--lib/pleroma/user.ex85
-rw-r--r--lib/pleroma/web/activity_pub/activity_pub.ex38
-rw-r--r--lib/pleroma/web/activity_pub/activity_pub_controller.ex11
-rw-r--r--lib/pleroma/web/activity_pub/transmogrifier.ex4
-rw-r--r--lib/pleroma/web/activity_pub/utils.ex19
-rw-r--r--lib/pleroma/web/endpoint.ex2
-rw-r--r--lib/pleroma/web/federator/federator.ex6
-rw-r--r--lib/pleroma/web/mastodon_api/mastodon_api_controller.ex75
-rw-r--r--lib/pleroma/web/mastodon_api/views/status_view.ex29
-rw-r--r--lib/pleroma/web/ostatus/ostatus.ex3
-rw-r--r--lib/pleroma/web/ostatus/ostatus_controller.ex1
-rw-r--r--lib/pleroma/web/rich_media/controllers/rich_media_controller.ex17
-rw-r--r--lib/pleroma/web/rich_media/helpers.ex19
-rw-r--r--lib/pleroma/web/rich_media/parser.ex55
-rw-r--r--lib/pleroma/web/rich_media/parsers/oembed_parser.ex8
-rw-r--r--lib/pleroma/web/router.ex10
-rw-r--r--lib/pleroma/web/salmon/salmon.ex30
-rw-r--r--lib/pleroma/web/templates/mastodon_api/mastodon/index.html.eex27
-rw-r--r--lib/pleroma/web/twitter_api/controllers/util_controller.ex52
-rw-r--r--lib/pleroma/web/twitter_api/representers/activity_representer.ex10
-rw-r--r--lib/pleroma/web/twitter_api/views/activity_view.ex12
-rw-r--r--lib/pleroma/web/websub/websub.ex31
-rw-r--r--lib/pleroma/web/websub/websub_controller.ex2
31 files changed, 585 insertions, 165 deletions
diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex
index 47c0e5b68..40bff08c7 100644
--- a/lib/pleroma/application.ex
+++ b/lib/pleroma/application.ex
@@ -22,6 +22,8 @@ defmodule Pleroma.Application do
def start(_type, _args) do
import Cachex.Spec
+ Pleroma.Config.DeprecationWarnings.warn()
+
# Define workers and child supervisors to be supervised
children =
[
@@ -99,12 +101,15 @@ defmodule Pleroma.Application do
],
id: :cachex_idem
),
- worker(Pleroma.FlakeId, []),
- worker(Pleroma.Web.Federator.RetryQueue, []),
- worker(Pleroma.Web.Federator, []),
- worker(Pleroma.Stats, []),
- worker(Pleroma.Web.Push, [])
+ worker(Pleroma.FlakeId, [])
] ++
+ hackney_pool_children() ++
+ [
+ worker(Pleroma.Web.Federator.RetryQueue, []),
+ worker(Pleroma.Web.Federator, []),
+ worker(Pleroma.Stats, []),
+ worker(Pleroma.Web.Push, [])
+ ] ++
streamer_child() ++
chat_child() ++
[
@@ -119,6 +124,20 @@ defmodule Pleroma.Application do
Supervisor.start_link(children, opts)
end
+ def enabled_hackney_pools() do
+ [:media] ++
+ if Application.get_env(:tesla, :adapter) == Tesla.Adapter.Hackney do
+ [:federation]
+ else
+ []
+ end ++
+ if Pleroma.Config.get([Pleroma.Uploader, :proxy_remote]) do
+ [:upload]
+ else
+ []
+ end
+ end
+
if Mix.env() == :test do
defp streamer_child(), do: []
defp chat_child(), do: []
@@ -135,4 +154,11 @@ defmodule Pleroma.Application do
end
end
end
+
+ defp hackney_pool_children() do
+ for pool <- enabled_hackney_pools() do
+ options = Pleroma.Config.get([:hackney_pools, pool])
+ :hackney_pool.child_spec(pool, options)
+ end
+ end
end
diff --git a/lib/pleroma/config/deprecation_warnings.ex b/lib/pleroma/config/deprecation_warnings.ex
new file mode 100644
index 000000000..dc50682ee
--- /dev/null
+++ b/lib/pleroma/config/deprecation_warnings.ex
@@ -0,0 +1,20 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Config.DeprecationWarnings do
+ require Logger
+
+ def check_frontend_config_mechanism() do
+ if Pleroma.Config.get(:fe) do
+ Logger.warn("""
+ !!!DEPRECATION WARNING!!!
+ You are using the old configuration mechanism for the frontend. Please check config.md.
+ """)
+ end
+ end
+
+ def warn do
+ check_frontend_config_mechanism()
+ end
+end
diff --git a/lib/pleroma/html.ex b/lib/pleroma/html.ex
index fb602d6b6..bf5daa948 100644
--- a/lib/pleroma/html.ex
+++ b/lib/pleroma/html.ex
@@ -69,7 +69,7 @@ defmodule Pleroma.HTML do
|> Floki.attribute("a", "href")
|> Enum.at(0)
- {:commit, result}
+ {:commit, {:ok, result}}
end)
end
end
diff --git a/lib/pleroma/http/connection.ex b/lib/pleroma/http/connection.ex
index 699d80cd7..b798eaa5a 100644
--- a/lib/pleroma/http/connection.ex
+++ b/lib/pleroma/http/connection.ex
@@ -10,7 +10,8 @@ defmodule Pleroma.HTTP.Connection do
@hackney_options [
timeout: 10000,
recv_timeout: 20000,
- follow_redirect: true
+ follow_redirect: true,
+ pool: :federation
]
@adapter Application.get_env(:tesla, :adapter)
diff --git a/lib/pleroma/instances.ex b/lib/pleroma/instances.ex
new file mode 100644
index 000000000..5e107f4c9
--- /dev/null
+++ b/lib/pleroma/instances.ex
@@ -0,0 +1,36 @@
+defmodule Pleroma.Instances do
+ @moduledoc "Instances context."
+
+ @adapter Pleroma.Instances.Instance
+
+ defdelegate filter_reachable(urls_or_hosts), to: @adapter
+ defdelegate reachable?(url_or_host), to: @adapter
+ defdelegate set_reachable(url_or_host), to: @adapter
+ defdelegate set_unreachable(url_or_host, unreachable_since \\ nil), to: @adapter
+
+ def set_consistently_unreachable(url_or_host),
+ do: set_unreachable(url_or_host, reachability_datetime_threshold())
+
+ def reachability_datetime_threshold do
+ federation_reachability_timeout_days =
+ Pleroma.Config.get(:instance)[:federation_reachability_timeout_days] || 0
+
+ if federation_reachability_timeout_days > 0 do
+ NaiveDateTime.add(
+ NaiveDateTime.utc_now(),
+ -federation_reachability_timeout_days * 24 * 3600,
+ :second
+ )
+ else
+ ~N[0000-01-01 00:00:00]
+ end
+ end
+
+ def host(url_or_host) when is_binary(url_or_host) do
+ if url_or_host =~ ~r/^http/i do
+ URI.parse(url_or_host).host
+ else
+ url_or_host
+ end
+ end
+end
diff --git a/lib/pleroma/instances/instance.ex b/lib/pleroma/instances/instance.ex
new file mode 100644
index 000000000..a87590d8b
--- /dev/null
+++ b/lib/pleroma/instances/instance.ex
@@ -0,0 +1,102 @@
+defmodule Pleroma.Instances.Instance do
+ @moduledoc "Instance."
+
+ alias Pleroma.Instances
+ alias Pleroma.Instances.Instance
+
+ use Ecto.Schema
+
+ import Ecto.{Query, Changeset}
+
+ alias Pleroma.Repo
+
+ schema "instances" do
+ field(:host, :string)
+ field(:unreachable_since, :naive_datetime)
+
+ timestamps()
+ end
+
+ defdelegate host(url_or_host), to: Instances
+
+ def changeset(struct, params \\ %{}) do
+ struct
+ |> cast(params, [:host, :unreachable_since])
+ |> validate_required([:host])
+ |> unique_constraint(:host)
+ end
+
+ def filter_reachable([]), do: []
+
+ def filter_reachable(urls_or_hosts) when is_list(urls_or_hosts) do
+ hosts =
+ urls_or_hosts
+ |> Enum.map(&(&1 && host(&1)))
+ |> Enum.filter(&(to_string(&1) != ""))
+
+ unreachable_hosts =
+ Repo.all(
+ from(i in Instance,
+ where:
+ i.host in ^hosts and
+ i.unreachable_since <= ^Instances.reachability_datetime_threshold(),
+ select: i.host
+ )
+ )
+
+ Enum.filter(urls_or_hosts, &(&1 && host(&1) not in unreachable_hosts))
+ end
+
+ def reachable?(url_or_host) when is_binary(url_or_host) do
+ !Repo.one(
+ from(i in Instance,
+ where:
+ i.host == ^host(url_or_host) and
+ i.unreachable_since <= ^Instances.reachability_datetime_threshold(),
+ select: true
+ )
+ )
+ end
+
+ def reachable?(_), do: true
+
+ def set_reachable(url_or_host) when is_binary(url_or_host) do
+ with host <- host(url_or_host),
+ %Instance{} = existing_record <- Repo.get_by(Instance, %{host: host}) do
+ {:ok, _instance} =
+ existing_record
+ |> changeset(%{unreachable_since: nil})
+ |> Repo.update()
+ end
+ end
+
+ def set_reachable(_), do: {:error, nil}
+
+ def set_unreachable(url_or_host, unreachable_since \\ nil)
+
+ def set_unreachable(url_or_host, unreachable_since) when is_binary(url_or_host) do
+ unreachable_since = unreachable_since || DateTime.utc_now()
+ host = host(url_or_host)
+ existing_record = Repo.get_by(Instance, %{host: host})
+
+ changes = %{unreachable_since: unreachable_since}
+
+ cond do
+ is_nil(existing_record) ->
+ %Instance{}
+ |> changeset(Map.put(changes, :host, host))
+ |> Repo.insert()
+
+ existing_record.unreachable_since &&
+ NaiveDateTime.compare(existing_record.unreachable_since, unreachable_since) != :gt ->
+ {:ok, existing_record}
+
+ true ->
+ existing_record
+ |> changeset(changes)
+ |> Repo.update()
+ end
+ end
+
+ def set_unreachable(_, _), do: {:error, nil}
+end
diff --git a/lib/pleroma/plugs/instance_static.ex b/lib/pleroma/plugs/instance_static.ex
index af2f6f331..11f108de7 100644
--- a/lib/pleroma/plugs/instance_static.ex
+++ b/lib/pleroma/plugs/instance_static.ex
@@ -21,7 +21,7 @@ defmodule Pleroma.Plugs.InstanceStatic do
end
end
- @only ~w(index.html static emoji packs sounds images instance favicon.png)
+ @only ~w(index.html static emoji packs sounds images instance favicon.png sw.js sw-pleroma.js)
def init(opts) do
opts
diff --git a/lib/pleroma/uploaders/mdii.ex b/lib/pleroma/uploaders/mdii.ex
index 530b34362..320b07abd 100644
--- a/lib/pleroma/uploaders/mdii.ex
+++ b/lib/pleroma/uploaders/mdii.ex
@@ -24,7 +24,8 @@ defmodule Pleroma.Uploaders.MDII do
extension = String.split(upload.name, ".") |> List.last()
query = "#{cgi}?#{extension}"
- with {:ok, %{status: 200, body: body}} <- @httpoison.post(query, file_data) do
+ with {:ok, %{status: 200, body: body}} <-
+ @httpoison.post(query, file_data, adapter: [pool: :default]) do
remote_file_name = String.split(body) |> List.first()
public_url = "#{files}/#{remote_file_name}.#{extension}"
{:ok, {:url, public_url}}
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index 1468cc133..33630ac7c 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -39,6 +39,7 @@ defmodule Pleroma.User do
field(:follower_address, :string)
field(:search_rank, :float, virtual: true)
field(:tags, {:array, :string}, default: [])
+ field(:bookmarks, {:array, :string}, default: [])
field(:last_refreshed_at, :naive_datetime)
has_many(:notifications, Notification)
embeds_one(:info, Pleroma.User.Info)
@@ -309,20 +310,30 @@ defmodule Pleroma.User do
@doc "A mass follow for local users. Ignores blocks and has no side effects"
@spec follow_all(User.t(), list(User.t())) :: {atom(), User.t()}
def follow_all(follower, followeds) do
- following =
- (follower.following ++ Enum.map(followeds, fn %{follower_address: fa} -> fa end))
- |> Enum.uniq()
+ followed_addresses = Enum.map(followeds, fn %{follower_address: fa} -> fa end)
+
+ q =
+ from(u in User,
+ where: u.id == ^follower.id,
+ update: [
+ set: [
+ following:
+ fragment(
+ "array(select distinct unnest (array_cat(?, ?)))",
+ u.following,
+ ^followed_addresses
+ )
+ ]
+ ]
+ )
- {:ok, follower} =
- follower
- |> follow_changeset(%{following: following})
- |> update_and_set_cache
+ {1, [follower]} = Repo.update_all(q, [], returning: true)
Enum.each(followeds, fn followed ->
update_follower_count(followed)
end)
- {:ok, follower}
+ set_cache(follower)
end
def follow(%User{} = follower, %User{info: info} = followed) do
@@ -343,18 +354,17 @@ defmodule Pleroma.User do
Websub.subscribe(follower, followed)
end
- following =
- [ap_followers | follower.following]
- |> Enum.uniq()
+ q =
+ from(u in User,
+ where: u.id == ^follower.id,
+ update: [push: [following: ^ap_followers]]
+ )
- follower =
- follower
- |> follow_changeset(%{following: following})
- |> update_and_set_cache
+ {1, [follower]} = Repo.update_all(q, [], returning: true)
{:ok, _} = update_follower_count(followed)
- follower
+ set_cache(follower)
end
end
@@ -362,17 +372,18 @@ defmodule Pleroma.User do
ap_followers = followed.follower_address
if following?(follower, followed) and follower.ap_id != followed.ap_id do
- following =
- follower.following
- |> List.delete(ap_followers)
+ q =
+ from(u in User,
+ where: u.id == ^follower.id,
+ update: [pull: [following: ^ap_followers]]
+ )
- {:ok, follower} =
- follower
- |> follow_changeset(%{following: following})
- |> update_and_set_cache
+ {1, [follower]} = Repo.update_all(q, [], returning: true)
{:ok, followed} = update_follower_count(followed)
+ set_cache(follower)
+
{:ok, follower, Utils.fetch_latest_follow(follower, followed)}
else
{:error, "Not subscribed!"}
@@ -423,12 +434,16 @@ defmodule Pleroma.User do
get_by_nickname(nickname)
end
+ def set_cache(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
+
def update_and_set_cache(changeset) do
with {:ok, user} <- Repo.update(changeset) 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}
+ set_cache(user)
else
e -> e
end
@@ -1156,6 +1171,22 @@ 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/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex
index feff22400..06e8c3f1c 100644
--- a/lib/pleroma/web/activity_pub/activity_pub.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub.ex
@@ -3,7 +3,7 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.ActivityPub do
- alias Pleroma.{Activity, Repo, Object, Upload, User, Notification}
+ alias Pleroma.{Activity, Repo, Object, Upload, User, Notification, Instances}
alias Pleroma.Web.ActivityPub.{Transmogrifier, MRF}
alias Pleroma.Web.WebFinger
alias Pleroma.Web.Federator
@@ -88,6 +88,10 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
recipients: recipients
})
+ Task.start(fn ->
+ Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity)
+ end)
+
Notification.create_notifications(activity)
stream_out(activity)
{:ok, activity}
@@ -730,7 +734,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
end
def publish(actor, activity) do
- followers =
+ remote_followers =
if actor.follower_address in activity.recipients do
{:ok, followers} = User.get_followers(actor)
followers |> Enum.filter(&(!&1.local))
@@ -741,13 +745,14 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
public = is_public?(activity)
remote_inboxes =
- (Pleroma.Web.Salmon.remote_users(activity) ++ followers)
+ (Pleroma.Web.Salmon.remote_users(activity) ++ remote_followers)
|> Enum.filter(fn user -> User.ap_enabled?(user) end)
|> Enum.map(fn %{info: %{source_data: data}} ->
(is_map(data["endpoints"]) && Map.get(data["endpoints"], "sharedInbox")) || data["inbox"]
end)
|> Enum.uniq()
|> Enum.filter(fn inbox -> should_federate?(inbox, public) end)
+ |> Instances.filter_reachable()
{:ok, data} = Transmogrifier.prepare_outgoing(activity.data)
json = Jason.encode!(data)
@@ -775,15 +780,24 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
digest: digest
})
- @httpoison.post(
- inbox,
- json,
- [
- {"Content-Type", "application/activity+json"},
- {"signature", signature},
- {"digest", digest}
- ]
- )
+ with {:ok, %{status: code}} when code in 200..299 <-
+ result =
+ @httpoison.post(
+ inbox,
+ json,
+ [
+ {"Content-Type", "application/activity+json"},
+ {"signature", signature},
+ {"digest", digest}
+ ]
+ ) do
+ Instances.set_reachable(inbox)
+ result
+ else
+ {_post_result, response} ->
+ Instances.set_unreachable(inbox)
+ {:error, response}
+ end
end
# TODO:
diff --git a/lib/pleroma/web/activity_pub/activity_pub_controller.ex b/lib/pleroma/web/activity_pub/activity_pub_controller.ex
index 7eed0a600..4dea6ab83 100644
--- a/lib/pleroma/web/activity_pub/activity_pub_controller.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub_controller.ex
@@ -4,6 +4,7 @@
defmodule Pleroma.Web.ActivityPub.ActivityPubController do
use Pleroma.Web, :controller
+
alias Pleroma.{Activity, User, Object}
alias Pleroma.Web.ActivityPub.{ObjectView, UserView}
alias Pleroma.Web.ActivityPub.ActivityPub
@@ -17,6 +18,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
action_fallback(:errors)
plug(Pleroma.Web.FederatingPlug when action in [:inbox, :relay])
+ plug(:set_requester_reachable when action in [:inbox])
plug(:relay_active? when action in [:relay])
def relay_active?(conn, _) do
@@ -289,4 +291,13 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
|> put_status(500)
|> json("error")
end
+
+ defp set_requester_reachable(%Plug.Conn{} = conn, _) do
+ with actor <- conn.params["actor"],
+ true <- is_binary(actor) do
+ Pleroma.Instances.set_reachable(actor)
+ end
+
+ conn
+ end
end
diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex
index c2ced51d8..43725c3db 100644
--- a/lib/pleroma/web/activity_pub/transmogrifier.ex
+++ b/lib/pleroma/web/activity_pub/transmogrifier.ex
@@ -453,9 +453,9 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
{:ok, follow_activity} <- Utils.update_follow_state(follow_activity, "reject"),
%User{local: true} = follower <- User.get_cached_by_ap_id(follow_activity.data["actor"]),
{:ok, activity} <-
- ActivityPub.accept(%{
+ ActivityPub.reject(%{
to: follow_activity.data["to"],
- type: "Accept",
+ type: "Reject",
actor: followed.ap_id,
object: follow_activity.data["id"],
local: false
diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex
index e40d05fcd..3b0cdfe71 100644
--- a/lib/pleroma/web/activity_pub/utils.ex
+++ b/lib/pleroma/web/activity_pub/utils.ex
@@ -316,6 +316,25 @@ defmodule Pleroma.Web.ActivityPub.Utils do
@doc """
Updates a follow activity's state (for locked accounts).
"""
+ def update_follow_state(
+ %Activity{data: %{"actor" => actor, "object" => object, "state" => "pending"}} = activity,
+ state
+ ) do
+ try do
+ Ecto.Adapters.SQL.query!(
+ Repo,
+ "UPDATE activities SET data = jsonb_set(data, '{state}', $1) WHERE data->>'type' = 'Follow' AND data->>'actor' = $2 AND data->>'object' = $3 AND data->>'state' = 'pending'",
+ [state, actor, object]
+ )
+
+ activity = Repo.get(Activity, activity.id)
+ {:ok, activity}
+ rescue
+ e ->
+ {:error, e}
+ end
+ end
+
def update_follow_state(%Activity{} = activity, state) do
with new_data <-
activity.data
diff --git a/lib/pleroma/web/endpoint.ex b/lib/pleroma/web/endpoint.ex
index 0b4ce9cc4..2b156fdfd 100644
--- a/lib/pleroma/web/endpoint.ex
+++ b/lib/pleroma/web/endpoint.ex
@@ -25,7 +25,7 @@ defmodule Pleroma.Web.Endpoint do
at: "/",
from: :pleroma,
only:
- ~w(index.html static finmoji emoji packs sounds images instance sw.js favicon.png schemas doc)
+ ~w(index.html static finmoji emoji packs sounds images instance sw.js sw-pleroma.js favicon.png schemas doc)
)
# Code reloading can be explicitly enabled under the
diff --git a/lib/pleroma/web/federator/federator.ex b/lib/pleroma/web/federator/federator.ex
index f3a0e18b8..46f7a4973 100644
--- a/lib/pleroma/web/federator/federator.ex
+++ b/lib/pleroma/web/federator/federator.ex
@@ -6,7 +6,7 @@ defmodule Pleroma.Web.Federator do
use GenServer
alias Pleroma.User
alias Pleroma.Activity
- alias Pleroma.Web.{WebFinger, Websub}
+ alias Pleroma.Web.{WebFinger, Websub, Salmon}
alias Pleroma.Web.Federator.RetryQueue
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Relay
@@ -124,6 +124,10 @@ defmodule Pleroma.Web.Federator do
end
end
+ def handle(:publish_single_salmon, {user_or_url, feed, poster}) do
+ Salmon.send_to_user(user_or_url, feed, poster)
+ end
+
def handle(:publish_single_ap, params) do
case ActivityPub.publish_one(params) do
{:ok, _} ->
diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
index 3364b2ac2..491ed9dc5 100644
--- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
+++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
@@ -6,7 +6,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
use Pleroma.Web, :controller
alias Pleroma.{Repo, Object, Activity, User, Notification, Stats}
alias Pleroma.Web
- alias Pleroma.HTML
alias Pleroma.Web.MastodonAPI.{
StatusView,
@@ -424,6 +423,28 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
end
+ def bookmark_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do
+ with %Activity{} = activity <- Repo.get(Activity, id),
+ %User{} = user <- User.get_by_nickname(user.nickname),
+ true <- ActivityPub.visible_for_user?(activity, user),
+ {:ok, user} <- User.bookmark(user, activity.data["object"]["id"]) do
+ conn
+ |> put_view(StatusView)
+ |> try_render("status.json", %{activity: activity, for: user, as: :activity})
+ end
+ end
+
+ def unbookmark_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do
+ with %Activity{} = activity <- Repo.get(Activity, id),
+ %User{} = user <- User.get_by_nickname(user.nickname),
+ true <- ActivityPub.visible_for_user?(activity, user),
+ {:ok, user} <- User.unbookmark(user, activity.data["object"]["id"]) do
+ conn
+ |> put_view(StatusView)
+ |> try_render("status.json", %{activity: activity, for: user, as: :activity})
+ end
+ end
+
def notifications(%{assigns: %{user: user}} = conn, params) do
notifications = Notification.for_user(user, params)
@@ -500,7 +521,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
def upload(%{assigns: %{user: user}} = conn, %{"file" => file} = data) do
with {:ok, object} <-
- ActivityPub.upload(file,
+ ActivityPub.upload(
+ file,
actor: User.ap_id(user),
description: Map.get(data, "description")
) do
@@ -859,6 +881,19 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|> render("index.json", %{activities: activities, for: user, as: :activity})
end
+ def bookmarks(%{assigns: %{user: user}} = conn, _) do
+ user = Repo.get(User, user.id)
+
+ activities =
+ user.bookmarks
+ |> Enum.map(fn id -> Activity.get_create_by_object_ap_id(id) end)
+ |> Enum.reverse()
+
+ conn
+ |> put_view(StatusView)
+ |> render("index.json", %{activities: activities, for: user, as: :activity})
+ end
+
def get_lists(%{assigns: %{user: user}} = conn, opts) do
lists = Pleroma.List.for_user(user, opts)
res = ListView.render("lists.json", lists: lists)
@@ -1101,7 +1136,9 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
def login(conn, _) do
with {:ok, app} <- get_or_make_app() do
path =
- o_auth_path(conn, :authorize,
+ o_auth_path(
+ conn,
+ :authorize,
response_type: "code",
client_id: app.client_id,
redirect_uri: ".",
@@ -1309,7 +1346,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
[],
adapter: [
timeout: timeout,
- recv_timeout: timeout
+ recv_timeout: timeout,
+ pool: :default
]
),
{:ok, data} <- Jason.decode(body) do
@@ -1342,29 +1380,22 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
end
- def get_status_card(status_id) do
+ def status_card(conn, %{"id" => status_id}) do
with %Activity{} = activity <- Repo.get(Activity, status_id),
- true <- ActivityPub.is_public?(activity),
- %Object{} = object <- Object.normalize(activity.data["object"]),
- page_url <- HTML.extract_first_external_url(object, object.data["content"]),
- {:ok, rich_media} <- Pleroma.Web.RichMedia.Parser.parse(page_url) do
- page_url = rich_media[:url] || page_url
- site_name = rich_media[:site_name] || URI.parse(page_url).host
-
- rich_media
- |> Map.take([:image, :title, :description])
- |> Map.put(:type, "link")
- |> Map.put(:provider_name, site_name)
- |> Map.put(:url, page_url)
+ true <- ActivityPub.is_public?(activity) do
+ data =
+ StatusView.render(
+ "card.json",
+ Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity)
+ )
+
+ json(conn, data)
else
- _ -> %{}
+ _e ->
+ %{}
end
end
- def status_card(conn, %{"id" => status_id}) do
- json(conn, get_status_card(status_id))
- end
-
def try_render(conn, target, params)
when is_binary(target) do
res = render(conn, target, params)
diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex
index ddfe6788c..d5b7e68c7 100644
--- a/lib/pleroma/web/mastodon_api/views/status_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/status_view.ex
@@ -87,6 +87,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
favourites_count: 0,
reblogged: false,
favourited: false,
+ bookmarked: false,
muted: false,
pinned: pinned?(activity, user),
sensitive: false,
@@ -121,6 +122,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
repeated = opts[:for] && opts[:for].ap_id in (object["announcements"] || [])
favorited = opts[:for] && opts[:for].ap_id in (object["likes"] || [])
+ bookmarked = opts[:for] && object["id"] in opts[:for].bookmarks
attachment_data = object["attachment"] || []
attachments = render_many(attachment_data, StatusView, "attachment.json", as: :attachment)
@@ -139,6 +141,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
__MODULE__
)
+ card = render("card.json", Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity))
+
%{
id: to_string(activity.id),
uri: object["id"],
@@ -147,6 +151,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
in_reply_to_id: reply_to && to_string(reply_to.id),
in_reply_to_account_id: reply_to_user && to_string(reply_to_user.id),
reblog: nil,
+ card: card,
content: content,
created_at: created_at,
reblogs_count: announcement_count,
@@ -154,6 +159,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
favourites_count: like_count,
reblogged: present?(repeated),
favourited: present?(favorited),
+ bookmarked: present?(bookmarked),
muted: false,
pinned: pinned?(activity, user),
sensitive: sensitive,
@@ -175,6 +181,29 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
nil
end
+ def render("card.json", %{rich_media: rich_media, page_url: page_url}) do
+ page_url = rich_media[:url] || page_url
+ page_url_data = URI.parse(page_url)
+ site_name = rich_media[:site_name] || page_url_data.host
+
+ %{
+ type: "link",
+ provider_name: site_name,
+ provider_url: page_url_data.scheme <> "://" <> page_url_data.host,
+ url: page_url,
+ image: rich_media[:image] |> MediaProxy.url(),
+ title: rich_media[:title],
+ description: rich_media[:description],
+ pleroma: %{
+ opengraph: rich_media
+ }
+ }
+ end
+
+ def render("card.json", _) do
+ nil
+ end
+
def render("attachment.json", %{attachment: attachment}) do
[attachment_url | _] = attachment["url"]
media_type = attachment_url["mediaType"] || attachment_url["mimeType"] || "image"
diff --git a/lib/pleroma/web/ostatus/ostatus.ex b/lib/pleroma/web/ostatus/ostatus.ex
index a3155b79d..a20ca17bb 100644
--- a/lib/pleroma/web/ostatus/ostatus.ex
+++ b/lib/pleroma/web/ostatus/ostatus.ex
@@ -48,6 +48,9 @@ defmodule Pleroma.Web.OStatus do
def handle_incoming(xml_string) do
with doc when doc != :error <- parse_document(xml_string) do
+ with {:ok, actor_user} <- find_make_or_update_user(doc),
+ do: Pleroma.Instances.set_reachable(actor_user.ap_id)
+
entries = :xmerl_xpath.string('//entry', doc)
activities =
diff --git a/lib/pleroma/web/ostatus/ostatus_controller.ex b/lib/pleroma/web/ostatus/ostatus_controller.ex
index 297aca2f9..302ff38a4 100644
--- a/lib/pleroma/web/ostatus/ostatus_controller.ex
+++ b/lib/pleroma/web/ostatus/ostatus_controller.ex
@@ -14,6 +14,7 @@ defmodule Pleroma.Web.OStatus.OStatusController do
alias Pleroma.Web.ActivityPub.ActivityPub
plug(Pleroma.Web.FederatingPlug when action in [:salmon_incoming])
+
action_fallback(:errors)
def feed_redirect(conn, %{"nickname" => nickname}) do
diff --git a/lib/pleroma/web/rich_media/controllers/rich_media_controller.ex b/lib/pleroma/web/rich_media/controllers/rich_media_controller.ex
deleted file mode 100644
index 91019961d..000000000
--- a/lib/pleroma/web/rich_media/controllers/rich_media_controller.ex
+++ /dev/null
@@ -1,17 +0,0 @@
-defmodule Pleroma.Web.RichMedia.RichMediaController do
- use Pleroma.Web, :controller
-
- import Pleroma.Web.ControllerHelper, only: [json_response: 3]
-
- def parse(conn, %{"url" => url}) do
- case Pleroma.Web.RichMedia.Parser.parse(url) do
- {:ok, data} ->
- conn
- |> json_response(200, data)
-
- {:error, msg} ->
- conn
- |> json_response(404, msg)
- end
- end
-end
diff --git a/lib/pleroma/web/rich_media/helpers.ex b/lib/pleroma/web/rich_media/helpers.ex
new file mode 100644
index 000000000..521fa7ee0
--- /dev/null
+++ b/lib/pleroma/web/rich_media/helpers.ex
@@ -0,0 +1,19 @@
+# Pleroma: A lightweight social networking server
+# Copyright _ 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.RichMedia.Helpers do
+ alias Pleroma.{Activity, Object, HTML}
+ alias Pleroma.Web.RichMedia.Parser
+
+ def fetch_data_for_activity(%Activity{} = activity) do
+ with true <- Pleroma.Config.get([:rich_media, :enabled]),
+ %Object{} = object <- Object.normalize(activity.data["object"]),
+ {:ok, page_url} <- HTML.extract_first_external_url(object, object.data["content"]),
+ {:ok, rich_media} <- Parser.parse(page_url) do
+ %{page_url: page_url, rich_media: rich_media}
+ else
+ _ -> %{}
+ end
+ end
+end
diff --git a/lib/pleroma/web/rich_media/parser.ex b/lib/pleroma/web/rich_media/parser.ex
index 947dc0c3c..32dec9887 100644
--- a/lib/pleroma/web/rich_media/parser.ex
+++ b/lib/pleroma/web/rich_media/parser.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.RichMedia.Parser do
@parsers [
Pleroma.Web.RichMedia.Parsers.OGP,
@@ -11,19 +15,26 @@ defmodule Pleroma.Web.RichMedia.Parser do
def parse(url), do: parse_url(url)
else
def parse(url) do
- with {:ok, data} <- Cachex.fetch(:rich_media_cache, url, fn _ -> parse_url(url) end) do
- data
- else
- _e ->
- {:error, "Parsing error"}
+ try do
+ Cachex.fetch!(:rich_media_cache, url, fn _ ->
+ {:commit, parse_url(url)}
+ end)
+ rescue
+ e ->
+ {:error, "Cachex error: #{inspect(e)}"}
end
end
end
defp parse_url(url) do
- {:ok, %Tesla.Env{body: html}} = Pleroma.HTTP.get(url)
+ try do
+ {:ok, %Tesla.Env{body: html}} = Pleroma.HTTP.get(url, [], adapter: [pool: :media])
- html |> maybe_parse() |> get_parsed_data()
+ html |> maybe_parse() |> clean_parsed_data() |> check_parsed_data()
+ rescue
+ e ->
+ {:error, "Parsing error: #{inspect(e)}"}
+ end
end
defp maybe_parse(html) do
@@ -35,11 +46,33 @@ defmodule Pleroma.Web.RichMedia.Parser do
end)
end
- defp get_parsed_data(data) when data == %{} do
- {:error, "No metadata found"}
+ defp check_parsed_data(%{title: title} = data) when is_binary(title) and byte_size(title) > 0 do
+ {:ok, data}
+ end
+
+ defp check_parsed_data(data) do
+ {:error, "Found metadata was invalid or incomplete: #{inspect(data)}"}
end
- defp get_parsed_data(data) do
- {:ok, data}
+ defp string_is_valid_unicode(data) when is_binary(data) do
+ data
+ |> :unicode.characters_to_binary()
+ |> clean_string()
+ end
+
+ defp string_is_valid_unicode(data), do: {:ok, data}
+
+ defp clean_string({:error, _, _}), do: {:error, "Invalid data"}
+ defp clean_string(data), do: {:ok, data}
+
+ defp clean_parsed_data(data) do
+ data
+ |> Enum.reject(fn {_, val} ->
+ case string_is_valid_unicode(val) do
+ {:ok, _} -> false
+ _ -> true
+ end
+ end)
+ |> Map.new()
end
end
diff --git a/lib/pleroma/web/rich_media/parsers/oembed_parser.ex b/lib/pleroma/web/rich_media/parsers/oembed_parser.ex
index ca7226faf..2530b8c9d 100644
--- a/lib/pleroma/web/rich_media/parsers/oembed_parser.ex
+++ b/lib/pleroma/web/rich_media/parsers/oembed_parser.ex
@@ -20,8 +20,12 @@ defmodule Pleroma.Web.RichMedia.Parsers.OEmbed do
end
defp get_oembed_data(url) do
- {:ok, %Tesla.Env{body: json}} = Pleroma.HTTP.get(url)
+ {:ok, %Tesla.Env{body: json}} = Pleroma.HTTP.get(url, [], adapter: [pool: :media])
- {:ok, Poison.decode!(json)}
+ {:ok, data} = Jason.decode(json)
+
+ data = data |> Map.new(fn {k, v} -> {String.to_atom(k), v} end)
+
+ {:ok, data}
end
end
diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index 31f739738..c6b4d37ab 100644
--- a/lib/pleroma/web/router.ex
+++ b/lib/pleroma/web/router.ex
@@ -185,6 +185,7 @@ defmodule Pleroma.Web.Router do
get("/timelines/direct", MastodonAPIController, :dm_timeline)
get("/favourites", MastodonAPIController, :favourites)
+ get("/bookmarks", MastodonAPIController, :bookmarks)
post("/statuses", MastodonAPIController, :post_status)
delete("/statuses/:id", MastodonAPIController, :delete_status)
@@ -195,6 +196,8 @@ defmodule Pleroma.Web.Router do
post("/statuses/:id/unfavourite", MastodonAPIController, :unfav_status)
post("/statuses/:id/pin", MastodonAPIController, :pin_status)
post("/statuses/:id/unpin", MastodonAPIController, :unpin_status)
+ post("/statuses/:id/bookmark", MastodonAPIController, :bookmark_status)
+ post("/statuses/:id/unbookmark", MastodonAPIController, :unbookmark_status)
post("/notifications/clear", MastodonAPIController, :clear_notifications)
post("/notifications/dismiss", MastodonAPIController, :dismiss_notification)
@@ -239,12 +242,6 @@ defmodule Pleroma.Web.Router do
put("/settings", MastodonAPIController, :put_settings)
end
- scope "/api", Pleroma.Web.RichMedia do
- pipe_through(:authenticated_api)
-
- get("/rich_media/parse", RichMediaController, :parse)
- end
-
scope "/api/v1", Pleroma.Web.MastodonAPI do
pipe_through(:api)
get("/instance", MastodonAPIController, :masto_instance)
@@ -284,6 +281,7 @@ defmodule Pleroma.Web.Router do
post("/help/test", TwitterAPI.UtilController, :help_test)
get("/statusnet/config", TwitterAPI.UtilController, :config)
get("/statusnet/version", TwitterAPI.UtilController, :version)
+ get("/pleroma/frontend_configurations", TwitterAPI.UtilController, :frontend_configurations)
end
scope "/api", Pleroma.Web do
diff --git a/lib/pleroma/web/salmon/salmon.ex b/lib/pleroma/web/salmon/salmon.ex
index e41657da1..07ca42a5f 100644
--- a/lib/pleroma/web/salmon/salmon.ex
+++ b/lib/pleroma/web/salmon/salmon.ex
@@ -6,6 +6,7 @@ defmodule Pleroma.Web.Salmon do
@httpoison Application.get_env(:pleroma, :httpoison)
use Bitwise
+ alias Pleroma.Instances
alias Pleroma.Web.XML
alias Pleroma.Web.OStatus.ActivityRepresenter
alias Pleroma.User
@@ -163,23 +164,28 @@ defmodule Pleroma.Web.Salmon do
# push an activity to remote accounts
#
- defp send_to_user(%{info: %{salmon: salmon}}, feed, poster),
+ def send_to_user(%{info: %{salmon: salmon}}, feed, poster),
do: send_to_user(salmon, feed, poster)
- defp send_to_user(url, feed, poster) when is_binary(url) do
- with {:ok, %{status: code}} <-
+ def send_to_user(url, feed, poster) when is_binary(url) do
+ with {:ok, %{status: code}} when code in 200..299 <-
poster.(
url,
feed,
[{"Content-Type", "application/magic-envelope+xml"}]
) do
+ Instances.set_reachable(url)
Logger.debug(fn -> "Pushed to #{url}, code #{code}" end)
+ :ok
else
- e -> Logger.debug(fn -> "Pushing Salmon to #{url} failed, #{inspect(e)}" end)
+ e ->
+ Instances.set_unreachable(url)
+ Logger.debug(fn -> "Pushing Salmon to #{url} failed, #{inspect(e)}" end)
+ :error
end
end
- defp send_to_user(_, _, _), do: nil
+ def send_to_user(_, _, _), do: :noop
@supported_activities [
"Create",
@@ -209,12 +215,16 @@ defmodule Pleroma.Web.Salmon do
{:ok, private, _} = keys_from_pem(keys)
{:ok, feed} = encode(private, feed)
- remote_users(activity)
+ remote_users = remote_users(activity)
+
+ salmon_urls = Enum.map(remote_users, & &1.info.salmon)
+ reachable_salmon_urls = Instances.filter_reachable(salmon_urls)
+
+ remote_users
+ |> Enum.filter(&(&1.info.salmon in reachable_salmon_urls))
|> Enum.each(fn remote_user ->
- Task.start(fn ->
- Logger.debug(fn -> "Sending Salmon to #{remote_user.ap_id}" end)
- send_to_user(remote_user, feed, poster)
- end)
+ Logger.debug(fn -> "Sending Salmon to #{remote_user.ap_id}" end)
+ Pleroma.Web.Federator.enqueue(:publish_single_salmon, {remote_user, feed, poster})
end)
end
end
diff --git a/lib/pleroma/web/templates/mastodon_api/mastodon/index.html.eex b/lib/pleroma/web/templates/mastodon_api/mastodon/index.html.eex
index 0862412ea..9a725e420 100644
--- a/lib/pleroma/web/templates/mastodon_api/mastodon/index.html.eex
+++ b/lib/pleroma/web/templates/mastodon_api/mastodon/index.html.eex
@@ -1,23 +1,28 @@
<!DOCTYPE html>
<html lang='en'>
<head>
+<meta charset='utf-8'>
+<meta content='width=device-width, initial-scale=1' name='viewport'>
<title>
<%= Application.get_env(:pleroma, :instance)[:name] %>
</title>
-<meta charset='utf-8'>
-<meta content='width=device-width, initial-scale=1' name='viewport'>
<link rel="icon" type="image/png" href="/favicon.png"/>
-<link rel="stylesheet" media="all" href="/packs/common.css" />
-<link rel="stylesheet" media="all" href="/packs/default.css" />
+<script crossorigin='anonymous' src="/packs/locales.js"></script>
+<script crossorigin='anonymous' src="/packs/locales/glitch/en.js"></script>
-<script src="/packs/common.js"></script>
-<script src="/packs/locale_en.js"></script>
-<link as='script' crossorigin='anonymous' href='/packs/features/getting_started.js' rel='preload'>
-<link as='script' crossorigin='anonymous' href='/packs/features/compose.js' rel='preload'>
-<link as='script' crossorigin='anonymous' href='/packs/features/home_timeline.js' rel='preload'>
-<link as='script' crossorigin='anonymous' href='/packs/features/notifications.js' rel='preload'>
+<link rel='preload' as='script' crossorigin='anonymous' href='/packs/features/getting_started.js'>
+<link rel='preload' as='script' crossorigin='anonymous' href='/packs/features/compose.js'>
+<link rel='preload' as='script' crossorigin='anonymous' href='/packs/features/home_timeline.js'>
+<link rel='preload' as='script' crossorigin='anonymous' href='/packs/features/notifications.js'>
<script id='initial-state' type='application/json'><%= raw @initial_state %></script>
-<script src="/packs/application.js"></script>
+
+<script src="/packs/core/common.js"></script>
+<link rel="stylesheet" media="all" href="/packs/core/common.css" />
+
+<script src="/packs/flavours/glitch/common.js"></script>
+<link rel="stylesheet" media="all" href="/packs/flavours/glitch/common.css" />
+
+<script src="/packs/flavours/glitch/home.js"></script>
</head>
<body class='app-body no-reduce-motion system-font'>
<div class='app-holder' data-props='{&quot;locale&quot;:&quot;en&quot;}' id='mastodon'>
diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex
index a79072f3d..b347faa71 100644
--- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex
+++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex
@@ -183,25 +183,31 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
invitesEnabled: if(Keyword.get(instance, :invites_enabled, false), do: "1", else: "0")
}
- pleroma_fe = %{
- theme: Keyword.get(instance_fe, :theme),
- background: Keyword.get(instance_fe, :background),
- logo: Keyword.get(instance_fe, :logo),
- logoMask: Keyword.get(instance_fe, :logo_mask),
- logoMargin: Keyword.get(instance_fe, :logo_margin),
- redirectRootNoLogin: Keyword.get(instance_fe, :redirect_root_no_login),
- redirectRootLogin: Keyword.get(instance_fe, :redirect_root_login),
- chatDisabled: !Keyword.get(instance_chat, :enabled),
- showInstanceSpecificPanel: Keyword.get(instance_fe, :show_instance_panel),
- scopeOptionsEnabled: Keyword.get(instance_fe, :scope_options_enabled),
- formattingOptionsEnabled: Keyword.get(instance_fe, :formatting_options_enabled),
- collapseMessageWithSubject: Keyword.get(instance_fe, :collapse_message_with_subject),
- hidePostStats: Keyword.get(instance_fe, :hide_post_stats),
- hideUserStats: Keyword.get(instance_fe, :hide_user_stats),
- scopeCopy: Keyword.get(instance_fe, :scope_copy),
- subjectLineBehavior: Keyword.get(instance_fe, :subject_line_behavior),
- alwaysShowSubjectInput: Keyword.get(instance_fe, :always_show_subject_input)
- }
+ pleroma_fe =
+ if instance_fe do
+ %{
+ theme: Keyword.get(instance_fe, :theme),
+ background: Keyword.get(instance_fe, :background),
+ logo: Keyword.get(instance_fe, :logo),
+ logoMask: Keyword.get(instance_fe, :logo_mask),
+ logoMargin: Keyword.get(instance_fe, :logo_margin),
+ redirectRootNoLogin: Keyword.get(instance_fe, :redirect_root_no_login),
+ redirectRootLogin: Keyword.get(instance_fe, :redirect_root_login),
+ chatDisabled: !Keyword.get(instance_chat, :enabled),
+ showInstanceSpecificPanel: Keyword.get(instance_fe, :show_instance_panel),
+ scopeOptionsEnabled: Keyword.get(instance_fe, :scope_options_enabled),
+ formattingOptionsEnabled: Keyword.get(instance_fe, :formatting_options_enabled),
+ collapseMessageWithSubject:
+ Keyword.get(instance_fe, :collapse_message_with_subject),
+ hidePostStats: Keyword.get(instance_fe, :hide_post_stats),
+ hideUserStats: Keyword.get(instance_fe, :hide_user_stats),
+ scopeCopy: Keyword.get(instance_fe, :scope_copy),
+ subjectLineBehavior: Keyword.get(instance_fe, :subject_line_behavior),
+ alwaysShowSubjectInput: Keyword.get(instance_fe, :always_show_subject_input)
+ }
+ else
+ Pleroma.Config.get([:frontend_configurations, :pleroma_fe])
+ end
managed_config = Keyword.get(instance, :managed_config)
@@ -216,6 +222,14 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
end
end
+ def frontend_configurations(conn, _params) do
+ config =
+ Pleroma.Config.get(:frontend_configurations, %{})
+ |> Enum.into(%{})
+
+ json(conn, config)
+ end
+
def version(conn, _params) do
version = Pleroma.Application.named_version()
diff --git a/lib/pleroma/web/twitter_api/representers/activity_representer.ex b/lib/pleroma/web/twitter_api/representers/activity_representer.ex
index 19b723586..c4025cbd7 100644
--- a/lib/pleroma/web/twitter_api/representers/activity_representer.ex
+++ b/lib/pleroma/web/twitter_api/representers/activity_representer.ex
@@ -12,6 +12,7 @@ defmodule Pleroma.Web.TwitterAPI.Representers.ActivityRepresenter do
alias Pleroma.Web.CommonAPI.Utils
alias Pleroma.Formatter
alias Pleroma.HTML
+ alias Pleroma.Web.MastodonAPI.StatusView
defp user_by_ap_id(user_list, ap_id) do
Enum.find(user_list, fn %{ap_id: user_id} -> ap_id == user_id end)
@@ -186,6 +187,12 @@ defmodule Pleroma.Web.TwitterAPI.Representers.ActivityRepresenter do
summary = HTML.strip_tags(object["summary"])
+ card =
+ StatusView.render(
+ "card.json",
+ Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity)
+ )
+
%{
"id" => activity.id,
"uri" => activity.data["object"]["id"],
@@ -214,7 +221,8 @@ defmodule Pleroma.Web.TwitterAPI.Representers.ActivityRepresenter do
"possibly_sensitive" => possibly_sensitive,
"visibility" => Pleroma.Web.MastodonAPI.StatusView.get_visibility(object),
"summary" => summary,
- "summary_html" => summary |> Formatter.emojify(object["emoji"])
+ "summary_html" => summary |> Formatter.emojify(object["emoji"]),
+ "card" => card
}
end
diff --git a/lib/pleroma/web/twitter_api/views/activity_view.ex b/lib/pleroma/web/twitter_api/views/activity_view.ex
index a01ee0010..d0d1221c3 100644
--- a/lib/pleroma/web/twitter_api/views/activity_view.ex
+++ b/lib/pleroma/web/twitter_api/views/activity_view.ex
@@ -10,6 +10,7 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do
alias Pleroma.Web.TwitterAPI.ActivityView
alias Pleroma.Web.TwitterAPI.TwitterAPI
alias Pleroma.Web.TwitterAPI.Representers.ObjectRepresenter
+ alias Pleroma.Web.MastodonAPI.StatusView
alias Pleroma.Activity
alias Pleroma.HTML
alias Pleroma.Object
@@ -274,6 +275,12 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do
summary = HTML.strip_tags(summary)
+ card =
+ StatusView.render(
+ "card.json",
+ Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity)
+ )
+
%{
"id" => activity.id,
"uri" => activity.data["object"]["id"],
@@ -300,9 +307,10 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do
"tags" => tags,
"activity_type" => "post",
"possibly_sensitive" => possibly_sensitive,
- "visibility" => Pleroma.Web.MastodonAPI.StatusView.get_visibility(object),
+ "visibility" => StatusView.get_visibility(object),
"summary" => summary,
- "summary_html" => summary |> Formatter.emojify(object["emoji"])
+ "summary_html" => summary |> Formatter.emojify(object["emoji"]),
+ "card" => card
}
end
diff --git a/lib/pleroma/web/websub/websub.ex b/lib/pleroma/web/websub/websub.ex
index 7ca62c83b..8f7d53b03 100644
--- a/lib/pleroma/web/websub/websub.ex
+++ b/lib/pleroma/web/websub/websub.ex
@@ -5,6 +5,7 @@
defmodule Pleroma.Web.Websub do
alias Ecto.Changeset
alias Pleroma.Repo
+ alias Pleroma.Instances
alias Pleroma.Web.Websub.{WebsubServerSubscription, WebsubClientSubscription}
alias Pleroma.Web.OStatus.FeedRepresenter
alias Pleroma.Web.{XML, Endpoint, OStatus}
@@ -53,23 +54,27 @@ defmodule Pleroma.Web.Websub do
]
def publish(topic, user, %{data: %{"type" => type}} = activity)
when type in @supported_activities do
- # TODO: Only send to still valid subscriptions.
+ response =
+ user
+ |> FeedRepresenter.to_simple_form([activity], [user])
+ |> :xmerl.export_simple(:xmerl_xml)
+ |> to_string
+
query =
from(
sub in WebsubServerSubscription,
where: sub.topic == ^topic and sub.state == "active",
- where: fragment("? > NOW()", sub.valid_until)
+ where: fragment("? > (NOW() at time zone 'UTC')", sub.valid_until)
)
subscriptions = Repo.all(query)
- Enum.each(subscriptions, fn sub ->
- response =
- user
- |> FeedRepresenter.to_simple_form([activity], [user])
- |> :xmerl.export_simple(:xmerl_xml)
- |> to_string
+ callbacks = Enum.map(subscriptions, & &1.callback)
+ reachable_callbacks = Instances.filter_reachable(callbacks)
+ subscriptions
+ |> Enum.filter(&(&1.callback in reachable_callbacks))
+ |> Enum.each(fn sub ->
data = %{
xml: response,
topic: topic,
@@ -267,7 +272,7 @@ defmodule Pleroma.Web.Websub do
signature = sign(secret || "", xml)
Logger.info(fn -> "Pushing #{topic} to #{callback}" end)
- with {:ok, %{status: code}} <-
+ with {:ok, %{status: code}} when code in 200..299 <-
@httpoison.post(
callback,
xml,
@@ -276,12 +281,14 @@ defmodule Pleroma.Web.Websub do
{"X-Hub-Signature", "sha1=#{signature}"}
]
) do
+ Instances.set_reachable(callback)
Logger.info(fn -> "Pushed to #{callback}, code #{code}" end)
{:ok, code}
else
- e ->
- Logger.debug(fn -> "Couldn't push to #{callback}, #{inspect(e)}" end)
- {:error, e}
+ {_post_result, response} ->
+ Instances.set_unreachable(callback)
+ Logger.debug(fn -> "Couldn't push to #{callback}, #{inspect(response)}" end)
+ {:error, response}
end
end
end
diff --git a/lib/pleroma/web/websub/websub_controller.ex b/lib/pleroma/web/websub/websub_controller.ex
index e58f144e5..a92dfe87b 100644
--- a/lib/pleroma/web/websub/websub_controller.ex
+++ b/lib/pleroma/web/websub/websub_controller.ex
@@ -4,9 +4,11 @@
defmodule Pleroma.Web.Websub.WebsubController do
use Pleroma.Web, :controller
+
alias Pleroma.{Repo, User}
alias Pleroma.Web.{Websub, Federator}
alias Pleroma.Web.Websub.WebsubClientSubscription
+
require Logger
plug(