Fix merge conflict

This commit is contained in:
rinpatch 2019-01-18 18:31:25 +03:00
commit 74346a7035
39 changed files with 559 additions and 81 deletions

View file

@ -155,7 +155,9 @@ defmodule Pleroma.Formatter do
short_match = String.split(match, "@") |> tl() |> hd()
{uuid,
"<span><a data-user='#{id}' class='mention' href='#{ap_id}'>@<span>#{short_match}</span></a></span>"}
"<span class='h-card'><a data-user='#{id}' class='u-url mention' href='#{ap_id}'>@<span>#{
short_match
}</span></a></span>"}
end)
{subs, uuid_text}
@ -178,7 +180,7 @@ defmodule Pleroma.Formatter do
subs ++
Enum.map(tags, fn {tag_text, tag, uuid} ->
url =
"<a data-tag='#{tag}' href='#{Pleroma.Web.base_url()}/tag/#{tag}' rel='tag'>#{
"<a class='hashtag' data-tag='#{tag}' href='#{Pleroma.Web.base_url()}/tag/#{tag}' rel='tag'>#{
tag_text
}</a>"

View file

@ -78,14 +78,14 @@ defmodule Pleroma.HTML.Scrubber.TwitterText do
# links
Meta.allow_tag_with_uri_attributes("a", ["href", "data-user", "data-tag"], @valid_schemes)
Meta.allow_tag_with_these_attributes("a", ["name", "title"])
Meta.allow_tag_with_these_attributes("a", ["name", "title", "class"])
# paragraphs and linebreaks
Meta.allow_tag_with_these_attributes("br", [])
Meta.allow_tag_with_these_attributes("p", [])
# microformats
Meta.allow_tag_with_these_attributes("span", [])
Meta.allow_tag_with_these_attributes("span", ["class"])
# allow inline images for custom emoji
@allow_inline_images Keyword.get(@markup, :allow_inline_images)
@ -119,7 +119,7 @@ defmodule Pleroma.HTML.Scrubber.Default do
Meta.strip_comments()
Meta.allow_tag_with_uri_attributes("a", ["href", "data-user", "data-tag"], @valid_schemes)
Meta.allow_tag_with_these_attributes("a", ["name", "title"])
Meta.allow_tag_with_these_attributes("a", ["name", "title", "class"])
Meta.allow_tag_with_these_attributes("abbr", ["title"])
@ -134,7 +134,7 @@ defmodule Pleroma.HTML.Scrubber.Default do
Meta.allow_tag_with_these_attributes("ol", [])
Meta.allow_tag_with_these_attributes("p", [])
Meta.allow_tag_with_these_attributes("pre", [])
Meta.allow_tag_with_these_attributes("span", [])
Meta.allow_tag_with_these_attributes("span", ["class"])
Meta.allow_tag_with_these_attributes("strong", [])
Meta.allow_tag_with_these_attributes("u", [])
Meta.allow_tag_with_these_attributes("ul", [])

View file

@ -31,12 +31,15 @@ defmodule Pleroma.HTTP do
process_request_options(options)
|> process_sni_options(url)
params = Keyword.get(options, :params, [])
%{}
|> Builder.method(method)
|> Builder.headers(headers)
|> Builder.opts(options)
|> Builder.url(url)
|> Builder.add_param(:body, :body, body)
|> Builder.add_param(:query, :query, params)
|> Enum.into([])
|> (&Tesla.request(Connection.new(), &1)).()
end

View file

@ -100,6 +100,8 @@ defmodule Pleroma.HTTP.RequestBuilder do
Map
"""
@spec add_param(map(), atom, atom, any()) :: map()
def add_param(request, :query, :query, values), do: Map.put(request, :query, values)
def add_param(request, :body, :body, value), do: Map.put(request, :body, value)
def add_param(request, :body, key, value) do
@ -107,7 +109,10 @@ defmodule Pleroma.HTTP.RequestBuilder do
|> Map.put_new_lazy(:body, &Tesla.Multipart.new/0)
|> Map.update!(
:body,
&Tesla.Multipart.add_field(&1, key, Poison.encode!(value),
&Tesla.Multipart.add_field(
&1,
key,
Jason.encode!(value),
headers: [{:"Content-Type", "application/json"}]
)
)

View file

@ -34,10 +34,11 @@ defmodule Pleroma.Stats do
peers =
from(
u in Pleroma.User,
select: fragment("distinct ?->'host'", u.info),
select: fragment("distinct split_part(?, '@', 2)", u.nickname),
where: u.local != ^true
)
|> Repo.all()
|> Enum.filter(& &1)
domain_count = Enum.count(peers)
@ -45,7 +46,7 @@ defmodule Pleroma.Stats do
from(u in User.local_user_query(), select: fragment("sum((?->>'note_count')::int)", u.info))
status_count = Repo.one(status_query)
user_count = Repo.aggregate(User.local_user_query(), :count, :id)
user_count = Repo.aggregate(User.active_local_user_query(), :count, :id)
Agent.update(__MODULE__, fn _ ->
{peers, %{domain_count: domain_count, status_count: status_count, user_count: user_count}}

View file

@ -34,8 +34,9 @@ defmodule Pleroma.Upload do
require Logger
@type source ::
Plug.Upload.t() | data_uri_string ::
String.t() | {:from_local, name :: String.t(), id :: String.t(), path :: String.t()}
Plug.Upload.t()
| (data_uri_string :: String.t())
| {:from_local, name :: String.t(), id :: String.t(), path :: String.t()}
@type option ::
{:type, :avatar | :banner | :background}
@ -215,6 +216,12 @@ defmodule Pleroma.Upload do
end
defp url_from_spec(base_url, {:file, path}) do
path =
path
|> URI.encode()
|> String.replace("?", "%3F")
|> String.replace(":", "%3A")
[base_url, "media", path]
|> Path.join()
end

View file

@ -822,7 +822,7 @@ defmodule Pleroma.User do
update_and_set_cache(cng)
end
def local_user_query() do
def local_user_query do
from(
u in User,
where: u.local == true,
@ -830,7 +830,14 @@ defmodule Pleroma.User do
)
end
def moderator_user_query() do
def active_local_user_query do
from(
u in local_user_query(),
where: fragment("?->'deactivated' @> 'false'", u.info)
)
end
def moderator_user_query do
from(
u in User,
where: u.local == true,
@ -1066,4 +1073,14 @@ defmodule Pleroma.User do
@strict_local_nickname_regex
end
end
def error_user(ap_id) do
%User{
name: ap_id,
ap_id: ap_id,
info: %User.Info{},
nickname: "erroruser@example.com",
inserted_at: NaiveDateTime.utc_now()
}
end
end

View file

@ -515,15 +515,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
defp restrict_reblogs(query, _), do: query
# Only search through last 100_000 activities by default
defp restrict_recent(query, %{"whole_db" => true}), do: query
defp restrict_recent(query, _) do
since = (Repo.aggregate(Activity, :max, :id) || 0) - 100_000
from(activity in query, where: activity.id > ^since)
end
defp restrict_blocked(query, %{"blocking_user" => %User{info: info}}) do
blocks = info.blocks || []
domain_blocks = info.domain_blocks || []
@ -574,7 +565,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|> restrict_actor(opts)
|> restrict_type(opts)
|> restrict_favorited_by(opts)
|> restrict_recent(opts)
|> restrict_blocked(opts)
|> restrict_media(opts)
|> restrict_visibility(opts)

View file

@ -54,6 +54,36 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
end
end
def object_likes(conn, %{"uuid" => uuid, "page" => page}) do
with ap_id <- o_status_url(conn, :object, uuid),
%Object{} = object <- Object.get_cached_by_ap_id(ap_id),
{_, true} <- {:public?, ActivityPub.is_public?(object)},
likes <- Utils.get_object_likes(object) do
{page, _} = Integer.parse(page)
conn
|> put_resp_header("content-type", "application/activity+json")
|> json(ObjectView.render("likes.json", ap_id, likes, page))
else
{:public?, false} ->
{:error, :not_found}
end
end
def object_likes(conn, %{"uuid" => uuid}) do
with ap_id <- o_status_url(conn, :object, uuid),
%Object{} = object <- Object.get_cached_by_ap_id(ap_id),
{_, true} <- {:public?, ActivityPub.is_public?(object)},
likes <- Utils.get_object_likes(object) do
conn
|> put_resp_header("content-type", "application/activity+json")
|> json(ObjectView.render("likes.json", ap_id, likes))
else
{:public?, false} ->
{:error, :not_found}
end
end
def activity(conn, %{"uuid" => uuid}) do
with ap_id <- o_status_url(conn, :activity, uuid),
%Activity{} = activity <- Activity.normalize(ap_id),
@ -204,6 +234,15 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
end
end
def handle_user_activity(user, %{"type" => "Like"} = params) do
with %Object{} = object <- Object.normalize(params["object"]),
{:ok, activity, _object} <- ActivityPub.like(user, object) do
{:ok, activity}
else
_ -> {:error, "Can't like object"}
end
end
def handle_user_activity(_, _) do
{:error, "Unhandled activity type"}
end

View file

@ -0,0 +1,29 @@
# Pleroma: A lightweight social networking server
# Copyright © 2019 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.MRF.NoPlaceholderTextPolicy do
@behaviour Pleroma.Web.ActivityPub.MRF
@impl true
def filter(
%{
"type" => "Create",
"object" => %{"content" => content, "attachment" => _attachment} = child_object
} = object
)
when content in [".", "<p>.</p>"] do
child_object =
child_object
|> Map.put("content", "")
object =
object
|> Map.put("object", child_object)
{:ok, object}
end
@impl true
def filter(object), do: {:ok, object}
end

View file

@ -629,6 +629,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|> add_mention_tags
|> add_emoji_tags
|> add_attributed_to
|> add_likes
|> prepare_attachments
|> set_conversation
|> set_reply_to_uri
@ -641,7 +642,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
# internal -> Mastodon
# """
def prepare_outgoing(%{"type" => "Create", "object" => %{"type" => "Note"} = object} = data) do
def prepare_outgoing(%{"type" => "Create", "object" => object} = data) do
object =
object
|> prepare_object
@ -788,6 +789,22 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|> Map.put("attributedTo", attributedTo)
end
def add_likes(%{"id" => id, "like_count" => likes} = object) do
likes = %{
"id" => "#{id}/likes",
"first" => "#{id}/likes?page=1",
"type" => "OrderedCollection",
"totalItems" => likes
}
object
|> Map.put("likes", likes)
end
def add_likes(object) do
object
end
def prepare_attachments(object) do
attachments =
(object["attachment"] || [])
@ -803,7 +820,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
defp strip_internal_fields(object) do
object
|> Map.drop([
"likes",
"like_count",
"announcements",
"announcement_count",

View file

@ -231,6 +231,27 @@ defmodule Pleroma.Web.ActivityPub.Utils do
Repo.one(query)
end
@doc """
Returns like activities targeting an object
"""
def get_object_likes(%{data: %{"id" => id}}) do
query =
from(
activity in Activity,
# this is to use the index
where:
fragment(
"coalesce((?)->'object'->>'id', (?)->>'object') = ?",
activity.data,
activity.data,
^id
),
where: fragment("(?)->>'type' = 'Like'", activity.data)
)
Repo.all(query)
end
def make_like_data(%User{ap_id: ap_id} = actor, %{data: %{"id" => id}} = object, activity_id) do
data = %{
"type" => "Like",

View file

@ -35,4 +35,38 @@ defmodule Pleroma.Web.ActivityPub.ObjectView do
Map.merge(base, additional)
end
def render("likes.json", ap_id, likes, page) do
collection(likes, "#{ap_id}/likes", page)
|> Map.merge(Pleroma.Web.ActivityPub.Utils.make_json_ld_header())
end
def render("likes.json", ap_id, likes) do
%{
"id" => "#{ap_id}/likes",
"type" => "OrderedCollection",
"totalItems" => length(likes),
"first" => collection(likes, "#{ap_id}/likes", 1)
}
|> Map.merge(Pleroma.Web.ActivityPub.Utils.make_json_ld_header())
end
def collection(collection, iri, page) do
offset = (page - 1) * 10
items = Enum.slice(collection, offset, 10)
items = Enum.map(items, fn object -> Transmogrifier.prepare_object(object.data) end)
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

View file

@ -103,7 +103,14 @@ defmodule Pleroma.Web.CommonAPI do
attachments,
tags,
get_content_type(data["content_type"]),
true
Enum.member?(
[true, "true"],
Map.get(
data,
"no_attachment_links",
Pleroma.Config.get([:instance, :no_attachment_links], false)
)
)
),
context <- make_context(inReplyTo),
cw <- data["spoiler_text"],

View file

@ -341,7 +341,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
params =
params
|> Map.put("in_reply_to_status_id", params["in_reply_to_id"])
|> Map.put("no_attachment_links", true)
idempotency_key =
case get_req_header(conn, "idempotency-key") do
@ -824,9 +823,9 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
json(conn, res)
end
def favourites(%{assigns: %{user: user}} = conn, _) do
def favourites(%{assigns: %{user: user}} = conn, params) do
params =
%{}
params
|> Map.put("type", "Create")
|> Map.put("favorited_by", user.ap_id)
|> Map.put("blocking_user", user)
@ -836,6 +835,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|> Enum.reverse()
conn
|> add_link_headers(:favourites, activities)
|> put_view(StatusView)
|> render("index.json", %{activities: activities, for: user, as: :activity})
end

View file

@ -32,6 +32,19 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
end)
end
defp get_user(ap_id) do
cond do
user = User.get_cached_by_ap_id(ap_id) ->
user
user = User.get_by_guessed_nickname(ap_id) ->
user
true ->
User.error_user(ap_id)
end
end
def render("index.json", opts) do
replied_to_activities = get_replied_to_activities(opts.activities)
@ -48,7 +61,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
"status.json",
%{activity: %{data: %{"type" => "Announce", "object" => object}} = activity} = opts
) do
user = User.get_cached_by_ap_id(activity.data["actor"])
user = get_user(activity.data["actor"])
created_at = Utils.to_masto_date(activity.data["published"])
reblogged = Activity.get_create_activity_by_object_ap_id(object)
@ -93,7 +106,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
end
def render("status.json", %{activity: %{data: %{"object" => object}} = activity} = opts) do
user = User.get_cached_by_ap_id(activity.data["actor"])
user = get_user(activity.data["actor"])
like_count = object["like_count"] || 0
announcement_count = object["announcement_count"] || 0
@ -116,7 +129,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
created_at = Utils.to_masto_date(object["published"])
reply_to = get_reply_to(activity, opts)
reply_to_user = reply_to && User.get_cached_by_ap_id(reply_to.data["actor"])
reply_to_user = reply_to && get_user(reply_to.data["actor"])
content =
object

View file

@ -1,5 +1,9 @@
defmodule Pleroma.Web.RichMedia.Parser do
@parsers [Pleroma.Web.RichMedia.Parsers.OGP, Pleroma.Web.RichMedia.Parsers.TwitterCard]
@parsers [
Pleroma.Web.RichMedia.Parsers.OGP,
Pleroma.Web.RichMedia.Parsers.TwitterCard,
Pleroma.Web.RichMedia.Parsers.OEmbed
]
if Mix.env() == :test do
def parse(url), do: parse_url(url)

View file

@ -0,0 +1,27 @@
defmodule Pleroma.Web.RichMedia.Parsers.OEmbed do
def parse(html, _data) do
with elements = [_ | _] <- get_discovery_data(html),
{:ok, oembed_url} <- get_oembed_url(elements),
{:ok, oembed_data} <- get_oembed_data(oembed_url) do
{:ok, oembed_data}
else
_e -> {:error, "No OEmbed data found"}
end
end
defp get_discovery_data(html) do
html |> Floki.find("link[type='application/json+oembed']")
end
defp get_oembed_url(nodes) do
{"link", attributes, _children} = nodes |> hd()
{:ok, Enum.into(attributes, %{})["href"]}
end
defp get_oembed_data(url) do
{:ok, %Tesla.Env{body: json}} = Pleroma.HTTP.get(url)
{:ok, Poison.decode!(json)}
end
end

View file

@ -431,6 +431,7 @@ defmodule Pleroma.Web.Router do
get("/users/:nickname/followers", ActivityPubController, :followers)
get("/users/:nickname/following", ActivityPubController, :following)
get("/users/:nickname/outbox", ActivityPubController, :outbox)
get("/objects/:uuid/likes", ActivityPubController, :object_likes)
end
pipeline :activitypub_client do

View file

@ -101,20 +101,10 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do
user
true ->
error_user(ap_id)
User.error_user(ap_id)
end
end
defp error_user(ap_id) do
%User{
name: ap_id,
ap_id: ap_id,
info: %User.Info{},
nickname: "erroruser@example.com",
inserted_at: NaiveDateTime.utc_now()
}
end
def render("index.json", opts) do
context_ids = collect_context_ids(opts.activities)
users = collect_users(opts.activities)

View file

@ -121,6 +121,12 @@ defmodule Pleroma.Web.Websub do
end
end
def incoming_subscription_request(user, params) do
Logger.info("Unhandled WebSub request for #{user.nickname}: #{inspect(params)}")
{:error, "Invalid WebSub request"}
end
defp get_subscription(topic, callback) do
Repo.get_by(WebsubServerSubscription, topic: topic, callback: callback) ||
%WebsubServerSubscription{}

View file

@ -67,6 +67,13 @@ defmodule Pleroma.Web.Websub.WebsubController do
end
end
def websub_subscription_confirmation(conn, params) do
Logger.info("Invalid WebSub confirmation request: #{inspect(params)}")
conn
|> send_resp(500, "Invalid parameters")
end
def websub_incoming(conn, %{"id" => id}) do
with "sha1=" <> signature <- hd(get_req_header(conn, "x-hub-signature")),
signature <- String.downcase(signature),