Merge remote-tracking branch 'remotes/origin/develop' into feature/object-hashtags-rework
# Conflicts: # CHANGELOG.md # lib/pleroma/web/activity_pub/activity_pub.ex
This commit is contained in:
commit
4e14945670
130 changed files with 923 additions and 175 deletions
|
|
@ -242,6 +242,13 @@ defmodule Mix.Tasks.Pleroma.Instance do
|
|||
rum_enabled: rum_enabled
|
||||
)
|
||||
|
||||
config_dir = Path.dirname(config_path)
|
||||
psql_dir = Path.dirname(psql_path)
|
||||
|
||||
[config_dir, psql_dir, static_dir, uploads_dir]
|
||||
|> Enum.reject(&File.exists?/1)
|
||||
|> Enum.map(&File.mkdir_p!/1)
|
||||
|
||||
shell_info("Writing config to #{config_path}.")
|
||||
|
||||
File.write(config_path, result_config)
|
||||
|
|
@ -275,10 +282,6 @@ defmodule Mix.Tasks.Pleroma.Instance do
|
|||
indexable: indexable
|
||||
)
|
||||
|
||||
unless File.exists?(static_dir) do
|
||||
File.mkdir_p!(static_dir)
|
||||
end
|
||||
|
||||
robots_txt_path = Path.join(static_dir, "robots.txt")
|
||||
|
||||
if File.exists?(robots_txt_path) do
|
||||
|
|
|
|||
|
|
@ -146,6 +146,7 @@ defmodule Pleroma.User do
|
|||
field(:inbox, :string)
|
||||
field(:shared_inbox, :string)
|
||||
field(:accepts_chat_messages, :boolean, default: nil)
|
||||
field(:last_active_at, :naive_datetime)
|
||||
|
||||
embeds_one(
|
||||
:notification_settings,
|
||||
|
|
@ -2030,6 +2031,15 @@ defmodule Pleroma.User do
|
|||
|> hd()
|
||||
end
|
||||
|
||||
def full_nickname(%User{} = user) do
|
||||
if String.contains?(user.nickname, "@") do
|
||||
user.nickname
|
||||
else
|
||||
%{host: host} = URI.parse(user.ap_id)
|
||||
user.nickname <> "@" <> host
|
||||
end
|
||||
end
|
||||
|
||||
def full_nickname(nickname_or_mention),
|
||||
do: String.trim_leading(nickname_or_mention, "@")
|
||||
|
||||
|
|
@ -2444,4 +2454,19 @@ defmodule Pleroma.User do
|
|||
def get_host(%User{ap_id: ap_id} = _user) do
|
||||
URI.parse(ap_id).host
|
||||
end
|
||||
|
||||
def update_last_active_at(%__MODULE__{local: true} = user) do
|
||||
user
|
||||
|> cast(%{last_active_at: NaiveDateTime.utc_now()}, [:last_active_at])
|
||||
|> update_and_set_cache()
|
||||
end
|
||||
|
||||
def active_user_count(weeks \\ 4) do
|
||||
active_after = Timex.shift(NaiveDateTime.utc_now(), weeks: -weeks)
|
||||
|
||||
__MODULE__
|
||||
|> where([u], u.last_active_at >= ^active_after)
|
||||
|> where([u], u.local == true)
|
||||
|> Repo.aggregate(:count)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -824,6 +824,12 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
|
||||
defp restrict_local(query, _), do: query
|
||||
|
||||
defp restrict_remote(query, %{remote: true}) do
|
||||
from(activity in query, where: activity.local == false)
|
||||
end
|
||||
|
||||
defp restrict_remote(query, _), do: query
|
||||
|
||||
defp restrict_actor(query, %{actor_id: actor_id}) do
|
||||
from(activity in query, where: activity.actor == ^actor_id)
|
||||
end
|
||||
|
|
@ -1198,6 +1204,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
|> restrict_replies(opts)
|
||||
|> restrict_since(opts)
|
||||
|> restrict_local(opts)
|
||||
|> restrict_remote(opts)
|
||||
|> restrict_actor(opts)
|
||||
|> restrict_type(opts)
|
||||
|> restrict_state(opts)
|
||||
|
|
|
|||
|
|
@ -99,7 +99,10 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
|
|||
summary: "Account",
|
||||
operationId: "AccountController.show",
|
||||
description: "View information about a profile.",
|
||||
parameters: [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}],
|
||||
parameters: [
|
||||
%Reference{"$ref": "#/components/parameters/accountIdOrNickname"},
|
||||
with_relationships_param()
|
||||
],
|
||||
responses: %{
|
||||
200 => Operation.response("Account", "application/json", Account),
|
||||
401 => Operation.response("Error", "application/json", ApiError),
|
||||
|
|
@ -130,7 +133,7 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
|
|||
:with_muted,
|
||||
:query,
|
||||
BooleanLike,
|
||||
"Include statuses from muted acccounts."
|
||||
"Include statuses from muted accounts."
|
||||
),
|
||||
Operation.parameter(:exclude_reblogs, :query, BooleanLike, "Exclude reblogs"),
|
||||
Operation.parameter(:exclude_replies, :query, BooleanLike, "Exclude replies"),
|
||||
|
|
@ -144,7 +147,7 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
|
|||
:with_muted,
|
||||
:query,
|
||||
BooleanLike,
|
||||
"Include reactions from muted acccounts."
|
||||
"Include reactions from muted accounts."
|
||||
)
|
||||
] ++ pagination_params(),
|
||||
responses: %{
|
||||
|
|
@ -347,7 +350,7 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
|
|||
operationId: "AccountController.mutes",
|
||||
description: "Accounts the user has muted.",
|
||||
security: [%{"oAuth" => ["follow", "read:mutes"]}],
|
||||
parameters: pagination_params(),
|
||||
parameters: [with_relationships_param() | pagination_params()],
|
||||
responses: %{
|
||||
200 => Operation.response("Accounts", "application/json", array_of_accounts())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@ defmodule Pleroma.Web.ApiSpec.TimelineOperation do
|
|||
security: [%{"oAuth" => ["read:statuses"]}],
|
||||
parameters: [
|
||||
local_param(),
|
||||
remote_param(),
|
||||
only_media_param(),
|
||||
with_muted_param(),
|
||||
exclude_visibilities_param(),
|
||||
reply_visibility_param() | pagination_params()
|
||||
|
|
@ -61,6 +63,7 @@ defmodule Pleroma.Web.ApiSpec.TimelineOperation do
|
|||
local_param(),
|
||||
instance_param(),
|
||||
only_media_param(),
|
||||
remote_param(),
|
||||
with_muted_param(),
|
||||
exclude_visibilities_param(),
|
||||
reply_visibility_param() | pagination_params()
|
||||
|
|
@ -107,6 +110,7 @@ defmodule Pleroma.Web.ApiSpec.TimelineOperation do
|
|||
),
|
||||
local_param(),
|
||||
only_media_param(),
|
||||
remote_param(),
|
||||
with_muted_param(),
|
||||
exclude_visibilities_param() | pagination_params()
|
||||
],
|
||||
|
|
@ -132,6 +136,9 @@ defmodule Pleroma.Web.ApiSpec.TimelineOperation do
|
|||
required: true
|
||||
),
|
||||
with_muted_param(),
|
||||
local_param(),
|
||||
remote_param(),
|
||||
only_media_param(),
|
||||
exclude_visibilities_param() | pagination_params()
|
||||
],
|
||||
operationId: "TimelineController.list",
|
||||
|
|
@ -198,4 +205,13 @@ defmodule Pleroma.Web.ApiSpec.TimelineOperation do
|
|||
"Show only statuses with media attached?"
|
||||
)
|
||||
end
|
||||
|
||||
defp remote_param do
|
||||
Operation.parameter(
|
||||
:remote,
|
||||
:query,
|
||||
%Schema{allOf: [BooleanLike], default: false},
|
||||
"Show only remote statuses?"
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -269,10 +269,14 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
|
|||
def relationships(%{assigns: %{user: _user}} = conn, _), do: json(conn, [])
|
||||
|
||||
@doc "GET /api/v1/accounts/:id"
|
||||
def show(%{assigns: %{user: for_user}} = conn, %{id: nickname_or_id}) do
|
||||
def show(%{assigns: %{user: for_user}} = conn, %{id: nickname_or_id} = params) do
|
||||
with %User{} = user <- User.get_cached_by_nickname_or_id(nickname_or_id, for: for_user),
|
||||
:visible <- User.visible_for(user, for_user) do
|
||||
render(conn, "show.json", user: user, for: for_user)
|
||||
render(conn, "show.json",
|
||||
user: user,
|
||||
for: for_user,
|
||||
embed_relationships: embed_relationships?(params)
|
||||
)
|
||||
else
|
||||
error -> user_visibility_error(conn, error)
|
||||
end
|
||||
|
|
@ -454,7 +458,12 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
|
|||
|
||||
conn
|
||||
|> add_link_headers(users)
|
||||
|> render("index.json", users: users, for: user, as: :user)
|
||||
|> render("index.json",
|
||||
users: users,
|
||||
for: user,
|
||||
as: :user,
|
||||
embed_relationships: embed_relationships?(params)
|
||||
)
|
||||
end
|
||||
|
||||
@doc "GET /api/v1/blocks"
|
||||
|
|
|
|||
|
|
@ -51,6 +51,8 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
|
|||
|> Map.put(:reply_filtering_user, user)
|
||||
|> Map.put(:announce_filtering_user, user)
|
||||
|> Map.put(:user, user)
|
||||
|> Map.put(:local_only, params[:local])
|
||||
|> Map.delete(:local)
|
||||
|
||||
activities =
|
||||
[user.ap_id | User.following(user)]
|
||||
|
|
@ -190,6 +192,7 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
|
|||
|> Map.put(:blocking_user, user)
|
||||
|> Map.put(:user, user)
|
||||
|> Map.put(:muting_user, user)
|
||||
|> Map.put(:local_only, params[:local])
|
||||
|
||||
# we must filter the following list for the user to avoid leaking statuses the user
|
||||
# does not actually have permission to see (for more info, peruse security issue #270).
|
||||
|
|
|
|||
|
|
@ -262,7 +262,9 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
|
|||
}
|
||||
},
|
||||
|
||||
# Pleroma extension
|
||||
# Pleroma extensions
|
||||
# Note: it's insecure to output :email but fully-qualified nickname may serve as safe stub
|
||||
fqn: User.full_nickname(user),
|
||||
pleroma: %{
|
||||
ap_id: user.ap_id,
|
||||
also_known_as: user.also_known_as,
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ defmodule Pleroma.Web.MastodonAPI.InstanceView do
|
|||
fields_limits: fields_limits(),
|
||||
post_formats: Config.get([:instance, :allowed_post_formats])
|
||||
},
|
||||
stats: %{mau: Pleroma.User.active_user_count()},
|
||||
vapid_public_key: Keyword.get(Pleroma.Web.Push.vapid_config(), :public_key)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
30
lib/pleroma/web/plugs/user_tracking_plug.ex
Normal file
30
lib/pleroma/web/plugs/user_tracking_plug.ex
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.Plugs.UserTrackingPlug do
|
||||
alias Pleroma.User
|
||||
|
||||
import Plug.Conn, only: [assign: 3]
|
||||
|
||||
@update_interval :timer.hours(24)
|
||||
|
||||
def init(opts), do: opts
|
||||
|
||||
def call(%{assigns: %{user: %User{id: id} = user}} = conn, _) when not is_nil(id) do
|
||||
with true <- needs_update?(user),
|
||||
{:ok, user} <- User.update_last_active_at(user) do
|
||||
assign(conn, :user, user)
|
||||
else
|
||||
_ -> conn
|
||||
end
|
||||
end
|
||||
|
||||
def call(conn, _), do: conn
|
||||
|
||||
defp needs_update?(%User{last_active_at: nil}), do: true
|
||||
|
||||
defp needs_update?(%User{last_active_at: last_active_at}) do
|
||||
NaiveDateTime.diff(NaiveDateTime.utc_now(), last_active_at, :millisecond) >= @update_interval
|
||||
end
|
||||
end
|
||||
|
|
@ -56,6 +56,7 @@ defmodule Pleroma.Web.Router do
|
|||
plug(Pleroma.Web.Plugs.UserEnabledPlug)
|
||||
plug(Pleroma.Web.Plugs.SetUserSessionIdPlug)
|
||||
plug(Pleroma.Web.Plugs.EnsureUserTokenAssignsPlug)
|
||||
plug(Pleroma.Web.Plugs.UserTrackingPlug)
|
||||
end
|
||||
|
||||
pipeline :base_api do
|
||||
|
|
@ -319,6 +320,8 @@ defmodule Pleroma.Web.Router do
|
|||
end
|
||||
|
||||
scope "/oauth", Pleroma.Web.OAuth do
|
||||
# Note: use /api/v1/accounts/verify_credentials for userinfo of signed-in user
|
||||
|
||||
get("/registration_details", OAuthController, :registration_details)
|
||||
|
||||
post("/mfa/verify", MFAController, :verify, as: :mfa_verify)
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
</div>
|
||||
<span class="display-name" style="padding-left: 0.5em;">
|
||||
<bdi><%= raw (@author.name |> Formatter.emojify(@author.emoji)) %></bdi>
|
||||
<span class="nickname"><%= full_nickname(@author) %></span>
|
||||
<span class="nickname">@<%= full_nickname(@author) %></span>
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ defmodule Pleroma.Web.EmbedView do
|
|||
|
||||
use Phoenix.HTML
|
||||
|
||||
defdelegate full_nickname(user), to: User
|
||||
|
||||
@media_types ["image", "audio", "video"]
|
||||
|
||||
defp fetch_media_type(%{"mediaType" => mediaType}) do
|
||||
|
|
@ -30,11 +32,6 @@ defmodule Pleroma.Web.EmbedView do
|
|||
)
|
||||
end
|
||||
|
||||
defp full_nickname(user) do
|
||||
%{host: host} = URI.parse(user.ap_id)
|
||||
"@" <> user.nickname <> "@" <> host
|
||||
end
|
||||
|
||||
defp status_title(%Activity{object: %Object{data: %{"name" => name}}}) when is_binary(name),
|
||||
do: name
|
||||
|
||||
|
|
|
|||
|
|
@ -17,12 +17,14 @@ defmodule Pleroma.Workers.AttachmentsCleanupWorker do
|
|||
"object" => %{"data" => %{"attachment" => [_ | _] = attachments, "actor" => actor}}
|
||||
}
|
||||
}) do
|
||||
attachments
|
||||
|> Enum.flat_map(fn item -> Enum.map(item["url"], & &1["href"]) end)
|
||||
|> fetch_objects
|
||||
|> prepare_objects(actor, Enum.map(attachments, & &1["name"]))
|
||||
|> filter_objects
|
||||
|> do_clean
|
||||
if Pleroma.Config.get([:instance, :cleanup_attachments], false) do
|
||||
attachments
|
||||
|> Enum.flat_map(fn item -> Enum.map(item["url"], & &1["href"]) end)
|
||||
|> fetch_objects
|
||||
|> prepare_objects(actor, Enum.map(attachments, & &1["name"]))
|
||||
|> filter_objects
|
||||
|> do_clean
|
||||
end
|
||||
|
||||
{:ok, :success}
|
||||
end
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ defmodule Pleroma.Workers.PurgeExpiredActivity do
|
|||
Worker which purges expired activity.
|
||||
"""
|
||||
|
||||
use Oban.Worker, queue: :activity_expiration, max_attempts: 1
|
||||
use Oban.Worker, queue: :activity_expiration, max_attempts: 1, unique: [period: :infinity]
|
||||
|
||||
import Ecto.Query
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue