Merge remote-tracking branch 'remotes/origin/develop' into feature/object-hashtags-rework

This commit is contained in:
Ivan Tashkinov 2021-03-02 08:26:30 +03:00
commit 882dd46843
146 changed files with 1354 additions and 272 deletions

View file

@ -20,7 +20,8 @@ defmodule Mix.Tasks.Pleroma.Ecto.Rollback do
start: :boolean,
quiet: :boolean,
log_sql: :boolean,
migrations_path: :string
migrations_path: :string,
env: :string
]
@moduledoc """
@ -59,7 +60,7 @@ defmodule Mix.Tasks.Pleroma.Ecto.Rollback do
level = Logger.level()
Logger.configure(level: :info)
if Pleroma.Config.get(:env) == :test do
if opts[:env] == "test" do
Logger.info("Rollback succesfully")
else
{:ok, _, _} =

View file

@ -18,7 +18,8 @@ defmodule Pleroma.Constants do
"emoji",
"context_id",
"deleted_activity_id",
"pleroma_internal"
"pleroma_internal",
"generator"
]
)

View file

@ -23,7 +23,11 @@ defmodule Pleroma.Stats do
@impl true
def init(_args) do
{:ok, nil, {:continue, :calculate_stats}}
if Pleroma.Config.get(:env) != :test do
{:ok, nil, {:continue, :calculate_stats}}
else
{:ok, calculate_stat_data()}
end
end
@doc "Performs update stats"

View file

@ -147,6 +147,7 @@ defmodule Pleroma.User do
field(:shared_inbox, :string)
field(:accepts_chat_messages, :boolean, default: nil)
field(:last_active_at, :naive_datetime)
field(:disclose_client, :boolean, default: true)
embeds_one(
:notification_settings,
@ -513,7 +514,8 @@ defmodule Pleroma.User do
:pleroma_settings_store,
:is_discoverable,
:actor_type,
:accepts_chat_messages
:accepts_chat_messages,
:disclose_client
]
)
|> unique_constraint(:nickname)

View file

@ -63,7 +63,8 @@ defmodule Pleroma.Web do
# Executed just before actual controller action, invokes before-action hooks (callbacks)
defp action(conn, params) do
with %{halted: false} = conn <- maybe_drop_authentication_if_oauth_check_ignored(conn),
with %{halted: false} = conn <-
maybe_drop_authentication_if_oauth_check_ignored(conn),
%{halted: false} = conn <- maybe_perform_public_or_authenticated_check(conn),
%{halted: false} = conn <- maybe_perform_authenticated_check(conn),
%{halted: false} = conn <- maybe_halt_on_missing_oauth_scopes_check(conn) do
@ -232,4 +233,16 @@ defmodule Pleroma.Web do
def base_url do
Pleroma.Web.Endpoint.url()
end
# TODO: Change to Phoenix.Router.routes/1 for Phoenix 1.6.0+
def get_api_routes do
Pleroma.Web.Router.__routes__()
|> Enum.reject(fn r -> r.plug == Pleroma.Web.Fallback.RedirectController end)
|> Enum.map(fn r ->
r.path
|> String.split("/", trim: true)
|> List.first()
end)
|> Enum.uniq()
end
end

View file

@ -70,19 +70,33 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AudioVideoValidator do
|> changeset(data)
end
defp fix_url(%{"url" => url} = data) when is_list(url) do
attachment =
Enum.find(url, fn x ->
mime_type = x["mimeType"] || x["mediaType"] || ""
defp find_attachment(url) do
mpeg_url =
Enum.find(url, fn
%{"mediaType" => mime_type, "tag" => tags} when is_list(tags) ->
mime_type == "application/x-mpegURL"
is_map(x) and String.starts_with?(mime_type, ["video/", "audio/"])
_ ->
false
end)
link_element =
Enum.find(url, fn x ->
mime_type = x["mimeType"] || x["mediaType"] || ""
url
|> Enum.concat(mpeg_url["tag"] || [])
|> Enum.find(fn
%{"mediaType" => mime_type} -> String.starts_with?(mime_type, ["video/", "audio/"])
%{"mimeType" => mime_type} -> String.starts_with?(mime_type, ["video/", "audio/"])
_ -> false
end)
end
is_map(x) and mime_type == "text/html"
defp fix_url(%{"url" => url} = data) when is_list(url) do
attachment = find_attachment(url)
link_element =
Enum.find(url, fn
%{"mediaType" => "text/html"} -> true
%{"mimeType" => "text/html"} -> true
_ -> false
end)
data

View file

@ -136,11 +136,11 @@ defmodule Pleroma.Web.ApiSpec.Admin.ReportOperation do
}
end
defp report_state do
def report_state do
%Schema{type: :string, enum: ["open", "closed", "resolved"]}
end
defp id_param do
def id_param do
Operation.parameter(:id, :path, FlakeID, "Report ID",
example: "9umDrYheeY451cQnEe",
required: true

View file

@ -0,0 +1,97 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ApiSpec.PleromaReportOperation do
alias OpenApiSpex.Operation
alias OpenApiSpex.Schema
alias Pleroma.Web.ApiSpec.Admin.ReportOperation
alias Pleroma.Web.ApiSpec.Schemas.Account
alias Pleroma.Web.ApiSpec.Schemas.ApiError
alias Pleroma.Web.ApiSpec.Schemas.FlakeID
alias Pleroma.Web.ApiSpec.Schemas.Status
def open_api_operation(action) do
operation = String.to_existing_atom("#{action}_operation")
apply(__MODULE__, operation, [])
end
def index_operation do
%Operation{
tags: ["Reports"],
summary: "Get a list of your own reports",
operationId: "PleromaAPI.ReportController.index",
security: [%{"oAuth" => ["read:reports"]}],
parameters: [
Operation.parameter(
:state,
:query,
ReportOperation.report_state(),
"Filter by report state"
),
Operation.parameter(
:limit,
:query,
%Schema{type: :integer},
"The number of records to retrieve"
),
Operation.parameter(
:page,
:query,
%Schema{type: :integer, default: 1},
"Page number"
),
Operation.parameter(
:page_size,
:query,
%Schema{type: :integer, default: 50},
"Number number of log entries per page"
)
],
responses: %{
200 =>
Operation.response("Response", "application/json", %Schema{
type: :object,
properties: %{
total: %Schema{type: :integer},
reports: %Schema{
type: :array,
items: report()
}
}
}),
404 => Operation.response("Not Found", "application/json", ApiError)
}
}
end
def show_operation do
%Operation{
tags: ["Reports"],
summary: "Get an individual report",
operationId: "PleromaAPI.ReportController.show",
parameters: [ReportOperation.id_param()],
security: [%{"oAuth" => ["read:reports"]}],
responses: %{
200 => Operation.response("Report", "application/json", report()),
404 => Operation.response("Not Found", "application/json", ApiError)
}
}
end
# Copied from ReportOperation.report with removing notes
defp report do
%Schema{
type: :object,
properties: %{
id: FlakeID,
state: ReportOperation.report_state(),
account: Account,
actor: Account,
content: %Schema{type: :string},
created_at: %Schema{type: :string, format: :"date-time"},
statuses: %Schema{type: :array, items: Status}
}
}
end
end

View file

@ -30,7 +30,8 @@ defmodule Pleroma.Web.ApiSpec.Schemas.ScheduledStatus do
visibility: %Schema{allOf: [VisibilityScope], nullable: true},
scheduled_at: %Schema{type: :string, format: :"date-time", nullable: true},
poll: StatusOperation.poll_params(),
in_reply_to_id: %Schema{type: :string, nullable: true}
in_reply_to_id: %Schema{type: :string, nullable: true},
expires_in: %Schema{type: :integer, nullable: true}
}
}
},
@ -46,7 +47,8 @@ defmodule Pleroma.Web.ApiSpec.Schemas.ScheduledStatus do
scheduled_at: nil,
poll: nil,
idempotency: nil,
in_reply_to_id: nil
in_reply_to_id: nil,
expires_in: nil
},
media_attachments: [Attachment.schema().example]
}

View file

@ -23,9 +23,10 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Status do
application: %Schema{
description: "The application used to post this status",
type: :object,
nullable: true,
properties: %{
name: %Schema{type: :string},
website: %Schema{type: :string, nullable: true, format: :uri}
website: %Schema{type: :string, format: :uri}
}
},
bookmarked: %Schema{type: :boolean, description: "Have you bookmarked this status?"},
@ -291,7 +292,7 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Status do
"url" => "http://localhost:4001/users/nick6",
"username" => "nick6"
},
"application" => %{"name" => "Web", "website" => nil},
"application" => nil,
"bookmarked" => false,
"card" => nil,
"content" => "foobar",

View file

@ -190,6 +190,7 @@ defmodule Pleroma.Web.CommonAPI.ActivityDraft do
Utils.make_note_data(draft)
|> Map.put("emoji", emoji)
|> Map.put("source", draft.status)
|> Map.put("generator", draft.params[:generator])
%__MODULE__{draft | object: object}
end

View file

@ -0,0 +1,26 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Fallback.LegacyPleromaApiRerouterPlug do
alias Pleroma.Web.Endpoint
alias Pleroma.Web.Fallback.RedirectController
def init(opts), do: opts
def call(%{path_info: ["api", "pleroma" | path_info_rest]} = conn, _opts) do
new_path_info = ["api", "v1", "pleroma" | path_info_rest]
new_request_path = Enum.join(new_path_info, "/")
conn
|> Map.merge(%{
path_info: new_path_info,
request_path: new_request_path
})
|> Endpoint.call(conn.params)
end
def call(conn, _opts) do
RedirectController.api_not_implemented(conn, %{})
end
end

View file

@ -21,6 +21,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
alias Pleroma.Web.CommonAPI
alias Pleroma.Web.MastodonAPI.AccountView
alias Pleroma.Web.MastodonAPI.ScheduledActivityView
alias Pleroma.Web.OAuth.Token
alias Pleroma.Web.Plugs.OAuthScopesPlug
alias Pleroma.Web.Plugs.RateLimiter
@ -138,7 +139,9 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
_
)
when not is_nil(scheduled_at) do
params = Map.put(params, :in_reply_to_status_id, params[:in_reply_to_id])
params =
Map.put(params, :in_reply_to_status_id, params[:in_reply_to_id])
|> put_application(conn)
attrs = %{
params: Map.new(params, fn {key, value} -> {to_string(key), value} end),
@ -162,7 +165,9 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
# Creates a regular status
def create(%{assigns: %{user: user}, body_params: %{status: _} = params} = conn, _) do
params = Map.put(params, :in_reply_to_status_id, params[:in_reply_to_id])
params =
Map.put(params, :in_reply_to_status_id, params[:in_reply_to_id])
|> put_application(conn)
with {:ok, activity} <- CommonAPI.post(user, params) do
try_render(conn, "show.json",
@ -414,4 +419,15 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
as: :activity
)
end
defp put_application(params, %{assigns: %{token: %Token{user: %User{} = user} = token}} = _conn) do
if user.disclose_client do
%{client_name: client_name, website: website} = Repo.preload(token, :app).app
Map.put(params, :generator, %{type: "Application", name: client_name, url: website})
else
Map.put(params, :generator, nil)
end
end
defp put_application(params, _), do: Map.put(params, :generator, nil)
end

View file

@ -37,7 +37,8 @@ defmodule Pleroma.Web.MastodonAPI.ScheduledActivityView do
visibility: params["visibility"],
scheduled_at: params["scheduled_at"],
poll: params["poll"],
in_reply_to_id: params["in_reply_to_id"]
in_reply_to_id: params["in_reply_to_id"],
expires_in: params["expires_in"]
}
|> Pleroma.Maps.put_if_present(:media_ids, params["media_ids"])
end

View file

@ -180,10 +180,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
media_attachments: reblogged[:media_attachments] || [],
mentions: mentions,
tags: reblogged[:tags] || [],
application: %{
name: "Web",
website: nil
},
application: build_application(activity_object.data["generator"]),
language: nil,
emojis: [],
pleroma: %{
@ -350,10 +347,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
poll: render(PollView, "show.json", object: object, for: opts[:for]),
mentions: mentions,
tags: build_tags(tags),
application: %{
name: "Web",
website: nil
},
application: build_application(object.data["generator"]),
language: nil,
emojis: build_emojis(object.data["emoji"]),
pleroma: %{
@ -542,4 +536,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
me: !!(current_user && current_user.ap_id in users)
}
end
@spec build_application(map() | nil) :: map() | nil
defp build_application(%{type: _type, name: name, url: url}), do: %{name: name, website: url}
defp build_application(_), do: nil
end

View file

@ -0,0 +1,46 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.PleromaAPI.ReportController do
use Pleroma.Web, :controller
alias Pleroma.Activity
alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.AdminAPI.Report
action_fallback(Pleroma.Web.MastodonAPI.FallbackController)
plug(Pleroma.Web.ApiSpec.CastAndValidate)
plug(Pleroma.Web.Plugs.OAuthScopesPlug, %{scopes: ["read:reports"]})
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.PleromaReportOperation
@doc "GET /api/v0/pleroma/reports"
def index(%{assigns: %{user: user}, body_params: params} = conn, _) do
params =
params
|> Map.put(:actor_id, user.ap_id)
reports = Utils.get_reports(params, Map.get(params, :page, 1), Map.get(params, :size, 20))
render(conn, "index.json", %{reports: reports, for: user})
end
@doc "GET /api/v0/pleroma/reports/:id"
def show(%{assigns: %{user: user}} = conn, %{id: id}) do
with %Activity{} = report <- Activity.get_report(id),
true <- report.actor == user.ap_id,
%{} = report_info <- Report.extract_report_info(report) do
render(conn, "show.json", Map.put(report_info, :for, user))
else
false ->
{:error, :not_found}
nil ->
{:error, :not_found}
e ->
{:error, inspect(e)}
end
end
end

View file

@ -0,0 +1,55 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.PleromaAPI.ReportView do
use Pleroma.Web, :view
alias Pleroma.HTML
alias Pleroma.Web.AdminAPI.Report
alias Pleroma.Web.CommonAPI.Utils
alias Pleroma.Web.MastodonAPI.AccountView
alias Pleroma.Web.MastodonAPI.StatusView
def render("index.json", %{reports: reports, for: for_user}) do
%{
reports:
reports[:items]
|> Enum.map(&Report.extract_report_info/1)
|> Enum.map(&render(__MODULE__, "show.json", Map.put(&1, :for, for_user))),
total: reports[:total]
}
end
def render("show.json", %{
report: report,
user: actor,
account: account,
statuses: statuses,
for: for_user
}) do
created_at = Utils.to_masto_date(report.data["published"])
content =
unless is_nil(report.data["content"]) do
HTML.filter_tags(report.data["content"])
else
nil
end
%{
id: report.id,
account: AccountView.render("show.json", %{user: account, for: for_user}),
actor: AccountView.render("show.json", %{user: actor, for: for_user}),
content: content,
created_at: created_at,
statuses:
StatusView.render("index.json", %{
activities: statuses,
as: :activity,
for: for_user
}),
state: report.data["state"]
}
end
end

View file

@ -10,6 +10,8 @@ defmodule Pleroma.Web.Plugs.FrontendStatic do
"""
@behaviour Plug
@api_routes Pleroma.Web.get_api_routes()
def file_path(path, frontend_type \\ :primary) do
if configuration = Pleroma.Config.get([:frontends, frontend_type]) do
instance_static_path = Pleroma.Config.get([:instance, :static_dir], "instance/static")
@ -34,7 +36,8 @@ defmodule Pleroma.Web.Plugs.FrontendStatic do
end
def call(conn, opts) do
with false <- invalid_path?(conn.path_info),
with false <- api_route?(conn.path_info),
false <- invalid_path?(conn.path_info),
frontend_type <- Map.get(opts, :frontend_type, :primary),
path when not is_nil(path) <- file_path("", frontend_type) do
call_static(conn, opts, path)
@ -52,6 +55,10 @@ defmodule Pleroma.Web.Plugs.FrontendStatic do
defp invalid_path?([h | t], match), do: String.contains?(h, match) or invalid_path?(t)
defp invalid_path?([], _match), do: false
defp api_route?([h | _]) when h in @api_routes, do: true
defp api_route?([_ | t]), do: api_route?(t)
defp api_route?([]), do: false
defp call_static(conn, opts, from) do
opts = Map.put(opts, :from, from)
Plug.Static.call(conn, opts)

View file

@ -140,7 +140,7 @@ defmodule Pleroma.Web.Router do
plug(Pleroma.Web.Plugs.MappedSignatureToIdentityPlug)
end
scope "/api/pleroma", Pleroma.Web.TwitterAPI do
scope "/api/v1/pleroma", Pleroma.Web.TwitterAPI do
pipe_through(:pleroma_api)
get("/password_reset/:token", PasswordController, :reset, as: :reset_password)
@ -150,12 +150,12 @@ defmodule Pleroma.Web.Router do
get("/healthcheck", UtilController, :healthcheck)
end
scope "/api/pleroma", Pleroma.Web do
scope "/api/v1/pleroma", Pleroma.Web do
pipe_through(:pleroma_api)
post("/uploader_callback/:upload_path", UploaderController, :callback)
end
scope "/api/pleroma/admin", Pleroma.Web.AdminAPI do
scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do
pipe_through(:admin_api)
put("/users/disable_mfa", AdminAPIController, :disable_mfa)
@ -259,7 +259,7 @@ defmodule Pleroma.Web.Router do
post("/backups", AdminAPIController, :create_backup)
end
scope "/api/pleroma/emoji", Pleroma.Web.PleromaAPI do
scope "/api/v1/pleroma/emoji", Pleroma.Web.PleromaAPI do
scope "/pack" do
pipe_through(:admin_api)
@ -368,6 +368,12 @@ defmodule Pleroma.Web.Router do
get("/statuses/:id/reactions", EmojiReactionController, :index)
end
scope "/api/v0/pleroma", Pleroma.Web.PleromaAPI do
pipe_through(:authenticated_api)
get("/reports", ReportController, :index)
get("/reports/:id", ReportController, :show)
end
scope "/api/v1/pleroma", Pleroma.Web.PleromaAPI do
scope [] do
pipe_through(:authenticated_api)
@ -809,6 +815,7 @@ defmodule Pleroma.Web.Router do
scope "/", Pleroma.Web.Fallback do
get("/registration/:token", RedirectController, :registration_page)
get("/:maybe_nickname_or_id", RedirectController, :redirector_with_meta)
match(:*, "/api/pleroma*path", LegacyPleromaApiRerouterPlug, [])
get("/api*path", RedirectController, :api_not_implemented)
get("/*path", RedirectController, :redirector_with_preload)