forked from AkkomaGang/akkoma
Merge branch 'develop' into kaniini/pleroma-bugfix/unlisted-statuses
This commit is contained in:
commit
76722ea9c8
59 changed files with 472 additions and 194 deletions
|
@ -26,3 +26,12 @@
|
||||||
config :pleroma, :websub, Pleroma.Web.WebsubMock
|
config :pleroma, :websub, Pleroma.Web.WebsubMock
|
||||||
config :pleroma, :ostatus, Pleroma.Web.OStatusMock
|
config :pleroma, :ostatus, Pleroma.Web.OStatusMock
|
||||||
config :pleroma, :httpoison, HTTPoisonMock
|
config :pleroma, :httpoison, HTTPoisonMock
|
||||||
|
|
||||||
|
try do
|
||||||
|
import_config "test.secret.exs"
|
||||||
|
rescue
|
||||||
|
_ ->
|
||||||
|
IO.puts(
|
||||||
|
"You may want to create test.secret.exs to declare custom database connection parameters."
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
|
@ -59,6 +59,16 @@ server {
|
||||||
}
|
}
|
||||||
# stop removing lines here.
|
# stop removing lines here.
|
||||||
|
|
||||||
|
add_header X-XSS-Protection "1; mode=block";
|
||||||
|
add_header X-Permitted-Cross-Domain-Policies none;
|
||||||
|
add_header X-Frame-Options DENY;
|
||||||
|
add_header X-Content-Type-Options nosniff;
|
||||||
|
add_header Referrer-Policy same-origin;
|
||||||
|
add_header X-Download-Options noopen;
|
||||||
|
|
||||||
|
# Uncomment this only after you get HTTPS working.
|
||||||
|
# add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";
|
||||||
|
|
||||||
proxy_http_version 1.1;
|
proxy_http_version 1.1;
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
proxy_set_header Connection "upgrade";
|
proxy_set_header Connection "upgrade";
|
||||||
|
|
|
@ -13,4 +13,3 @@ Restart=on-failure
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=multi-user.target
|
WantedBy=multi-user.target
|
||||||
Alias=pleroma.service
|
|
||||||
|
|
|
@ -39,15 +39,9 @@ sub vcl_recv {
|
||||||
return (hash);
|
return (hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
# Hack to enable a Terms of Service page missing from Pleroma
|
|
||||||
if (req.url ~ "^/about/more$") {
|
|
||||||
set req.http.x-redir = "https://" + req.http.host + "/static/terms-of-service.html";
|
|
||||||
return (synth(750, ""));
|
|
||||||
}
|
|
||||||
|
|
||||||
# Strip headers that will affect caching from all other static content
|
# Strip headers that will affect caching from all other static content
|
||||||
# This also permits caching of individual toots and AP Activities
|
# This also permits caching of individual toots and AP Activities
|
||||||
if ((req.url ~ "^/(media|notice|objects|static)/") ||
|
if ((req.url ~ "^/(media|static)/") ||
|
||||||
(req.url ~ "(?i)\.(html|js|css|jpg|jpeg|png|gif|gz|tgz|bz2|tbz|mp3|ogg|svg|swf|ttf|pdf|woff|woff2)$"))
|
(req.url ~ "(?i)\.(html|js|css|jpg|jpeg|png|gif|gz|tgz|bz2|tbz|mp3|ogg|svg|swf|ttf|pdf|woff|woff2)$"))
|
||||||
{
|
{
|
||||||
unset req.http.Cookie;
|
unset req.http.Cookie;
|
||||||
|
@ -99,8 +93,7 @@ sub vcl_backend_response {
|
||||||
|
|
||||||
# Strip cache-restricting headers from Pleroma on static content that we want to cache
|
# Strip cache-restricting headers from Pleroma on static content that we want to cache
|
||||||
# Also enable streaming of cached content to clients (no waiting for Varnish to complete backend fetch)
|
# Also enable streaming of cached content to clients (no waiting for Varnish to complete backend fetch)
|
||||||
if ((bereq.url ~ "^/(notice|objects)/") ||
|
if (bereq.url ~ "(?i)\.(js|css|jpg|jpeg|png|gif|gz|tgz|bz2|tbz|mp3|ogg|svg|swf|ttf|pdf|woff|woff2)$")
|
||||||
(bereq.url ~ "(?i)\.(js|css|jpg|jpeg|png|gif|gz|tgz|bz2|tbz|mp3|ogg|svg|swf|ttf|pdf|woff|woff2)$"))
|
|
||||||
{
|
{
|
||||||
unset beresp.http.set-cookie;
|
unset beresp.http.set-cookie;
|
||||||
unset beresp.http.Cache-Control;
|
unset beresp.http.Cache-Control;
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
defmodule Mix.Tasks.FixApUsers do
|
defmodule Mix.Tasks.FixApUsers do
|
||||||
use Mix.Task
|
use Mix.Task
|
||||||
import Mix.Ecto
|
|
||||||
import Ecto.Query
|
import Ecto.Query
|
||||||
alias Pleroma.{Repo, User}
|
alias Pleroma.{Repo, User}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
defmodule Mix.Tasks.GeneratePasswordReset do
|
defmodule Mix.Tasks.GeneratePasswordReset do
|
||||||
use Mix.Task
|
use Mix.Task
|
||||||
import Mix.Ecto
|
alias Pleroma.User
|
||||||
alias Pleroma.{Repo, User}
|
|
||||||
|
|
||||||
@shortdoc "Generate password reset link for user"
|
@shortdoc "Generate password reset link for user"
|
||||||
def run([nickname]) do
|
def run([nickname]) do
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
defmodule Mix.Tasks.RegisterUser do
|
defmodule Mix.Tasks.RegisterUser do
|
||||||
use Mix.Task
|
use Mix.Task
|
||||||
import Mix.Ecto
|
|
||||||
alias Pleroma.{Repo, User}
|
alias Pleroma.{Repo, User}
|
||||||
|
|
||||||
@shortdoc "Register user"
|
@shortdoc "Register user"
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
defmodule Mix.Tasks.RmUser do
|
defmodule Mix.Tasks.RmUser do
|
||||||
use Mix.Task
|
use Mix.Task
|
||||||
import Mix.Ecto
|
alias Pleroma.User
|
||||||
alias Pleroma.{User, Repo}
|
|
||||||
|
|
||||||
@shortdoc "Permanently delete a user"
|
@shortdoc "Permanently delete a user"
|
||||||
def run([nickname]) do
|
def run([nickname]) do
|
||||||
|
|
|
@ -23,6 +23,18 @@ def start(_type, _args) do
|
||||||
limit: 2500
|
limit: 2500
|
||||||
]
|
]
|
||||||
]),
|
]),
|
||||||
|
worker(
|
||||||
|
Cachex,
|
||||||
|
[
|
||||||
|
:idempotency_cache,
|
||||||
|
[
|
||||||
|
default_ttl: :timer.seconds(6 * 60 * 60),
|
||||||
|
ttl_interval: :timer.seconds(60),
|
||||||
|
limit: 2500
|
||||||
|
]
|
||||||
|
],
|
||||||
|
id: :cachex_idem
|
||||||
|
),
|
||||||
worker(Pleroma.Web.Federator, []),
|
worker(Pleroma.Web.Federator, []),
|
||||||
worker(Pleroma.Gopher.Server, []),
|
worker(Pleroma.Gopher.Server, []),
|
||||||
worker(Pleroma.Stats, [])
|
worker(Pleroma.Stats, [])
|
||||||
|
|
|
@ -65,12 +65,6 @@ def link(name, selector, type \\ 1) do
|
||||||
"#{type}#{name}\t#{selector}\t#{address}\t#{port}\r\n"
|
"#{type}#{name}\t#{selector}\t#{address}\t#{port}\r\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
def response("") do
|
|
||||||
info("Welcome to #{Keyword.get(@instance, :name, "Pleroma")}!") <>
|
|
||||||
link("Public Timeline", "/main/public") <>
|
|
||||||
link("Federated Timeline", "/main/all") <> ".\r\n"
|
|
||||||
end
|
|
||||||
|
|
||||||
def render_activities(activities) do
|
def render_activities(activities) do
|
||||||
activities
|
activities
|
||||||
|> Enum.reverse()
|
|> Enum.reverse()
|
||||||
|
@ -93,6 +87,12 @@ def render_activities(activities) do
|
||||||
|> Enum.join("\r\n")
|
|> Enum.join("\r\n")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def response("") do
|
||||||
|
info("Welcome to #{Keyword.get(@instance, :name, "Pleroma")}!") <>
|
||||||
|
link("Public Timeline", "/main/public") <>
|
||||||
|
link("Federated Timeline", "/main/all") <> ".\r\n"
|
||||||
|
end
|
||||||
|
|
||||||
def response("/main/public") do
|
def response("/main/public") do
|
||||||
posts =
|
posts =
|
||||||
ActivityPub.fetch_public_activities(%{"type" => ["Create"], "local_only" => true})
|
ActivityPub.fetch_public_activities(%{"type" => ["Create"], "local_only" => true})
|
||||||
|
|
|
@ -91,7 +91,8 @@ def create_notifications(_), do: {:ok, []}
|
||||||
|
|
||||||
# TODO move to sql, too.
|
# TODO move to sql, too.
|
||||||
def create_notification(%Activity{} = activity, %User{} = user) do
|
def create_notification(%Activity{} = activity, %User{} = user) do
|
||||||
unless User.blocks?(user, %{ap_id: activity.data["actor"]}) do
|
unless User.blocks?(user, %{ap_id: activity.data["actor"]}) or
|
||||||
|
user.ap_id == activity.data["actor"] do
|
||||||
notification = %Notification{user_id: user.id, activity: activity}
|
notification = %Notification{user_id: user.id, activity: activity}
|
||||||
{:ok, notification} = Repo.insert(notification)
|
{:ok, notification} = Repo.insert(notification)
|
||||||
Pleroma.Web.Streamer.stream("user", notification)
|
Pleroma.Web.Streamer.stream("user", notification)
|
||||||
|
|
|
@ -7,11 +7,11 @@ def init(options) do
|
||||||
options
|
options
|
||||||
end
|
end
|
||||||
|
|
||||||
def call(%{assigns: %{valid_signature: true}} = conn, opts) do
|
def call(%{assigns: %{valid_signature: true}} = conn, _opts) do
|
||||||
conn
|
conn
|
||||||
end
|
end
|
||||||
|
|
||||||
def call(conn, opts) do
|
def call(conn, _opts) do
|
||||||
user = conn.params["actor"]
|
user = conn.params["actor"]
|
||||||
Logger.debug("Checking sig for #{user}")
|
Logger.debug("Checking sig for #{user}")
|
||||||
[signature | _] = get_req_header(conn, "signature")
|
[signature | _] = get_req_header(conn, "signature")
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
defmodule Pleroma.Stats do
|
defmodule Pleroma.Stats do
|
||||||
import Ecto.Query
|
import Ecto.Query
|
||||||
alias Pleroma.{User, Repo, Activity}
|
alias Pleroma.{User, Repo}
|
||||||
|
|
||||||
def start_link do
|
def start_link do
|
||||||
agent = Agent.start_link(fn -> {[], %{}} end, name: __MODULE__)
|
agent = Agent.start_link(fn -> {[], %{}} end, name: __MODULE__)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
||||||
alias Pleroma.{Activity, Repo, Object, Upload, User, Notification}
|
alias Pleroma.{Activity, Repo, Object, Upload, User, Notification}
|
||||||
alias Pleroma.Web.ActivityPub.Transmogrifier
|
alias Pleroma.Web.ActivityPub.{Transmogrifier, MRF}
|
||||||
alias Pleroma.Web.WebFinger
|
alias Pleroma.Web.WebFinger
|
||||||
alias Pleroma.Web.Federator
|
alias Pleroma.Web.Federator
|
||||||
alias Pleroma.Web.OStatus
|
alias Pleroma.Web.OStatus
|
||||||
|
@ -11,7 +11,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
||||||
@httpoison Application.get_env(:pleroma, :httpoison)
|
@httpoison Application.get_env(:pleroma, :httpoison)
|
||||||
|
|
||||||
@instance Application.get_env(:pleroma, :instance)
|
@instance Application.get_env(:pleroma, :instance)
|
||||||
@rewrite_policy Keyword.get(@instance, :rewrite_policy)
|
|
||||||
|
|
||||||
def get_recipients(data) do
|
def get_recipients(data) do
|
||||||
(data["to"] || []) ++ (data["cc"] || [])
|
(data["to"] || []) ++ (data["cc"] || [])
|
||||||
|
@ -20,8 +19,8 @@ def get_recipients(data) do
|
||||||
def insert(map, local \\ true) when is_map(map) do
|
def insert(map, local \\ true) when is_map(map) do
|
||||||
with nil <- Activity.get_by_ap_id(map["id"]),
|
with nil <- Activity.get_by_ap_id(map["id"]),
|
||||||
map <- lazy_put_activity_defaults(map),
|
map <- lazy_put_activity_defaults(map),
|
||||||
:ok <- insert_full_object(map),
|
{:ok, map} <- MRF.filter(map),
|
||||||
{:ok, map} <- @rewrite_policy.filter(map) do
|
:ok <- insert_full_object(map) do
|
||||||
{:ok, activity} =
|
{:ok, activity} =
|
||||||
Repo.insert(%Activity{
|
Repo.insert(%Activity{
|
||||||
data: map,
|
data: map,
|
||||||
|
@ -66,7 +65,7 @@ def create(%{to: to, actor: actor, context: context, object: object} = params) d
|
||||||
),
|
),
|
||||||
{:ok, activity} <- insert(create_data, local),
|
{:ok, activity} <- insert(create_data, local),
|
||||||
:ok <- maybe_federate(activity),
|
:ok <- maybe_federate(activity),
|
||||||
{:ok, actor} <- User.increase_note_count(actor) do
|
{:ok, _actor} <- User.increase_note_count(actor) do
|
||||||
{:ok, activity}
|
{:ok, activity}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -177,7 +176,7 @@ def delete(%Object{data: %{"id" => id, "actor" => actor}} = object, local \\ tru
|
||||||
Repo.delete_all(Activity.all_non_create_by_object_ap_id_q(id)),
|
Repo.delete_all(Activity.all_non_create_by_object_ap_id_q(id)),
|
||||||
{:ok, activity} <- insert(data, local),
|
{:ok, activity} <- insert(data, local),
|
||||||
:ok <- maybe_federate(activity),
|
:ok <- maybe_federate(activity),
|
||||||
{:ok, actor} <- User.decrease_note_count(user) do
|
{:ok, _actor} <- User.decrease_note_count(user) do
|
||||||
{:ok, activity}
|
{:ok, activity}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -236,7 +235,7 @@ defp restrict_tag(query, %{"tag" => tag}) do
|
||||||
|
|
||||||
defp restrict_tag(query, _), do: query
|
defp restrict_tag(query, _), do: query
|
||||||
|
|
||||||
defp restrict_recipients(query, [], user), do: query
|
defp restrict_recipients(query, [], _user), do: query
|
||||||
|
|
||||||
defp restrict_recipients(query, recipients, nil) do
|
defp restrict_recipients(query, recipients, nil) do
|
||||||
from(activity in query, where: fragment("? && ?", ^recipients, activity.recipients))
|
from(activity in query, where: fragment("? && ?", ^recipients, activity.recipients))
|
||||||
|
@ -313,7 +312,9 @@ defp restrict_recent(query, _) do
|
||||||
|
|
||||||
defp restrict_blocked(query, %{"blocking_user" => %User{info: info}}) do
|
defp restrict_blocked(query, %{"blocking_user" => %User{info: info}}) do
|
||||||
blocks = info["blocks"] || []
|
blocks = info["blocks"] || []
|
||||||
from(activity in query,
|
|
||||||
|
from(
|
||||||
|
activity in query,
|
||||||
where: fragment("not (? = ANY(?))", activity.actor, ^blocks),
|
where: fragment("not (? = ANY(?))", activity.actor, ^blocks),
|
||||||
where: fragment("not (?->'to' \\?| ?)", activity.data, ^blocks)
|
where: fragment("not (?->'to' \\?| ?)", activity.data, ^blocks)
|
||||||
)
|
)
|
||||||
|
@ -405,7 +406,7 @@ def fetch_and_prepare_user_from_ap_id(ap_id) do
|
||||||
end
|
end
|
||||||
|
|
||||||
def make_user_from_ap_id(ap_id) do
|
def make_user_from_ap_id(ap_id) do
|
||||||
if user = User.get_by_ap_id(ap_id) do
|
if _user = User.get_by_ap_id(ap_id) do
|
||||||
Transmogrifier.upgrade_user_from_ap_id(ap_id)
|
Transmogrifier.upgrade_user_from_ap_id(ap_id)
|
||||||
else
|
else
|
||||||
with {:ok, data} <- fetch_and_prepare_user_from_ap_id(ap_id) do
|
with {:ok, data} <- fetch_and_prepare_user_from_ap_id(ap_id) do
|
||||||
|
@ -501,7 +502,7 @@ def fetch_object_from_id(id) do
|
||||||
object = %Object{} ->
|
object = %Object{} ->
|
||||||
{:ok, object}
|
{:ok, object}
|
||||||
|
|
||||||
e ->
|
_e ->
|
||||||
Logger.info("Couldn't get object via AP, trying out OStatus fetching...")
|
Logger.info("Couldn't get object via AP, trying out OStatus fetching...")
|
||||||
|
|
||||||
case OStatus.fetch_activity_from_url(id) do
|
case OStatus.fetch_activity_from_url(id) do
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
defmodule Pleroma.Web.ActivityPub.ActivityPubController do
|
defmodule Pleroma.Web.ActivityPub.ActivityPubController do
|
||||||
use Pleroma.Web, :controller
|
use Pleroma.Web, :controller
|
||||||
alias Pleroma.{User, Repo, Object, Activity}
|
alias Pleroma.{User, Object}
|
||||||
alias Pleroma.Web.ActivityPub.{ObjectView, UserView, Transmogrifier}
|
alias Pleroma.Web.ActivityPub.{ObjectView, UserView}
|
||||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||||
alias Pleroma.Web.Federator
|
alias Pleroma.Web.Federator
|
||||||
|
|
||||||
|
|
24
lib/pleroma/web/activity_pub/mrf.ex
Normal file
24
lib/pleroma/web/activity_pub/mrf.ex
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
defmodule Pleroma.Web.ActivityPub.MRF do
|
||||||
|
@callback filter(Map.t()) :: {:ok | :reject, Map.t()}
|
||||||
|
|
||||||
|
def filter(object) do
|
||||||
|
get_policies()
|
||||||
|
|> Enum.reduce({:ok, object}, fn
|
||||||
|
policy, {:ok, object} ->
|
||||||
|
policy.filter(object)
|
||||||
|
|
||||||
|
_, error ->
|
||||||
|
error
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_policies() do
|
||||||
|
Application.get_env(:pleroma, :instance, [])
|
||||||
|
|> Keyword.get(:rewrite_policy, [])
|
||||||
|
|> get_policies()
|
||||||
|
end
|
||||||
|
|
||||||
|
defp get_policies(policy) when is_atom(policy), do: [policy]
|
||||||
|
defp get_policies(policies) when is_list(policies), do: policies
|
||||||
|
defp get_policies(_), do: []
|
||||||
|
end
|
|
@ -1,6 +1,8 @@
|
||||||
defmodule Pleroma.Web.ActivityPub.MRF.DropPolicy do
|
defmodule Pleroma.Web.ActivityPub.MRF.DropPolicy do
|
||||||
require Logger
|
require Logger
|
||||||
|
@behaviour Pleroma.Web.ActivityPub.MRF
|
||||||
|
|
||||||
|
@impl true
|
||||||
def filter(object) do
|
def filter(object) do
|
||||||
Logger.info("REJECTING #{inspect(object)}")
|
Logger.info("REJECTING #{inspect(object)}")
|
||||||
{:reject, object}
|
{:reject, object}
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
defmodule Pleroma.Web.ActivityPub.MRF.NoOpPolicy do
|
defmodule Pleroma.Web.ActivityPub.MRF.NoOpPolicy do
|
||||||
|
@behaviour Pleroma.Web.ActivityPub.MRF
|
||||||
|
|
||||||
|
@impl true
|
||||||
def filter(object) do
|
def filter(object) do
|
||||||
{:ok, object}
|
{:ok, object}
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
|
defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
|
@behaviour Pleroma.Web.ActivityPub.MRF
|
||||||
|
|
||||||
@mrf_policy Application.get_env(:pleroma, :mrf_simple)
|
@mrf_policy Application.get_env(:pleroma, :mrf_simple)
|
||||||
|
|
||||||
|
@ -17,9 +18,10 @@ defp check_media_removal(actor_info, object) do
|
||||||
if actor_info.host in @media_removal do
|
if actor_info.host in @media_removal do
|
||||||
child_object = Map.delete(object["object"], "attachment")
|
child_object = Map.delete(object["object"], "attachment")
|
||||||
object = Map.put(object, "object", child_object)
|
object = Map.put(object, "object", child_object)
|
||||||
|
{:ok, object}
|
||||||
|
else
|
||||||
|
{:ok, object}
|
||||||
end
|
end
|
||||||
|
|
||||||
{:ok, object}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@media_nsfw Keyword.get(@mrf_policy, :media_nsfw)
|
@media_nsfw Keyword.get(@mrf_policy, :media_nsfw)
|
||||||
|
@ -32,9 +34,10 @@ defp check_media_nsfw(actor_info, object) do
|
||||||
child_object = Map.put(child_object, "tags", tags)
|
child_object = Map.put(child_object, "tags", tags)
|
||||||
child_object = Map.put(child_object, "sensitive", true)
|
child_object = Map.put(child_object, "sensitive", true)
|
||||||
object = Map.put(object, "object", child_object)
|
object = Map.put(object, "object", child_object)
|
||||||
|
{:ok, object}
|
||||||
|
else
|
||||||
|
{:ok, object}
|
||||||
end
|
end
|
||||||
|
|
||||||
{:ok, object}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@ftl_removal Keyword.get(@mrf_policy, :federated_timeline_removal)
|
@ftl_removal Keyword.get(@mrf_policy, :federated_timeline_removal)
|
||||||
|
@ -43,24 +46,31 @@ defp check_ftl_removal(actor_info, object) do
|
||||||
user = User.get_by_ap_id(object["actor"])
|
user = User.get_by_ap_id(object["actor"])
|
||||||
|
|
||||||
# flip to/cc relationship to make the post unlisted
|
# flip to/cc relationship to make the post unlisted
|
||||||
if "https://www.w3.org/ns/activitystreams#Public" in object["to"] and
|
object =
|
||||||
user.follower_address in object["cc"] do
|
if "https://www.w3.org/ns/activitystreams#Public" in object["to"] and
|
||||||
to =
|
user.follower_address in object["cc"] do
|
||||||
List.delete(object["to"], "https://www.w3.org/ns/activitystreams#Public") ++
|
to =
|
||||||
[user.follower_address]
|
List.delete(object["to"], "https://www.w3.org/ns/activitystreams#Public") ++
|
||||||
|
[user.follower_address]
|
||||||
|
|
||||||
cc =
|
cc =
|
||||||
List.delete(object["cc"], user.follower_address) ++
|
List.delete(object["cc"], user.follower_address) ++
|
||||||
["https://www.w3.org/ns/activitystreams#Public"]
|
["https://www.w3.org/ns/activitystreams#Public"]
|
||||||
|
|
||||||
object = Map.put(object, "to", to)
|
object
|
||||||
object = Map.put(object, "cc", cc)
|
|> Map.put("to", to)
|
||||||
end
|
|> Map.put("cc", cc)
|
||||||
|
else
|
||||||
|
object
|
||||||
|
end
|
||||||
|
|
||||||
|
{:ok, object}
|
||||||
|
else
|
||||||
|
{:ok, object}
|
||||||
end
|
end
|
||||||
|
|
||||||
{:ok, object}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
def filter(object) do
|
def filter(object) do
|
||||||
actor_info = URI.parse(object["actor"])
|
actor_info = URI.parse(object["actor"])
|
||||||
|
|
||||||
|
@ -70,7 +80,7 @@ def filter(object) do
|
||||||
{:ok, object} <- check_ftl_removal(actor_info, object) do
|
{:ok, object} <- check_ftl_removal(actor_info, object) do
|
||||||
{:ok, object}
|
{:ok, object}
|
||||||
else
|
else
|
||||||
e -> {:reject, nil}
|
_e -> {:reject, nil}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -72,9 +72,12 @@ def fix_emoji(object) do
|
||||||
|> Enum.reduce(%{}, fn data, mapping ->
|
|> Enum.reduce(%{}, fn data, mapping ->
|
||||||
name = data["name"]
|
name = data["name"]
|
||||||
|
|
||||||
if String.starts_with?(name, ":") do
|
name =
|
||||||
name = name |> String.slice(1..-2)
|
if String.starts_with?(name, ":") do
|
||||||
end
|
name |> String.slice(1..-2)
|
||||||
|
else
|
||||||
|
name
|
||||||
|
end
|
||||||
|
|
||||||
mapping |> Map.put(name, data["icon"]["url"])
|
mapping |> Map.put(name, data["icon"]["url"])
|
||||||
end)
|
end)
|
||||||
|
@ -143,12 +146,12 @@ def handle_incoming(
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_incoming(
|
def handle_incoming(
|
||||||
%{"type" => "Like", "object" => object_id, "actor" => actor, "id" => id} = data
|
%{"type" => "Like", "object" => object_id, "actor" => actor, "id" => id} = _data
|
||||||
) do
|
) do
|
||||||
with %User{} = actor <- User.get_or_fetch_by_ap_id(actor),
|
with %User{} = actor <- User.get_or_fetch_by_ap_id(actor),
|
||||||
{:ok, object} <-
|
{:ok, object} <-
|
||||||
get_obj_helper(object_id) || ActivityPub.fetch_object_from_id(object_id),
|
get_obj_helper(object_id) || ActivityPub.fetch_object_from_id(object_id),
|
||||||
{:ok, activity, object} <- ActivityPub.like(actor, object, id, false) do
|
{:ok, activity, _object} <- ActivityPub.like(actor, object, id, false) do
|
||||||
{:ok, activity}
|
{:ok, activity}
|
||||||
else
|
else
|
||||||
_e -> :error
|
_e -> :error
|
||||||
|
@ -156,12 +159,12 @@ def handle_incoming(
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_incoming(
|
def handle_incoming(
|
||||||
%{"type" => "Announce", "object" => object_id, "actor" => actor, "id" => id} = data
|
%{"type" => "Announce", "object" => object_id, "actor" => actor, "id" => id} = _data
|
||||||
) do
|
) do
|
||||||
with %User{} = actor <- User.get_or_fetch_by_ap_id(actor),
|
with %User{} = actor <- User.get_or_fetch_by_ap_id(actor),
|
||||||
{:ok, object} <-
|
{:ok, object} <-
|
||||||
get_obj_helper(object_id) || ActivityPub.fetch_object_from_id(object_id),
|
get_obj_helper(object_id) || ActivityPub.fetch_object_from_id(object_id),
|
||||||
{:ok, activity, object} <- ActivityPub.announce(actor, object, id, false) do
|
{:ok, activity, _object} <- ActivityPub.announce(actor, object, id, false) do
|
||||||
{:ok, activity}
|
{:ok, activity}
|
||||||
else
|
else
|
||||||
_e -> :error
|
_e -> :error
|
||||||
|
@ -202,7 +205,7 @@ def handle_incoming(
|
||||||
|
|
||||||
# TODO: Make secure.
|
# TODO: Make secure.
|
||||||
def handle_incoming(
|
def handle_incoming(
|
||||||
%{"type" => "Delete", "object" => object_id, "actor" => actor, "id" => id} = data
|
%{"type" => "Delete", "object" => object_id, "actor" => actor, "id" => _id} = _data
|
||||||
) do
|
) do
|
||||||
object_id =
|
object_id =
|
||||||
case object_id do
|
case object_id do
|
||||||
|
@ -210,13 +213,13 @@ def handle_incoming(
|
||||||
id -> id
|
id -> id
|
||||||
end
|
end
|
||||||
|
|
||||||
with %User{} = actor <- User.get_or_fetch_by_ap_id(actor),
|
with %User{} = _actor <- User.get_or_fetch_by_ap_id(actor),
|
||||||
{:ok, object} <-
|
{:ok, object} <-
|
||||||
get_obj_helper(object_id) || ActivityPub.fetch_object_from_id(object_id),
|
get_obj_helper(object_id) || ActivityPub.fetch_object_from_id(object_id),
|
||||||
{:ok, activity} <- ActivityPub.delete(object, false) do
|
{:ok, activity} <- ActivityPub.delete(object, false) do
|
||||||
{:ok, activity}
|
{:ok, activity}
|
||||||
else
|
else
|
||||||
e -> :error
|
_e -> :error
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -254,10 +257,10 @@ def prepare_object(object) do
|
||||||
|> set_reply_to_uri
|
|> set_reply_to_uri
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc
|
# @doc
|
||||||
"""
|
# """
|
||||||
internal -> Mastodon
|
# internal -> Mastodon
|
||||||
"""
|
# """
|
||||||
|
|
||||||
def prepare_outgoing(%{"type" => "Create", "object" => %{"type" => "Note"} = object} = data) do
|
def prepare_outgoing(%{"type" => "Create", "object" => %{"type" => "Note"} = object} = data) do
|
||||||
object =
|
object =
|
||||||
|
@ -272,7 +275,7 @@ def prepare_outgoing(%{"type" => "Create", "object" => %{"type" => "Note"} = obj
|
||||||
{:ok, data}
|
{:ok, data}
|
||||||
end
|
end
|
||||||
|
|
||||||
def prepare_outgoing(%{"type" => type} = data) do
|
def prepare_outgoing(%{"type" => _type} = data) do
|
||||||
data =
|
data =
|
||||||
data
|
data
|
||||||
|> maybe_fix_object_url
|
|> maybe_fix_object_url
|
||||||
|
@ -286,7 +289,7 @@ def maybe_fix_object_url(data) do
|
||||||
case ActivityPub.fetch_object_from_id(data["object"]) do
|
case ActivityPub.fetch_object_from_id(data["object"]) do
|
||||||
{:ok, relative_object} ->
|
{:ok, relative_object} ->
|
||||||
if relative_object.data["external_url"] do
|
if relative_object.data["external_url"] do
|
||||||
data =
|
_data =
|
||||||
data
|
data
|
||||||
|> Map.put("object", relative_object.data["external_url"])
|
|> Map.put("object", relative_object.data["external_url"])
|
||||||
else
|
else
|
||||||
|
|
|
@ -47,25 +47,6 @@ def render("user.json", %{user: user}) do
|
||||||
|> Map.merge(Utils.make_json_ld_header())
|
|> Map.merge(Utils.make_json_ld_header())
|
||||||
end
|
end
|
||||||
|
|
||||||
def collection(collection, iri, page, total \\ nil) do
|
|
||||||
offset = (page - 1) * 10
|
|
||||||
items = Enum.slice(collection, offset, 10)
|
|
||||||
items = Enum.map(items, fn user -> user.ap_id end)
|
|
||||||
total = total || length(collection)
|
|
||||||
|
|
||||||
map = %{
|
|
||||||
"id" => "#{iri}?page=#{page}",
|
|
||||||
"type" => "OrderedCollectionPage",
|
|
||||||
"partOf" => iri,
|
|
||||||
"totalItems" => length(collection),
|
|
||||||
"orderedItems" => items
|
|
||||||
}
|
|
||||||
|
|
||||||
if offset < length(collection) do
|
|
||||||
Map.put(map, "next", "#{iri}?page=#{page + 1}")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def render("following.json", %{user: user, page: page}) do
|
def render("following.json", %{user: user, page: page}) do
|
||||||
query = User.get_friends_query(user)
|
query = User.get_friends_query(user)
|
||||||
query = from(user in query, select: [:ap_id])
|
query = from(user in query, select: [:ap_id])
|
||||||
|
@ -123,9 +104,12 @@ def render("outbox.json", %{user: user, max_id: max_qid}) do
|
||||||
"limit" => "10"
|
"limit" => "10"
|
||||||
}
|
}
|
||||||
|
|
||||||
if max_qid != nil do
|
params =
|
||||||
params = Map.put(params, "max_id", max_qid)
|
if max_qid != nil do
|
||||||
end
|
Map.put(params, "max_id", max_qid)
|
||||||
|
else
|
||||||
|
params
|
||||||
|
end
|
||||||
|
|
||||||
activities = ActivityPub.fetch_public_activities(params)
|
activities = ActivityPub.fetch_public_activities(params)
|
||||||
min_id = Enum.at(activities, 0).id
|
min_id = Enum.at(activities, 0).id
|
||||||
|
@ -162,4 +146,23 @@ def render("outbox.json", %{user: user, max_id: max_qid}) do
|
||||||
page |> Map.merge(Utils.make_json_ld_header())
|
page |> Map.merge(Utils.make_json_ld_header())
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def collection(collection, iri, page, total \\ nil) do
|
||||||
|
offset = (page - 1) * 10
|
||||||
|
items = Enum.slice(collection, offset, 10)
|
||||||
|
items = Enum.map(items, fn user -> user.ap_id end)
|
||||||
|
total = total || length(collection)
|
||||||
|
|
||||||
|
map = %{
|
||||||
|
"id" => "#{iri}?page=#{page}",
|
||||||
|
"type" => "OrderedCollectionPage",
|
||||||
|
"partOf" => iri,
|
||||||
|
"totalItems" => total,
|
||||||
|
"orderedItems" => items
|
||||||
|
}
|
||||||
|
|
||||||
|
if offset < total do
|
||||||
|
Map.put(map, "next", "#{iri}?page=#{page + 1}")
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
defmodule Pleroma.Web.UserSocket do
|
defmodule Pleroma.Web.UserSocket do
|
||||||
use Phoenix.Socket
|
use Phoenix.Socket
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
alias Comeonin.Pbkdf2
|
|
||||||
|
|
||||||
## Channels
|
## Channels
|
||||||
# channel "room:*", Pleroma.Web.RoomChannel
|
# channel "room:*", Pleroma.Web.RoomChannel
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
defmodule Pleroma.Web.CommonAPI do
|
defmodule Pleroma.Web.CommonAPI do
|
||||||
alias Pleroma.{Repo, Activity, Object, User}
|
alias Pleroma.{Repo, Activity, Object}
|
||||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||||
alias Pleroma.Formatter
|
alias Pleroma.Formatter
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
defmodule Pleroma.Web.CommonAPI.Utils do
|
defmodule Pleroma.Web.CommonAPI.Utils do
|
||||||
alias Pleroma.{Repo, Object, Formatter, User, Activity}
|
alias Pleroma.{Repo, Object, Formatter, Activity}
|
||||||
alias Pleroma.Web.ActivityPub.Utils
|
alias Pleroma.Web.ActivityPub.Utils
|
||||||
alias Calendar.Strftime
|
alias Calendar.Strftime
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ def to_for_user_and_mentions(user, mentions, inReplyTo, "private") do
|
||||||
{[user.follower_address | to], cc}
|
{[user.follower_address | to], cc}
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_for_user_and_mentions(user, mentions, inReplyTo, "direct") do
|
def to_for_user_and_mentions(_user, mentions, inReplyTo, "direct") do
|
||||||
mentioned_users = Enum.map(mentions, fn {_, %{ap_id: ap_id}} -> ap_id end)
|
mentioned_users = Enum.map(mentions, fn {_, %{ap_id: ap_id}} -> ap_id end)
|
||||||
|
|
||||||
if inReplyTo do
|
if inReplyTo do
|
||||||
|
@ -69,7 +69,7 @@ def make_content_html(status, mentions, attachments, tags, no_attachment_links \
|
||||||
def make_context(%Activity{data: %{"context" => context}}), do: context
|
def make_context(%Activity{data: %{"context" => context}}), do: context
|
||||||
def make_context(_), do: Utils.generate_context_id()
|
def make_context(_), do: Utils.generate_context_id()
|
||||||
|
|
||||||
def maybe_add_attachments(text, attachments, _no_links = true), do: text
|
def maybe_add_attachments(text, _attachments, _no_links = true), do: text
|
||||||
|
|
||||||
def maybe_add_attachments(text, attachments, _no_links) do
|
def maybe_add_attachments(text, attachments, _no_links) do
|
||||||
add_attachments(text, attachments)
|
add_attachments(text, attachments)
|
||||||
|
|
|
@ -14,6 +14,10 @@ defmodule Pleroma.Web.Federator do
|
||||||
@federating Keyword.get(@instance, :federating)
|
@federating Keyword.get(@instance, :federating)
|
||||||
@max_jobs 20
|
@max_jobs 20
|
||||||
|
|
||||||
|
def init(args) do
|
||||||
|
{:ok, args}
|
||||||
|
end
|
||||||
|
|
||||||
def start_link do
|
def start_link do
|
||||||
spawn(fn ->
|
spawn(fn ->
|
||||||
# 1 minute
|
# 1 minute
|
||||||
|
@ -89,12 +93,12 @@ def handle(:incoming_ap_doc, params) do
|
||||||
|
|
||||||
with {:ok, _user} <- ap_enabled_actor(params["actor"]),
|
with {:ok, _user} <- ap_enabled_actor(params["actor"]),
|
||||||
nil <- Activity.get_by_ap_id(params["id"]),
|
nil <- Activity.get_by_ap_id(params["id"]),
|
||||||
{:ok, activity} <- Transmogrifier.handle_incoming(params) do
|
{:ok, _activity} <- Transmogrifier.handle_incoming(params) do
|
||||||
else
|
else
|
||||||
%Activity{} ->
|
%Activity{} ->
|
||||||
Logger.info("Already had #{params["id"]}")
|
Logger.info("Already had #{params["id"]}")
|
||||||
|
|
||||||
e ->
|
_e ->
|
||||||
# Just drop those for now
|
# Just drop those for now
|
||||||
Logger.info("Unhandled activity")
|
Logger.info("Unhandled activity")
|
||||||
Logger.info(Poison.encode!(params, pretty: 2))
|
Logger.info(Poison.encode!(params, pretty: 2))
|
||||||
|
@ -154,7 +158,7 @@ def maybe_start_job(running_jobs, queue) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_cast({:enqueue, type, payload, priority}, state)
|
def handle_cast({:enqueue, type, payload, _priority}, state)
|
||||||
when type in [:incoming_doc, :incoming_ap_doc] do
|
when type in [:incoming_doc, :incoming_ap_doc] do
|
||||||
%{in: {i_running_jobs, i_queue}, out: {o_running_jobs, o_queue}} = state
|
%{in: {i_running_jobs, i_queue}, out: {o_running_jobs, o_queue}} = state
|
||||||
i_queue = enqueue_sorted(i_queue, {type, payload}, 1)
|
i_queue = enqueue_sorted(i_queue, {type, payload}, 1)
|
||||||
|
@ -162,7 +166,7 @@ def handle_cast({:enqueue, type, payload, priority}, state)
|
||||||
{:noreply, %{in: {i_running_jobs, i_queue}, out: {o_running_jobs, o_queue}}}
|
{:noreply, %{in: {i_running_jobs, i_queue}, out: {o_running_jobs, o_queue}}}
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_cast({:enqueue, type, payload, priority}, state) do
|
def handle_cast({:enqueue, type, payload, _priority}, state) do
|
||||||
%{in: {i_running_jobs, i_queue}, out: {o_running_jobs, o_queue}} = state
|
%{in: {i_running_jobs, i_queue}, out: {o_running_jobs, o_queue}} = state
|
||||||
o_queue = enqueue_sorted(o_queue, {type, payload}, 1)
|
o_queue = enqueue_sorted(o_queue, {type, payload}, 1)
|
||||||
{o_running_jobs, o_queue} = maybe_start_job(o_running_jobs, o_queue)
|
{o_running_jobs, o_queue} = maybe_start_job(o_running_jobs, o_queue)
|
||||||
|
|
|
@ -45,7 +45,7 @@ def validate_conn(conn) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
e ->
|
_e ->
|
||||||
Logger.debug("Could not public key!")
|
Logger.debug("Could not public key!")
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
|
|
@ -112,7 +112,7 @@ def masto_instance(conn, _params) do
|
||||||
version: "#{@mastodon_api_level} (compatible; #{Keyword.get(@instance, :version)})",
|
version: "#{@mastodon_api_level} (compatible; #{Keyword.get(@instance, :version)})",
|
||||||
email: Keyword.get(@instance, :email),
|
email: Keyword.get(@instance, :email),
|
||||||
urls: %{
|
urls: %{
|
||||||
streaming_api: String.replace(Web.base_url(), ["http", "https"], "wss")
|
streaming_api: String.replace(Pleroma.Web.Endpoint.static_url(), "http", "ws")
|
||||||
},
|
},
|
||||||
stats: Stats.get_stats(),
|
stats: Stats.get_stats(),
|
||||||
thumbnail: Web.base_url() <> "/instance/thumbnail.jpeg",
|
thumbnail: Web.base_url() <> "/instance/thumbnail.jpeg",
|
||||||
|
@ -212,14 +212,14 @@ def user_statuses(%{assigns: %{user: user}} = conn, params) do
|
||||||
|> Map.put("actor_id", ap_id)
|
|> Map.put("actor_id", ap_id)
|
||||||
|> Map.put("whole_db", true)
|
|> Map.put("whole_db", true)
|
||||||
|
|
||||||
if params["pinned"] == "true" do
|
activities =
|
||||||
# Since Pleroma has no "pinned" posts feature, we'll just set an empty list here
|
if params["pinned"] == "true" do
|
||||||
activities = []
|
# Since Pleroma has no "pinned" posts feature, we'll just set an empty list here
|
||||||
else
|
[]
|
||||||
activities =
|
else
|
||||||
ActivityPub.fetch_public_activities(params)
|
ActivityPub.fetch_public_activities(params)
|
||||||
|> Enum.reverse()
|
|> Enum.reverse()
|
||||||
end
|
end
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> add_link_headers(:user_statuses, activities, params["id"])
|
|> add_link_headers(:user_statuses, activities, params["id"])
|
||||||
|
@ -275,7 +275,19 @@ def post_status(%{assigns: %{user: user}} = conn, %{"status" => _} = params) do
|
||||||
|> Map.put("in_reply_to_status_id", params["in_reply_to_id"])
|
|> Map.put("in_reply_to_status_id", params["in_reply_to_id"])
|
||||||
|> Map.put("no_attachment_links", true)
|
|> Map.put("no_attachment_links", true)
|
||||||
|
|
||||||
{:ok, activity} = CommonAPI.post(user, params)
|
idempotency_key =
|
||||||
|
case get_req_header(conn, "idempotency-key") do
|
||||||
|
[key] -> key
|
||||||
|
_ -> Ecto.UUID.generate()
|
||||||
|
end
|
||||||
|
|
||||||
|
{:ok, activity} =
|
||||||
|
Cachex.get!(
|
||||||
|
:idempotency_cache,
|
||||||
|
idempotency_key,
|
||||||
|
fallback: fn _ -> CommonAPI.post(user, params) end
|
||||||
|
)
|
||||||
|
|
||||||
render(conn, StatusView, "status.json", %{activity: activity, for: user, as: :activity})
|
render(conn, StatusView, "status.json", %{activity: activity, for: user, as: :activity})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -82,19 +82,6 @@ def render(
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_reply_to(activity, %{replied_to_activities: replied_to_activities}) do
|
|
||||||
id = activity.data["object"]["inReplyTo"]
|
|
||||||
replied_to_activities[activity.data["object"]["inReplyTo"]]
|
|
||||||
end
|
|
||||||
|
|
||||||
def get_reply_to(%{data: %{"object" => object}}, _) do
|
|
||||||
if object["inReplyTo"] && object["inReplyTo"] != "" do
|
|
||||||
Activity.get_create_activity_by_object_ap_id(object["inReplyTo"])
|
|
||||||
else
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def render("status.json", %{activity: %{data: %{"object" => object}} = activity} = opts) do
|
def render("status.json", %{activity: %{data: %{"object" => object}} = activity} = opts) do
|
||||||
user = User.get_cached_by_ap_id(activity.data["actor"])
|
user = User.get_cached_by_ap_id(activity.data["actor"])
|
||||||
|
|
||||||
|
@ -164,19 +151,6 @@ def render("status.json", %{activity: %{data: %{"object" => object}} = activity}
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_visibility(object) do
|
|
||||||
public = "https://www.w3.org/ns/activitystreams#Public"
|
|
||||||
to = object["to"] || []
|
|
||||||
cc = object["cc"] || []
|
|
||||||
|
|
||||||
cond do
|
|
||||||
public in to -> "public"
|
|
||||||
public in cc -> "unlisted"
|
|
||||||
Enum.any?(to, &String.contains?(&1, "/followers")) -> "private"
|
|
||||||
true -> "direct"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def render("attachment.json", %{attachment: attachment}) do
|
def render("attachment.json", %{attachment: attachment}) do
|
||||||
[%{"mediaType" => media_type, "href" => href} | _] = attachment["url"]
|
[%{"mediaType" => media_type, "href" => href} | _] = attachment["url"]
|
||||||
|
|
||||||
|
@ -199,4 +173,30 @@ def render("attachment.json", %{attachment: attachment}) do
|
||||||
type: type
|
type: type
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def get_reply_to(activity, %{replied_to_activities: replied_to_activities}) do
|
||||||
|
_id = activity.data["object"]["inReplyTo"]
|
||||||
|
replied_to_activities[activity.data["object"]["inReplyTo"]]
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_reply_to(%{data: %{"object" => object}}, _) do
|
||||||
|
if object["inReplyTo"] && object["inReplyTo"] != "" do
|
||||||
|
Activity.get_create_activity_by_object_ap_id(object["inReplyTo"])
|
||||||
|
else
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_visibility(object) do
|
||||||
|
public = "https://www.w3.org/ns/activitystreams#Public"
|
||||||
|
to = object["to"] || []
|
||||||
|
cc = object["cc"] || []
|
||||||
|
|
||||||
|
cond do
|
||||||
|
public in to -> "public"
|
||||||
|
public in cc -> "unlisted"
|
||||||
|
Enum.any?(to, &String.contains?(&1, "/followers")) -> "private"
|
||||||
|
true -> "direct"
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
1
lib/pleroma/web/nodeinfo/nodeinfo.ex
Normal file
1
lib/pleroma/web/nodeinfo/nodeinfo.ex
Normal file
|
@ -0,0 +1 @@
|
||||||
|
|
62
lib/pleroma/web/nodeinfo/nodeinfo_controller.ex
Normal file
62
lib/pleroma/web/nodeinfo/nodeinfo_controller.ex
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
defmodule Pleroma.Web.Nodeinfo.NodeinfoController do
|
||||||
|
use Pleroma.Web, :controller
|
||||||
|
|
||||||
|
alias Pleroma.Stats
|
||||||
|
alias Pleroma.Web
|
||||||
|
|
||||||
|
@instance Application.get_env(:pleroma, :instance)
|
||||||
|
|
||||||
|
def schemas(conn, _params) do
|
||||||
|
response = %{
|
||||||
|
links: [
|
||||||
|
%{
|
||||||
|
rel: "http://nodeinfo.diaspora.software/ns/schema/2.0",
|
||||||
|
href: Web.base_url() <> "/nodeinfo/2.0.json"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
json(conn, response)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Schema definition: https://github.com/jhass/nodeinfo/blob/master/schemas/2.0/schema.json
|
||||||
|
def nodeinfo(conn, %{"version" => "2.0"}) do
|
||||||
|
stats = Stats.get_stats()
|
||||||
|
|
||||||
|
response = %{
|
||||||
|
version: "2.0",
|
||||||
|
software: %{
|
||||||
|
name: "pleroma",
|
||||||
|
version: Keyword.get(@instance, :version)
|
||||||
|
},
|
||||||
|
protocols: ["ostatus", "activitypub"],
|
||||||
|
services: %{
|
||||||
|
inbound: [],
|
||||||
|
outbound: []
|
||||||
|
},
|
||||||
|
openRegistrations: Keyword.get(@instance, :registrations_open),
|
||||||
|
usage: %{
|
||||||
|
users: %{
|
||||||
|
total: stats.user_count || 0
|
||||||
|
},
|
||||||
|
localPosts: stats.status_count || 0
|
||||||
|
},
|
||||||
|
metadata: %{
|
||||||
|
nodeName: Keyword.get(@instance, :name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
conn
|
||||||
|
|> put_resp_header(
|
||||||
|
"content-type",
|
||||||
|
"application/json; profile=http://nodeinfo.diaspora.software/ns/schema/2.0#; charset=utf-8"
|
||||||
|
)
|
||||||
|
|> json(response)
|
||||||
|
end
|
||||||
|
|
||||||
|
def nodeinfo(conn, _) do
|
||||||
|
conn
|
||||||
|
|> put_status(404)
|
||||||
|
|> json(%{error: "Nodeinfo schema version not handled"})
|
||||||
|
end
|
||||||
|
end
|
|
@ -11,7 +11,7 @@ defmodule Pleroma.Web.OAuth.Authorization do
|
||||||
field(:valid_until, :naive_datetime)
|
field(:valid_until, :naive_datetime)
|
||||||
field(:used, :boolean, default: false)
|
field(:used, :boolean, default: false)
|
||||||
belongs_to(:user, Pleroma.User)
|
belongs_to(:user, Pleroma.User)
|
||||||
belongs_to(:app, Pleroma.App)
|
belongs_to(:app, App)
|
||||||
|
|
||||||
timestamps()
|
timestamps()
|
||||||
end
|
end
|
||||||
|
|
|
@ -9,7 +9,7 @@ defmodule Pleroma.Web.OAuth.Token do
|
||||||
field(:refresh_token, :string)
|
field(:refresh_token, :string)
|
||||||
field(:valid_until, :naive_datetime)
|
field(:valid_until, :naive_datetime)
|
||||||
belongs_to(:user, Pleroma.User)
|
belongs_to(:user, Pleroma.User)
|
||||||
belongs_to(:app, Pleroma.App)
|
belongs_to(:app, App)
|
||||||
|
|
||||||
timestamps()
|
timestamps()
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
defmodule Pleroma.Web.OStatus.ActivityRepresenter do
|
defmodule Pleroma.Web.OStatus.ActivityRepresenter do
|
||||||
alias Pleroma.{Activity, User, Object}
|
alias Pleroma.{Activity, User, Object}
|
||||||
alias Pleroma.Web.OStatus.UserRepresenter
|
alias Pleroma.Web.OStatus.UserRepresenter
|
||||||
alias Pleroma.Formatter
|
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
defp get_href(id) do
|
defp get_href(id) do
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
defmodule Pleroma.Web.OStatus.NoteHandler do
|
defmodule Pleroma.Web.OStatus.NoteHandler do
|
||||||
require Logger
|
require Logger
|
||||||
alias Pleroma.Web.{XML, OStatus}
|
alias Pleroma.Web.{XML, OStatus}
|
||||||
alias Pleroma.{Object, User, Activity}
|
alias Pleroma.{Object, Activity}
|
||||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||||
alias Pleroma.Web.ActivityPub.Utils
|
alias Pleroma.Web.ActivityPub.Utils
|
||||||
alias Pleroma.Web.CommonAPI
|
alias Pleroma.Web.CommonAPI
|
||||||
|
|
|
@ -8,7 +8,6 @@ defmodule Pleroma.Web.OStatus.OStatusController do
|
||||||
alias Pleroma.Web.XML
|
alias Pleroma.Web.XML
|
||||||
alias Pleroma.Web.ActivityPub.ActivityPubController
|
alias Pleroma.Web.ActivityPub.ActivityPubController
|
||||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||||
import Ecto.Query
|
|
||||||
|
|
||||||
def feed_redirect(conn, %{"nickname" => nickname} = params) do
|
def feed_redirect(conn, %{"nickname" => nickname} = params) do
|
||||||
user = User.get_cached_by_nickname(nickname)
|
user = User.get_cached_by_nickname(nickname)
|
||||||
|
|
|
@ -295,6 +295,11 @@ def user_fetcher(username) do
|
||||||
|
|
||||||
get("/host-meta", WebFinger.WebFingerController, :host_meta)
|
get("/host-meta", WebFinger.WebFingerController, :host_meta)
|
||||||
get("/webfinger", WebFinger.WebFingerController, :webfinger)
|
get("/webfinger", WebFinger.WebFingerController, :webfinger)
|
||||||
|
get("/nodeinfo", Nodeinfo.NodeinfoController, :schemas)
|
||||||
|
end
|
||||||
|
|
||||||
|
scope "/nodeinfo", Pleroma.Web do
|
||||||
|
get("/:version", Nodeinfo.NodeinfoController, :nodeinfo)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,10 @@ defmodule Pleroma.Web.Streamer do
|
||||||
require Logger
|
require Logger
|
||||||
alias Pleroma.{User, Notification}
|
alias Pleroma.{User, Notification}
|
||||||
|
|
||||||
|
def init(args) do
|
||||||
|
{:ok, args}
|
||||||
|
end
|
||||||
|
|
||||||
def start_link do
|
def start_link do
|
||||||
spawn(fn ->
|
spawn(fn ->
|
||||||
# 30 seconds
|
# 30 seconds
|
||||||
|
@ -110,20 +114,26 @@ def handle_cast(m, state) do
|
||||||
|
|
||||||
def push_to_socket(topics, topic, item) do
|
def push_to_socket(topics, topic, item) do
|
||||||
Enum.each(topics[topic] || [], fn socket ->
|
Enum.each(topics[topic] || [], fn socket ->
|
||||||
json =
|
# Get the current user so we have up-to-date blocks etc.
|
||||||
%{
|
user = User.get_cached_by_ap_id(socket.assigns[:user].ap_id)
|
||||||
event: "update",
|
blocks = user.info["blocks"] || []
|
||||||
payload:
|
|
||||||
Pleroma.Web.MastodonAPI.StatusView.render(
|
|
||||||
"status.json",
|
|
||||||
activity: item,
|
|
||||||
for: socket.assigns[:user]
|
|
||||||
)
|
|
||||||
|> Jason.encode!()
|
|
||||||
}
|
|
||||||
|> Jason.encode!()
|
|
||||||
|
|
||||||
send(socket.transport_pid, {:text, json})
|
unless item.actor in blocks do
|
||||||
|
json =
|
||||||
|
%{
|
||||||
|
event: "update",
|
||||||
|
payload:
|
||||||
|
Pleroma.Web.MastodonAPI.StatusView.render(
|
||||||
|
"status.json",
|
||||||
|
activity: item,
|
||||||
|
for: user
|
||||||
|
)
|
||||||
|
|> Jason.encode!()
|
||||||
|
}
|
||||||
|
|> Jason.encode!()
|
||||||
|
|
||||||
|
send(socket.transport_pid, {:text, json})
|
||||||
|
end
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -92,7 +92,7 @@ def do_remote_follow(conn, %{
|
||||||
|
|
||||||
with %User{} = user <- User.get_cached_by_nickname(username),
|
with %User{} = user <- User.get_cached_by_nickname(username),
|
||||||
true <- Pbkdf2.checkpw(password, user.password_hash),
|
true <- Pbkdf2.checkpw(password, user.password_hash),
|
||||||
%User{} = followed <- Repo.get(User, id),
|
%User{} = _followed <- Repo.get(User, id),
|
||||||
{:ok, follower} <- User.follow(user, followee),
|
{:ok, follower} <- User.follow(user, followee),
|
||||||
{:ok, _activity} <- ActivityPub.follow(follower, followee) do
|
{:ok, _activity} <- ActivityPub.follow(follower, followee) do
|
||||||
conn
|
conn
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
|
defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
|
||||||
alias Pleroma.{User, Activity, Repo, Object}
|
alias Pleroma.{User, Activity, Repo, Object}
|
||||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||||
alias Pleroma.Web.TwitterAPI.Representers.ActivityRepresenter
|
|
||||||
alias Pleroma.Web.TwitterAPI.UserView
|
alias Pleroma.Web.TwitterAPI.UserView
|
||||||
alias Pleroma.Web.{OStatus, CommonAPI}
|
alias Pleroma.Web.{OStatus, CommonAPI}
|
||||||
import Ecto.Query
|
import Ecto.Query
|
||||||
|
@ -184,7 +183,7 @@ defp parse_int(string, default) when is_binary(string) do
|
||||||
|
|
||||||
defp parse_int(_, default), do: default
|
defp parse_int(_, default), do: default
|
||||||
|
|
||||||
def search(user, %{"q" => query} = params) do
|
def search(_user, %{"q" => query} = params) do
|
||||||
limit = parse_int(params["rpp"], 20)
|
limit = parse_int(params["rpp"], 20)
|
||||||
page = parse_int(params["page"], 1)
|
page = parse_int(params["page"], 1)
|
||||||
offset = (page - 1) * limit
|
offset = (page - 1) * limit
|
||||||
|
@ -206,7 +205,7 @@ def search(user, %{"q" => query} = params) do
|
||||||
order_by: [desc: :inserted_at]
|
order_by: [desc: :inserted_at]
|
||||||
)
|
)
|
||||||
|
|
||||||
activities = Repo.all(q)
|
_activities = Repo.all(q)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp make_date do
|
defp make_date do
|
||||||
|
|
|
@ -347,7 +347,8 @@ def empty_array(conn, _params) do
|
||||||
def update_profile(%{assigns: %{user: user}} = conn, params) do
|
def update_profile(%{assigns: %{user: user}} = conn, params) do
|
||||||
params =
|
params =
|
||||||
if bio = params["description"] do
|
if bio = params["description"] do
|
||||||
Map.put(params, "bio", bio)
|
bio_brs = Regex.replace(~r/\r?\n/, bio, "<br>")
|
||||||
|
Map.put(params, "bio", bio_brs)
|
||||||
else
|
else
|
||||||
params
|
params
|
||||||
end
|
end
|
||||||
|
|
|
@ -31,7 +31,7 @@ defp query_users(user_ids) do
|
||||||
end
|
end
|
||||||
|
|
||||||
defp collect_context_ids(activities) do
|
defp collect_context_ids(activities) do
|
||||||
contexts =
|
_contexts =
|
||||||
activities
|
activities
|
||||||
|> Enum.reject(& &1.data["context_id"])
|
|> Enum.reject(& &1.data["context_id"])
|
||||||
|> Enum.map(fn %{data: data} ->
|
|> Enum.map(fn %{data: data} ->
|
||||||
|
|
|
@ -2,7 +2,6 @@ defmodule Pleroma.Web.TwitterAPI.NotificationView do
|
||||||
use Pleroma.Web, :view
|
use Pleroma.Web, :view
|
||||||
alias Pleroma.{Notification, User}
|
alias Pleroma.{Notification, User}
|
||||||
alias Pleroma.Web.CommonAPI.Utils
|
alias Pleroma.Web.CommonAPI.Utils
|
||||||
alias Pleroma.Web.MediaProxy
|
|
||||||
alias Pleroma.Web.TwitterAPI.UserView
|
alias Pleroma.Web.TwitterAPI.UserView
|
||||||
alias Pleroma.Web.TwitterAPI.ActivityView
|
alias Pleroma.Web.TwitterAPI.ActivityView
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
defmodule Pleroma.Web.WebFinger do
|
defmodule Pleroma.Web.WebFinger do
|
||||||
@httpoison Application.get_env(:pleroma, :httpoison)
|
@httpoison Application.get_env(:pleroma, :httpoison)
|
||||||
|
|
||||||
alias Pleroma.{Repo, User, XmlBuilder}
|
alias Pleroma.{User, XmlBuilder}
|
||||||
alias Pleroma.Web
|
alias Pleroma.Web
|
||||||
alias Pleroma.Web.{XML, Salmon, OStatus}
|
alias Pleroma.Web.{XML, Salmon, OStatus}
|
||||||
require Jason
|
require Jason
|
||||||
|
@ -239,13 +239,14 @@ def finger(account) do
|
||||||
URI.parse(account).host
|
URI.parse(account).host
|
||||||
end
|
end
|
||||||
|
|
||||||
case find_lrdd_template(domain) do
|
address =
|
||||||
{:ok, template} ->
|
case find_lrdd_template(domain) do
|
||||||
address = String.replace(template, "{uri}", URI.encode(account))
|
{:ok, template} ->
|
||||||
|
String.replace(template, "{uri}", URI.encode(account))
|
||||||
|
|
||||||
_ ->
|
_ ->
|
||||||
address = "http://#{domain}/.well-known/webfinger?resource=acct:#{account}"
|
"http://#{domain}/.well-known/webfinger?resource=acct:#{account}"
|
||||||
end
|
end
|
||||||
|
|
||||||
with response <-
|
with response <-
|
||||||
@httpoison.get(
|
@httpoison.get(
|
||||||
|
|
|
@ -14,7 +14,7 @@ def string_from_xpath(xpath, doc) do
|
||||||
|
|
||||||
if res == "", do: nil, else: res
|
if res == "", do: nil, else: res
|
||||||
catch
|
catch
|
||||||
e ->
|
_e ->
|
||||||
Logger.debug("Couldn't find xpath #{xpath} in XML doc")
|
Logger.debug("Couldn't find xpath #{xpath} in XML doc")
|
||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><title>Pleroma</title><link rel=stylesheet href=/static/font/css/fontello.css><link rel=stylesheet href=/static/font/css/animation.css><link href=/static/css/app.6c8da1b0ace79ad8881a0e5e716ec818.css rel=stylesheet></head><body style="display: none"><div id=app></div><script type=text/javascript src=/static/js/manifest.cdeff2a56af285544b89.js></script><script type=text/javascript src=/static/js/vendor.ef2aee0b2db579c3a86a.js></script><script type=text/javascript src=/static/js/app.408cea515c3032097a51.js></script></body></html>
|
<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><title>Pleroma</title><link rel=icon type=image/png href=/favicon.png><link rel=stylesheet href=/static/font/css/fontello.css><link rel=stylesheet href=/static/font/css/animation.css><link href=/static/css/app.6c8da1b0ace79ad8881a0e5e716ec818.css rel=stylesheet></head><body style="display: none"><div id=app></div><script type=text/javascript src=/static/js/manifest.38e369a50eccc2857845.js></script><script type=text/javascript src=/static/js/vendor.ef2aee0b2db579c3a86a.js></script><script type=text/javascript src=/static/js/app.af121efa5ff89725b4c6.js></script></body></html>
|
|
@ -2,7 +2,8 @@
|
||||||
"theme": "pleroma-dark",
|
"theme": "pleroma-dark",
|
||||||
"background": "/static/aurora_borealis.jpg",
|
"background": "/static/aurora_borealis.jpg",
|
||||||
"logo": "/static/logo.png",
|
"logo": "/static/logo.png",
|
||||||
"defaultPath": "/main/all",
|
"redirectRootNoLogin": "/main/all",
|
||||||
|
"redirectRootLogin": "/main/friends",
|
||||||
"chatDisabled": false,
|
"chatDisabled": false,
|
||||||
"showInstanceSpecificPanel": true
|
"showInstanceSpecificPanel": false
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
7
priv/static/static/js/app.af121efa5ff89725b4c6.js
Normal file
7
priv/static/static/js/app.af121efa5ff89725b4c6.js
Normal file
File diff suppressed because one or more lines are too long
1
priv/static/static/js/app.af121efa5ff89725b4c6.js.map
Normal file
1
priv/static/static/js/app.af121efa5ff89725b4c6.js.map
Normal file
File diff suppressed because one or more lines are too long
2
priv/static/static/js/manifest.38e369a50eccc2857845.js
Normal file
2
priv/static/static/js/manifest.38e369a50eccc2857845.js
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
!function(e){function t(a){if(r[a])return r[a].exports;var n=r[a]={exports:{},id:a,loaded:!1};return e[a].call(n.exports,n,n.exports,t),n.loaded=!0,n.exports}var a=window.webpackJsonp;window.webpackJsonp=function(o,c){for(var p,l,s=0,f=[];s<o.length;s++)l=o[s],n[l]&&f.push.apply(f,n[l]),n[l]=0;for(p in c)Object.prototype.hasOwnProperty.call(c,p)&&(e[p]=c[p]);for(a&&a(o,c);f.length;)f.shift().call(null,t);if(c[0])return r[0]=0,t(0)};var r={},n={0:0};t.e=function(e,a){if(0===n[e])return a.call(null,t);if(void 0!==n[e])n[e].push(a);else{n[e]=[a];var r=document.getElementsByTagName("head")[0],o=document.createElement("script");o.type="text/javascript",o.charset="utf-8",o.async=!0,o.src=t.p+"static/js/"+e+"."+{1:"ef2aee0b2db579c3a86a",2:"af121efa5ff89725b4c6"}[e]+".js",r.appendChild(o)}},t.m=e,t.c=r,t.p="/"}([]);
|
||||||
|
//# sourceMappingURL=manifest.38e369a50eccc2857845.js.map
|
File diff suppressed because one or more lines are too long
|
@ -1,2 +0,0 @@
|
||||||
!function(e){function t(a){if(r[a])return r[a].exports;var n=r[a]={exports:{},id:a,loaded:!1};return e[a].call(n.exports,n,n.exports,t),n.loaded=!0,n.exports}var a=window.webpackJsonp;window.webpackJsonp=function(c,o){for(var p,l,s=0,i=[];s<c.length;s++)l=c[s],n[l]&&i.push.apply(i,n[l]),n[l]=0;for(p in o)Object.prototype.hasOwnProperty.call(o,p)&&(e[p]=o[p]);for(a&&a(c,o);i.length;)i.shift().call(null,t);if(o[0])return r[0]=0,t(0)};var r={},n={0:0};t.e=function(e,a){if(0===n[e])return a.call(null,t);if(void 0!==n[e])n[e].push(a);else{n[e]=[a];var r=document.getElementsByTagName("head")[0],c=document.createElement("script");c.type="text/javascript",c.charset="utf-8",c.async=!0,c.src=t.p+"static/js/"+e+"."+{1:"ef2aee0b2db579c3a86a",2:"408cea515c3032097a51"}[e]+".js",r.appendChild(c)}},t.m=e,t.c=r,t.p="/"}([]);
|
|
||||||
//# sourceMappingURL=manifest.cdeff2a56af285544b89.js.map
|
|
|
@ -33,6 +33,13 @@ test "it doesn't create a notification for user if the user blocks the activity
|
||||||
|
|
||||||
assert nil == Notification.create_notification(activity, user)
|
assert nil == Notification.create_notification(activity, user)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "it doesn't create a notification for user if he is the activity author" do
|
||||||
|
activity = insert(:note_activity)
|
||||||
|
author = User.get_by_ap_id(activity.data["actor"])
|
||||||
|
|
||||||
|
assert nil == Notification.create_notification(activity, author)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "get notification" do
|
describe "get notification" do
|
||||||
|
|
|
@ -26,7 +26,7 @@ def insert(data \\ %{}, opts \\ %{}) do
|
||||||
end
|
end
|
||||||
|
|
||||||
def insert_list(times, data \\ %{}, opts \\ %{}) do
|
def insert_list(times, data \\ %{}, opts \\ %{}) do
|
||||||
Enum.map(1..times, fn n ->
|
Enum.map(1..times, fn _n ->
|
||||||
{:ok, activity} = insert(data, opts)
|
{:ok, activity} = insert(data, opts)
|
||||||
activity
|
activity
|
||||||
end)
|
end)
|
||||||
|
|
|
@ -367,7 +367,7 @@ def get("https://shitposter.club/api/statuses/user_timeline/1.atom", _body, _hea
|
||||||
|
|
||||||
def post(
|
def post(
|
||||||
"https://social.heldscal.la/main/push/hub",
|
"https://social.heldscal.la/main/push/hub",
|
||||||
{:form, data},
|
{:form, _data},
|
||||||
"Content-type": "application/x-www-form-urlencoded"
|
"Content-type": "application/x-www-form-urlencoded"
|
||||||
) do
|
) do
|
||||||
{:ok,
|
{:ok,
|
||||||
|
@ -711,11 +711,11 @@ def get(url, body, headers) do
|
||||||
}"}
|
}"}
|
||||||
end
|
end
|
||||||
|
|
||||||
def post(url, body, headers) do
|
def post(url, _body, _headers) do
|
||||||
{:error, "Not implemented the mock response for post #{inspect(url)}"}
|
{:error, "Not implemented the mock response for post #{inspect(url)}"}
|
||||||
end
|
end
|
||||||
|
|
||||||
def post(url, body, headers, options) do
|
def post(url, _body, _headers, _options) do
|
||||||
{:error, "Not implemented the mock response for post #{inspect(url)}"}
|
{:error, "Not implemented the mock response for post #{inspect(url)}"}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -63,7 +63,42 @@ test "the public timeline", %{conn: conn} do
|
||||||
test "posting a status", %{conn: conn} do
|
test "posting a status", %{conn: conn} do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
|
|
||||||
conn =
|
idempotency_key = "Pikachu rocks!"
|
||||||
|
|
||||||
|
conn_one =
|
||||||
|
conn
|
||||||
|
|> assign(:user, user)
|
||||||
|
|> put_req_header("idempotency-key", idempotency_key)
|
||||||
|
|> post("/api/v1/statuses", %{
|
||||||
|
"status" => "cofe",
|
||||||
|
"spoiler_text" => "2hu",
|
||||||
|
"sensitive" => "false"
|
||||||
|
})
|
||||||
|
|
||||||
|
{:ok, ttl} = Cachex.ttl(:idempotency_cache, idempotency_key)
|
||||||
|
# Six hours
|
||||||
|
assert ttl > :timer.seconds(6 * 60 * 60 - 1)
|
||||||
|
|
||||||
|
assert %{"content" => "cofe", "id" => id, "spoiler_text" => "2hu", "sensitive" => false} =
|
||||||
|
json_response(conn_one, 200)
|
||||||
|
|
||||||
|
assert Repo.get(Activity, id)
|
||||||
|
|
||||||
|
conn_two =
|
||||||
|
conn
|
||||||
|
|> assign(:user, user)
|
||||||
|
|> put_req_header("idempotency-key", idempotency_key)
|
||||||
|
|> post("/api/v1/statuses", %{
|
||||||
|
"status" => "cofe",
|
||||||
|
"spoiler_text" => "2hu",
|
||||||
|
"sensitive" => "false"
|
||||||
|
})
|
||||||
|
|
||||||
|
assert %{"id" => second_id} = json_response(conn_two, 200)
|
||||||
|
|
||||||
|
assert id == second_id
|
||||||
|
|
||||||
|
conn_three =
|
||||||
conn
|
conn
|
||||||
|> assign(:user, user)
|
|> assign(:user, user)
|
||||||
|> post("/api/v1/statuses", %{
|
|> post("/api/v1/statuses", %{
|
||||||
|
@ -72,10 +107,9 @@ test "posting a status", %{conn: conn} do
|
||||||
"sensitive" => "false"
|
"sensitive" => "false"
|
||||||
})
|
})
|
||||||
|
|
||||||
assert %{"content" => "cofe", "id" => id, "spoiler_text" => "2hu", "sensitive" => false} =
|
assert %{"id" => third_id} = json_response(conn_three, 200)
|
||||||
json_response(conn, 200)
|
|
||||||
|
|
||||||
assert Repo.get(Activity, id)
|
refute id == third_id
|
||||||
end
|
end
|
||||||
|
|
||||||
test "posting a sensitive status", %{conn: conn} do
|
test "posting a sensitive status", %{conn: conn} do
|
||||||
|
|
63
test/web/streamer_test.exs
Normal file
63
test/web/streamer_test.exs
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
defmodule Pleroma.Web.StreamerTest do
|
||||||
|
use Pleroma.DataCase
|
||||||
|
|
||||||
|
alias Pleroma.Web.Streamer
|
||||||
|
alias Pleroma.User
|
||||||
|
alias Pleroma.Web.CommonAPI
|
||||||
|
import Pleroma.Factory
|
||||||
|
|
||||||
|
test "it sends to public" do
|
||||||
|
user = insert(:user)
|
||||||
|
other_user = insert(:user)
|
||||||
|
|
||||||
|
task =
|
||||||
|
Task.async(fn ->
|
||||||
|
assert_receive {:text, _}, 4_000
|
||||||
|
end)
|
||||||
|
|
||||||
|
fake_socket = %{
|
||||||
|
transport_pid: task.pid,
|
||||||
|
assigns: %{
|
||||||
|
user: user
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{:ok, activity} = CommonAPI.post(other_user, %{"status" => "Test"})
|
||||||
|
|
||||||
|
topics = %{
|
||||||
|
"public" => [fake_socket]
|
||||||
|
}
|
||||||
|
|
||||||
|
Streamer.push_to_socket(topics, "public", activity)
|
||||||
|
|
||||||
|
Task.await(task)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it doesn't send to blocked users" do
|
||||||
|
user = insert(:user)
|
||||||
|
blocked_user = insert(:user)
|
||||||
|
{:ok, user} = User.block(user, blocked_user)
|
||||||
|
|
||||||
|
task =
|
||||||
|
Task.async(fn ->
|
||||||
|
refute_receive {:text, _}, 1_000
|
||||||
|
end)
|
||||||
|
|
||||||
|
fake_socket = %{
|
||||||
|
transport_pid: task.pid,
|
||||||
|
assigns: %{
|
||||||
|
user: user
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{:ok, activity} = CommonAPI.post(blocked_user, %{"status" => "Test"})
|
||||||
|
|
||||||
|
topics = %{
|
||||||
|
"public" => [fake_socket]
|
||||||
|
}
|
||||||
|
|
||||||
|
Streamer.push_to_socket(topics, "public", activity)
|
||||||
|
|
||||||
|
Task.await(task)
|
||||||
|
end
|
||||||
|
end
|
|
@ -257,8 +257,10 @@ test "without valid credentials", %{conn: conn} do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "with credentials", %{conn: conn, user: current_user} do
|
test "with credentials", %{conn: conn, user: current_user} do
|
||||||
|
other_user = insert(:user)
|
||||||
|
|
||||||
{:ok, activity} =
|
{:ok, activity} =
|
||||||
ActivityBuilder.insert(%{"to" => [current_user.ap_id]}, %{user: current_user})
|
ActivityBuilder.insert(%{"to" => [current_user.ap_id]}, %{user: other_user})
|
||||||
|
|
||||||
conn =
|
conn =
|
||||||
conn
|
conn
|
||||||
|
@ -784,4 +786,18 @@ test "it returns the tags timeline", %{conn: conn} do
|
||||||
assert status["id"] == activity.id
|
assert status["id"] == activity.id
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "Convert newlines to <br> in bio", %{conn: conn} do
|
||||||
|
user = insert(:user)
|
||||||
|
|
||||||
|
conn =
|
||||||
|
conn
|
||||||
|
|> assign(:user, user)
|
||||||
|
|> post("/api/account/update_profile.json", %{
|
||||||
|
"description" => "Hello,\r\nWorld! I\n am a test."
|
||||||
|
})
|
||||||
|
|
||||||
|
user = Repo.get!(User, user.id)
|
||||||
|
assert user.bio == "Hello,<br>World! I<br> am a test."
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue