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, :ostatus, Pleroma.Web.OStatusMock
|
||||
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.
|
||||
|
||||
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_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
|
|
|
@ -13,4 +13,3 @@ Restart=on-failure
|
|||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
Alias=pleroma.service
|
||||
|
|
|
@ -39,15 +39,9 @@ sub vcl_recv {
|
|||
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
|
||||
# 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)$"))
|
||||
{
|
||||
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
|
||||
# Also enable streaming of cached content to clients (no waiting for Varnish to complete backend fetch)
|
||||
if ((bereq.url ~ "^/(notice|objects)/") ||
|
||||
(bereq.url ~ "(?i)\.(js|css|jpg|jpeg|png|gif|gz|tgz|bz2|tbz|mp3|ogg|svg|swf|ttf|pdf|woff|woff2)$"))
|
||||
if (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.Cache-Control;
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
defmodule Mix.Tasks.FixApUsers do
|
||||
use Mix.Task
|
||||
import Mix.Ecto
|
||||
import Ecto.Query
|
||||
alias Pleroma.{Repo, User}
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
defmodule Mix.Tasks.GeneratePasswordReset do
|
||||
use Mix.Task
|
||||
import Mix.Ecto
|
||||
alias Pleroma.{Repo, User}
|
||||
alias Pleroma.User
|
||||
|
||||
@shortdoc "Generate password reset link for user"
|
||||
def run([nickname]) do
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
defmodule Mix.Tasks.RegisterUser do
|
||||
use Mix.Task
|
||||
import Mix.Ecto
|
||||
alias Pleroma.{Repo, User}
|
||||
|
||||
@shortdoc "Register user"
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
defmodule Mix.Tasks.RmUser do
|
||||
use Mix.Task
|
||||
import Mix.Ecto
|
||||
alias Pleroma.{User, Repo}
|
||||
alias Pleroma.User
|
||||
|
||||
@shortdoc "Permanently delete a user"
|
||||
def run([nickname]) do
|
||||
|
|
|
@ -23,6 +23,18 @@ def start(_type, _args) do
|
|||
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.Gopher.Server, []),
|
||||
worker(Pleroma.Stats, [])
|
||||
|
|
|
@ -65,12 +65,6 @@ def link(name, selector, type \\ 1) do
|
|||
"#{type}#{name}\t#{selector}\t#{address}\t#{port}\r\n"
|
||||
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
|
||||
activities
|
||||
|> Enum.reverse()
|
||||
|
@ -93,6 +87,12 @@ def render_activities(activities) do
|
|||
|> Enum.join("\r\n")
|
||||
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
|
||||
posts =
|
||||
ActivityPub.fetch_public_activities(%{"type" => ["Create"], "local_only" => true})
|
||||
|
|
|
@ -91,7 +91,8 @@ def create_notifications(_), do: {:ok, []}
|
|||
|
||||
# TODO move to sql, too.
|
||||
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}
|
||||
{:ok, notification} = Repo.insert(notification)
|
||||
Pleroma.Web.Streamer.stream("user", notification)
|
||||
|
|
|
@ -7,11 +7,11 @@ def init(options) do
|
|||
options
|
||||
end
|
||||
|
||||
def call(%{assigns: %{valid_signature: true}} = conn, opts) do
|
||||
def call(%{assigns: %{valid_signature: true}} = conn, _opts) do
|
||||
conn
|
||||
end
|
||||
|
||||
def call(conn, opts) do
|
||||
def call(conn, _opts) do
|
||||
user = conn.params["actor"]
|
||||
Logger.debug("Checking sig for #{user}")
|
||||
[signature | _] = get_req_header(conn, "signature")
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
defmodule Pleroma.Stats do
|
||||
import Ecto.Query
|
||||
alias Pleroma.{User, Repo, Activity}
|
||||
alias Pleroma.{User, Repo}
|
||||
|
||||
def start_link do
|
||||
agent = Agent.start_link(fn -> {[], %{}} end, name: __MODULE__)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
||||
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.Federator
|
||||
alias Pleroma.Web.OStatus
|
||||
|
@ -11,7 +11,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
@httpoison Application.get_env(:pleroma, :httpoison)
|
||||
|
||||
@instance Application.get_env(:pleroma, :instance)
|
||||
@rewrite_policy Keyword.get(@instance, :rewrite_policy)
|
||||
|
||||
def get_recipients(data) do
|
||||
(data["to"] || []) ++ (data["cc"] || [])
|
||||
|
@ -20,8 +19,8 @@ def get_recipients(data) do
|
|||
def insert(map, local \\ true) when is_map(map) do
|
||||
with nil <- Activity.get_by_ap_id(map["id"]),
|
||||
map <- lazy_put_activity_defaults(map),
|
||||
:ok <- insert_full_object(map),
|
||||
{:ok, map} <- @rewrite_policy.filter(map) do
|
||||
{:ok, map} <- MRF.filter(map),
|
||||
:ok <- insert_full_object(map) do
|
||||
{:ok, activity} =
|
||||
Repo.insert(%Activity{
|
||||
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 <- maybe_federate(activity),
|
||||
{:ok, actor} <- User.increase_note_count(actor) do
|
||||
{:ok, _actor} <- User.increase_note_count(actor) do
|
||||
{:ok, activity}
|
||||
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)),
|
||||
{:ok, activity} <- insert(data, local),
|
||||
:ok <- maybe_federate(activity),
|
||||
{:ok, actor} <- User.decrease_note_count(user) do
|
||||
{:ok, _actor} <- User.decrease_note_count(user) do
|
||||
{:ok, activity}
|
||||
end
|
||||
end
|
||||
|
@ -236,7 +235,7 @@ defp restrict_tag(query, %{"tag" => tag}) do
|
|||
|
||||
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
|
||||
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
|
||||
blocks = info["blocks"] || []
|
||||
from(activity in query,
|
||||
|
||||
from(
|
||||
activity in query,
|
||||
where: fragment("not (? = ANY(?))", activity.actor, ^blocks),
|
||||
where: fragment("not (?->'to' \\?| ?)", activity.data, ^blocks)
|
||||
)
|
||||
|
@ -405,7 +406,7 @@ def fetch_and_prepare_user_from_ap_id(ap_id) do
|
|||
end
|
||||
|
||||
def make_user_from_ap_id(ap_id) do
|
||||
if user = User.get_by_ap_id(ap_id) do
|
||||
if _user = User.get_by_ap_id(ap_id) do
|
||||
Transmogrifier.upgrade_user_from_ap_id(ap_id)
|
||||
else
|
||||
with {:ok, data} <- fetch_and_prepare_user_from_ap_id(ap_id) do
|
||||
|
@ -501,7 +502,7 @@ def fetch_object_from_id(id) do
|
|||
object = %Object{} ->
|
||||
{:ok, object}
|
||||
|
||||
e ->
|
||||
_e ->
|
||||
Logger.info("Couldn't get object via AP, trying out OStatus fetching...")
|
||||
|
||||
case OStatus.fetch_activity_from_url(id) do
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
defmodule Pleroma.Web.ActivityPub.ActivityPubController do
|
||||
use Pleroma.Web, :controller
|
||||
alias Pleroma.{User, Repo, Object, Activity}
|
||||
alias Pleroma.Web.ActivityPub.{ObjectView, UserView, Transmogrifier}
|
||||
alias Pleroma.{User, Object}
|
||||
alias Pleroma.Web.ActivityPub.{ObjectView, UserView}
|
||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||
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
|
||||
require Logger
|
||||
@behaviour Pleroma.Web.ActivityPub.MRF
|
||||
|
||||
@impl true
|
||||
def filter(object) do
|
||||
Logger.info("REJECTING #{inspect(object)}")
|
||||
{:reject, object}
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
defmodule Pleroma.Web.ActivityPub.MRF.NoOpPolicy do
|
||||
@behaviour Pleroma.Web.ActivityPub.MRF
|
||||
|
||||
@impl true
|
||||
def filter(object) do
|
||||
{:ok, object}
|
||||
end
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
|
||||
alias Pleroma.User
|
||||
@behaviour Pleroma.Web.ActivityPub.MRF
|
||||
|
||||
@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
|
||||
child_object = Map.delete(object["object"], "attachment")
|
||||
object = Map.put(object, "object", child_object)
|
||||
{:ok, object}
|
||||
else
|
||||
{:ok, object}
|
||||
end
|
||||
|
||||
{:ok, object}
|
||||
end
|
||||
|
||||
@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, "sensitive", true)
|
||||
object = Map.put(object, "object", child_object)
|
||||
{:ok, object}
|
||||
else
|
||||
{:ok, object}
|
||||
end
|
||||
|
||||
{:ok, object}
|
||||
end
|
||||
|
||||
@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"])
|
||||
|
||||
# flip to/cc relationship to make the post unlisted
|
||||
if "https://www.w3.org/ns/activitystreams#Public" in object["to"] and
|
||||
user.follower_address in object["cc"] do
|
||||
to =
|
||||
List.delete(object["to"], "https://www.w3.org/ns/activitystreams#Public") ++
|
||||
[user.follower_address]
|
||||
object =
|
||||
if "https://www.w3.org/ns/activitystreams#Public" in object["to"] and
|
||||
user.follower_address in object["cc"] do
|
||||
to =
|
||||
List.delete(object["to"], "https://www.w3.org/ns/activitystreams#Public") ++
|
||||
[user.follower_address]
|
||||
|
||||
cc =
|
||||
List.delete(object["cc"], user.follower_address) ++
|
||||
["https://www.w3.org/ns/activitystreams#Public"]
|
||||
cc =
|
||||
List.delete(object["cc"], user.follower_address) ++
|
||||
["https://www.w3.org/ns/activitystreams#Public"]
|
||||
|
||||
object = Map.put(object, "to", to)
|
||||
object = Map.put(object, "cc", cc)
|
||||
end
|
||||
object
|
||||
|> Map.put("to", to)
|
||||
|> Map.put("cc", cc)
|
||||
else
|
||||
object
|
||||
end
|
||||
|
||||
{:ok, object}
|
||||
else
|
||||
{:ok, object}
|
||||
end
|
||||
|
||||
{:ok, object}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def filter(object) do
|
||||
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}
|
||||
else
|
||||
e -> {:reject, nil}
|
||||
_e -> {:reject, nil}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -72,9 +72,12 @@ def fix_emoji(object) do
|
|||
|> Enum.reduce(%{}, fn data, mapping ->
|
||||
name = data["name"]
|
||||
|
||||
if String.starts_with?(name, ":") do
|
||||
name = name |> String.slice(1..-2)
|
||||
end
|
||||
name =
|
||||
if String.starts_with?(name, ":") do
|
||||
name |> String.slice(1..-2)
|
||||
else
|
||||
name
|
||||
end
|
||||
|
||||
mapping |> Map.put(name, data["icon"]["url"])
|
||||
end)
|
||||
|
@ -143,12 +146,12 @@ def handle_incoming(
|
|||
end
|
||||
|
||||
def handle_incoming(
|
||||
%{"type" => "Like", "object" => object_id, "actor" => actor, "id" => id} = data
|
||||
%{"type" => "Like", "object" => object_id, "actor" => actor, "id" => id} = _data
|
||||
) do
|
||||
with %User{} = actor <- User.get_or_fetch_by_ap_id(actor),
|
||||
{:ok, object} <-
|
||||
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}
|
||||
else
|
||||
_e -> :error
|
||||
|
@ -156,12 +159,12 @@ def handle_incoming(
|
|||
end
|
||||
|
||||
def handle_incoming(
|
||||
%{"type" => "Announce", "object" => object_id, "actor" => actor, "id" => id} = data
|
||||
%{"type" => "Announce", "object" => object_id, "actor" => actor, "id" => id} = _data
|
||||
) do
|
||||
with %User{} = actor <- User.get_or_fetch_by_ap_id(actor),
|
||||
{:ok, object} <-
|
||||
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}
|
||||
else
|
||||
_e -> :error
|
||||
|
@ -202,7 +205,7 @@ def handle_incoming(
|
|||
|
||||
# TODO: Make secure.
|
||||
def handle_incoming(
|
||||
%{"type" => "Delete", "object" => object_id, "actor" => actor, "id" => id} = data
|
||||
%{"type" => "Delete", "object" => object_id, "actor" => actor, "id" => _id} = _data
|
||||
) do
|
||||
object_id =
|
||||
case object_id do
|
||||
|
@ -210,13 +213,13 @@ def handle_incoming(
|
|||
id -> id
|
||||
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} <-
|
||||
get_obj_helper(object_id) || ActivityPub.fetch_object_from_id(object_id),
|
||||
{:ok, activity} <- ActivityPub.delete(object, false) do
|
||||
{:ok, activity}
|
||||
else
|
||||
e -> :error
|
||||
_e -> :error
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -254,10 +257,10 @@ def prepare_object(object) do
|
|||
|> set_reply_to_uri
|
||||
end
|
||||
|
||||
@doc
|
||||
"""
|
||||
internal -> Mastodon
|
||||
"""
|
||||
# @doc
|
||||
# """
|
||||
# internal -> Mastodon
|
||||
# """
|
||||
|
||||
def prepare_outgoing(%{"type" => "Create", "object" => %{"type" => "Note"} = object} = data) do
|
||||
object =
|
||||
|
@ -272,7 +275,7 @@ def prepare_outgoing(%{"type" => "Create", "object" => %{"type" => "Note"} = obj
|
|||
{:ok, data}
|
||||
end
|
||||
|
||||
def prepare_outgoing(%{"type" => type} = data) do
|
||||
def prepare_outgoing(%{"type" => _type} = data) do
|
||||
data =
|
||||
data
|
||||
|> maybe_fix_object_url
|
||||
|
@ -286,7 +289,7 @@ def maybe_fix_object_url(data) do
|
|||
case ActivityPub.fetch_object_from_id(data["object"]) do
|
||||
{:ok, relative_object} ->
|
||||
if relative_object.data["external_url"] do
|
||||
data =
|
||||
_data =
|
||||
data
|
||||
|> Map.put("object", relative_object.data["external_url"])
|
||||
else
|
||||
|
|
|
@ -47,25 +47,6 @@ def render("user.json", %{user: user}) do
|
|||
|> Map.merge(Utils.make_json_ld_header())
|
||||
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
|
||||
query = User.get_friends_query(user)
|
||||
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"
|
||||
}
|
||||
|
||||
if max_qid != nil do
|
||||
params = Map.put(params, "max_id", max_qid)
|
||||
end
|
||||
params =
|
||||
if max_qid != nil do
|
||||
Map.put(params, "max_id", max_qid)
|
||||
else
|
||||
params
|
||||
end
|
||||
|
||||
activities = ActivityPub.fetch_public_activities(params)
|
||||
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())
|
||||
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
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
defmodule Pleroma.Web.UserSocket do
|
||||
use Phoenix.Socket
|
||||
alias Pleroma.User
|
||||
alias Comeonin.Pbkdf2
|
||||
|
||||
## Channels
|
||||
# channel "room:*", Pleroma.Web.RoomChannel
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
defmodule Pleroma.Web.CommonAPI do
|
||||
alias Pleroma.{Repo, Activity, Object, User}
|
||||
alias Pleroma.{Repo, Activity, Object}
|
||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||
alias Pleroma.Formatter
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
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 Calendar.Strftime
|
||||
|
||||
|
@ -49,7 +49,7 @@ def to_for_user_and_mentions(user, mentions, inReplyTo, "private") do
|
|||
{[user.follower_address | to], cc}
|
||||
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)
|
||||
|
||||
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(_), 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
|
||||
add_attachments(text, attachments)
|
||||
|
|
|
@ -14,6 +14,10 @@ defmodule Pleroma.Web.Federator do
|
|||
@federating Keyword.get(@instance, :federating)
|
||||
@max_jobs 20
|
||||
|
||||
def init(args) do
|
||||
{:ok, args}
|
||||
end
|
||||
|
||||
def start_link do
|
||||
spawn(fn ->
|
||||
# 1 minute
|
||||
|
@ -89,12 +93,12 @@ def handle(:incoming_ap_doc, params) do
|
|||
|
||||
with {:ok, _user} <- ap_enabled_actor(params["actor"]),
|
||||
nil <- Activity.get_by_ap_id(params["id"]),
|
||||
{:ok, activity} <- Transmogrifier.handle_incoming(params) do
|
||||
{:ok, _activity} <- Transmogrifier.handle_incoming(params) do
|
||||
else
|
||||
%Activity{} ->
|
||||
Logger.info("Already had #{params["id"]}")
|
||||
|
||||
e ->
|
||||
_e ->
|
||||
# Just drop those for now
|
||||
Logger.info("Unhandled activity")
|
||||
Logger.info(Poison.encode!(params, pretty: 2))
|
||||
|
@ -154,7 +158,7 @@ def maybe_start_job(running_jobs, queue) do
|
|||
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
|
||||
%{in: {i_running_jobs, i_queue}, out: {o_running_jobs, o_queue}} = state
|
||||
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}}}
|
||||
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
|
||||
o_queue = enqueue_sorted(o_queue, {type, payload}, 1)
|
||||
{o_running_jobs, o_queue} = maybe_start_job(o_running_jobs, o_queue)
|
||||
|
|
|
@ -45,7 +45,7 @@ def validate_conn(conn) do
|
|||
end
|
||||
end
|
||||
else
|
||||
e ->
|
||||
_e ->
|
||||
Logger.debug("Could not public key!")
|
||||
false
|
||||
end
|
||||
|
|
|
@ -112,7 +112,7 @@ def masto_instance(conn, _params) do
|
|||
version: "#{@mastodon_api_level} (compatible; #{Keyword.get(@instance, :version)})",
|
||||
email: Keyword.get(@instance, :email),
|
||||
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(),
|
||||
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("whole_db", true)
|
||||
|
||||
if params["pinned"] == "true" do
|
||||
# Since Pleroma has no "pinned" posts feature, we'll just set an empty list here
|
||||
activities = []
|
||||
else
|
||||
activities =
|
||||
activities =
|
||||
if params["pinned"] == "true" do
|
||||
# Since Pleroma has no "pinned" posts feature, we'll just set an empty list here
|
||||
[]
|
||||
else
|
||||
ActivityPub.fetch_public_activities(params)
|
||||
|> Enum.reverse()
|
||||
end
|
||||
end
|
||||
|
||||
conn
|
||||
|> 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("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})
|
||||
end
|
||||
|
||||
|
|
|
@ -82,19 +82,6 @@ def render(
|
|||
}
|
||||
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
|
||||
user = User.get_cached_by_ap_id(activity.data["actor"])
|
||||
|
||||
|
@ -164,19 +151,6 @@ def render("status.json", %{activity: %{data: %{"object" => object}} = activity}
|
|||
}
|
||||
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
|
||||
[%{"mediaType" => media_type, "href" => href} | _] = attachment["url"]
|
||||
|
||||
|
@ -199,4 +173,30 @@ def render("attachment.json", %{attachment: attachment}) do
|
|||
type: type
|
||||
}
|
||||
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
|
||||
|
|
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(:used, :boolean, default: false)
|
||||
belongs_to(:user, Pleroma.User)
|
||||
belongs_to(:app, Pleroma.App)
|
||||
belongs_to(:app, App)
|
||||
|
||||
timestamps()
|
||||
end
|
||||
|
|
|
@ -9,7 +9,7 @@ defmodule Pleroma.Web.OAuth.Token do
|
|||
field(:refresh_token, :string)
|
||||
field(:valid_until, :naive_datetime)
|
||||
belongs_to(:user, Pleroma.User)
|
||||
belongs_to(:app, Pleroma.App)
|
||||
belongs_to(:app, App)
|
||||
|
||||
timestamps()
|
||||
end
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
defmodule Pleroma.Web.OStatus.ActivityRepresenter do
|
||||
alias Pleroma.{Activity, User, Object}
|
||||
alias Pleroma.Web.OStatus.UserRepresenter
|
||||
alias Pleroma.Formatter
|
||||
require Logger
|
||||
|
||||
defp get_href(id) do
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
defmodule Pleroma.Web.OStatus.NoteHandler do
|
||||
require Logger
|
||||
alias Pleroma.Web.{XML, OStatus}
|
||||
alias Pleroma.{Object, User, Activity}
|
||||
alias Pleroma.{Object, Activity}
|
||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||
alias Pleroma.Web.ActivityPub.Utils
|
||||
alias Pleroma.Web.CommonAPI
|
||||
|
|
|
@ -8,7 +8,6 @@ defmodule Pleroma.Web.OStatus.OStatusController do
|
|||
alias Pleroma.Web.XML
|
||||
alias Pleroma.Web.ActivityPub.ActivityPubController
|
||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||
import Ecto.Query
|
||||
|
||||
def feed_redirect(conn, %{"nickname" => nickname} = params) do
|
||||
user = User.get_cached_by_nickname(nickname)
|
||||
|
|
|
@ -295,6 +295,11 @@ def user_fetcher(username) do
|
|||
|
||||
get("/host-meta", WebFinger.WebFingerController, :host_meta)
|
||||
get("/webfinger", WebFinger.WebFingerController, :webfinger)
|
||||
get("/nodeinfo", Nodeinfo.NodeinfoController, :schemas)
|
||||
end
|
||||
|
||||
scope "/nodeinfo", Pleroma.Web do
|
||||
get("/:version", Nodeinfo.NodeinfoController, :nodeinfo)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -3,6 +3,10 @@ defmodule Pleroma.Web.Streamer do
|
|||
require Logger
|
||||
alias Pleroma.{User, Notification}
|
||||
|
||||
def init(args) do
|
||||
{:ok, args}
|
||||
end
|
||||
|
||||
def start_link do
|
||||
spawn(fn ->
|
||||
# 30 seconds
|
||||
|
@ -110,20 +114,26 @@ def handle_cast(m, state) do
|
|||
|
||||
def push_to_socket(topics, topic, item) do
|
||||
Enum.each(topics[topic] || [], fn socket ->
|
||||
json =
|
||||
%{
|
||||
event: "update",
|
||||
payload:
|
||||
Pleroma.Web.MastodonAPI.StatusView.render(
|
||||
"status.json",
|
||||
activity: item,
|
||||
for: socket.assigns[:user]
|
||||
)
|
||||
|> Jason.encode!()
|
||||
}
|
||||
|> Jason.encode!()
|
||||
# Get the current user so we have up-to-date blocks etc.
|
||||
user = User.get_cached_by_ap_id(socket.assigns[:user].ap_id)
|
||||
blocks = user.info["blocks"] || []
|
||||
|
||||
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
|
||||
|
||||
|
|
|
@ -92,7 +92,7 @@ def do_remote_follow(conn, %{
|
|||
|
||||
with %User{} = user <- User.get_cached_by_nickname(username),
|
||||
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, _activity} <- ActivityPub.follow(follower, followee) do
|
||||
conn
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
|
||||
alias Pleroma.{User, Activity, Repo, Object}
|
||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||
alias Pleroma.Web.TwitterAPI.Representers.ActivityRepresenter
|
||||
alias Pleroma.Web.TwitterAPI.UserView
|
||||
alias Pleroma.Web.{OStatus, CommonAPI}
|
||||
import Ecto.Query
|
||||
|
@ -184,7 +183,7 @@ defp parse_int(string, default) when is_binary(string) do
|
|||
|
||||
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)
|
||||
page = parse_int(params["page"], 1)
|
||||
offset = (page - 1) * limit
|
||||
|
@ -206,7 +205,7 @@ def search(user, %{"q" => query} = params) do
|
|||
order_by: [desc: :inserted_at]
|
||||
)
|
||||
|
||||
activities = Repo.all(q)
|
||||
_activities = Repo.all(q)
|
||||
end
|
||||
|
||||
defp make_date do
|
||||
|
|
|
@ -347,7 +347,8 @@ def empty_array(conn, _params) do
|
|||
def update_profile(%{assigns: %{user: user}} = conn, params) do
|
||||
params =
|
||||
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
|
||||
params
|
||||
end
|
||||
|
|
|
@ -31,7 +31,7 @@ defp query_users(user_ids) do
|
|||
end
|
||||
|
||||
defp collect_context_ids(activities) do
|
||||
contexts =
|
||||
_contexts =
|
||||
activities
|
||||
|> Enum.reject(& &1.data["context_id"])
|
||||
|> Enum.map(fn %{data: data} ->
|
||||
|
|
|
@ -2,7 +2,6 @@ defmodule Pleroma.Web.TwitterAPI.NotificationView do
|
|||
use Pleroma.Web, :view
|
||||
alias Pleroma.{Notification, User}
|
||||
alias Pleroma.Web.CommonAPI.Utils
|
||||
alias Pleroma.Web.MediaProxy
|
||||
alias Pleroma.Web.TwitterAPI.UserView
|
||||
alias Pleroma.Web.TwitterAPI.ActivityView
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
defmodule Pleroma.Web.WebFinger do
|
||||
@httpoison Application.get_env(:pleroma, :httpoison)
|
||||
|
||||
alias Pleroma.{Repo, User, XmlBuilder}
|
||||
alias Pleroma.{User, XmlBuilder}
|
||||
alias Pleroma.Web
|
||||
alias Pleroma.Web.{XML, Salmon, OStatus}
|
||||
require Jason
|
||||
|
@ -239,13 +239,14 @@ def finger(account) do
|
|||
URI.parse(account).host
|
||||
end
|
||||
|
||||
case find_lrdd_template(domain) do
|
||||
{:ok, template} ->
|
||||
address = String.replace(template, "{uri}", URI.encode(account))
|
||||
address =
|
||||
case find_lrdd_template(domain) do
|
||||
{:ok, template} ->
|
||||
String.replace(template, "{uri}", URI.encode(account))
|
||||
|
||||
_ ->
|
||||
address = "http://#{domain}/.well-known/webfinger?resource=acct:#{account}"
|
||||
end
|
||||
_ ->
|
||||
"http://#{domain}/.well-known/webfinger?resource=acct:#{account}"
|
||||
end
|
||||
|
||||
with response <-
|
||||
@httpoison.get(
|
||||
|
|
|
@ -14,7 +14,7 @@ def string_from_xpath(xpath, doc) do
|
|||
|
||||
if res == "", do: nil, else: res
|
||||
catch
|
||||
e ->
|
||||
_e ->
|
||||
Logger.debug("Couldn't find xpath #{xpath} in XML doc")
|
||||
nil
|
||||
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",
|
||||
"background": "/static/aurora_borealis.jpg",
|
||||
"logo": "/static/logo.png",
|
||||
"defaultPath": "/main/all",
|
||||
"redirectRootNoLogin": "/main/all",
|
||||
"redirectRootLogin": "/main/friends",
|
||||
"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)
|
||||
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
|
||||
|
||||
describe "get notification" do
|
||||
|
|
|
@ -26,7 +26,7 @@ def insert(data \\ %{}, opts \\ %{}) do
|
|||
end
|
||||
|
||||
def insert_list(times, data \\ %{}, opts \\ %{}) do
|
||||
Enum.map(1..times, fn n ->
|
||||
Enum.map(1..times, fn _n ->
|
||||
{:ok, activity} = insert(data, opts)
|
||||
activity
|
||||
end)
|
||||
|
|
|
@ -367,7 +367,7 @@ def get("https://shitposter.club/api/statuses/user_timeline/1.atom", _body, _hea
|
|||
|
||||
def post(
|
||||
"https://social.heldscal.la/main/push/hub",
|
||||
{:form, data},
|
||||
{:form, _data},
|
||||
"Content-type": "application/x-www-form-urlencoded"
|
||||
) do
|
||||
{:ok,
|
||||
|
@ -711,11 +711,11 @@ def get(url, body, headers) do
|
|||
}"}
|
||||
end
|
||||
|
||||
def post(url, body, headers) do
|
||||
def post(url, _body, _headers) do
|
||||
{:error, "Not implemented the mock response for post #{inspect(url)}"}
|
||||
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)}"}
|
||||
end
|
||||
end
|
||||
|
|
|
@ -63,7 +63,42 @@ test "the public timeline", %{conn: conn} do
|
|||
test "posting a status", %{conn: conn} do
|
||||
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
|
||||
|> assign(:user, user)
|
||||
|> post("/api/v1/statuses", %{
|
||||
|
@ -72,10 +107,9 @@ test "posting a status", %{conn: conn} do
|
|||
"sensitive" => "false"
|
||||
})
|
||||
|
||||
assert %{"content" => "cofe", "id" => id, "spoiler_text" => "2hu", "sensitive" => false} =
|
||||
json_response(conn, 200)
|
||||
assert %{"id" => third_id} = json_response(conn_three, 200)
|
||||
|
||||
assert Repo.get(Activity, id)
|
||||
refute id == third_id
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
test "with credentials", %{conn: conn, user: current_user} do
|
||||
other_user = insert(:user)
|
||||
|
||||
{:ok, activity} =
|
||||
ActivityBuilder.insert(%{"to" => [current_user.ap_id]}, %{user: current_user})
|
||||
ActivityBuilder.insert(%{"to" => [current_user.ap_id]}, %{user: other_user})
|
||||
|
||||
conn =
|
||||
conn
|
||||
|
@ -784,4 +786,18 @@ test "it returns the tags timeline", %{conn: conn} do
|
|||
assert status["id"] == activity.id
|
||||
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
|
||||
|
|
Loading…
Reference in a new issue