Add timeline visibility options
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
parent
95ed4de284
commit
5dabf69757
7 changed files with 83 additions and 22 deletions
|
@ -263,7 +263,8 @@
|
|||
multitenancy: %{
|
||||
enabled: false
|
||||
},
|
||||
local_bubble: []
|
||||
local_bubble: [],
|
||||
federated_timeline_available: true
|
||||
|
||||
config :pleroma, :welcome,
|
||||
direct_message: [
|
||||
|
@ -894,7 +895,7 @@
|
|||
private_instance? = :if_instance_is_private
|
||||
|
||||
config :pleroma, :restrict_unauthenticated,
|
||||
timelines: %{local: private_instance?, federated: private_instance?},
|
||||
timelines: %{local: private_instance?, federated: private_instance?, bubble: true},
|
||||
profiles: %{local: private_instance?, remote: private_instance?},
|
||||
activities: %{local: private_instance?, remote: private_instance?}
|
||||
|
||||
|
|
|
@ -1156,6 +1156,12 @@
|
|||
type: {:list, :string},
|
||||
description:
|
||||
"List of instances that make up your local bubble (closely-related instances). Used to populate the 'bubble' timeline (domain only)."
|
||||
},
|
||||
%{
|
||||
key: :federated_timeline_available,
|
||||
type: :boolean,
|
||||
description:
|
||||
"Let people view the 'firehose' feed of all public statuses from all instances."
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
|
@ -72,7 +72,8 @@ def public_operation do
|
|||
operationId: "TimelineController.public",
|
||||
responses: %{
|
||||
200 => Operation.response("Array of Status", "application/json", array_of_statuses()),
|
||||
401 => Operation.response("Error", "application/json", ApiError)
|
||||
401 => Operation.response("Error", "application/json", ApiError),
|
||||
404 => Operation.response("Error", "application/json", ApiError)
|
||||
}
|
||||
}
|
||||
end
|
||||
|
|
|
@ -16,7 +16,7 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
|
|||
alias Pleroma.Web.Plugs.RateLimiter
|
||||
|
||||
plug(Pleroma.Web.ApiSpec.CastAndValidate)
|
||||
plug(:skip_public_check when action in [:public, :hashtag])
|
||||
plug(:skip_public_check when action in [:public, :hashtag, :bubble])
|
||||
|
||||
# TODO: Replace with a macro when there is a Phoenix release with the following commit in it:
|
||||
# https://github.com/phoenixframework/phoenix/commit/2e8c63c01fec4dde5467dbbbf9705ff9e780735e
|
||||
|
@ -28,13 +28,13 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
|
|||
plug(RateLimiter, [name: :timeline, bucket_name: :list_timeline] when action == :list)
|
||||
plug(RateLimiter, [name: :timeline, bucket_name: :bubble_timeline] when action == :bubble)
|
||||
|
||||
plug(OAuthScopesPlug, %{scopes: ["read:statuses"]} when action in [:home, :direct, :bubble])
|
||||
plug(OAuthScopesPlug, %{scopes: ["read:statuses"]} when action in [:home, :direct])
|
||||
plug(OAuthScopesPlug, %{scopes: ["read:lists"]} when action == :list)
|
||||
|
||||
plug(
|
||||
OAuthScopesPlug,
|
||||
%{scopes: ["read:statuses"], fallback: :proceed_unauthenticated}
|
||||
when action in [:public, :hashtag]
|
||||
when action in [:public, :hashtag, :bubble]
|
||||
)
|
||||
|
||||
plug(Pleroma.Web.Plugs.SetDomainPlug when action in [:public, :hashtag])
|
||||
|
@ -98,21 +98,19 @@ def direct(%{assigns: %{user: user}} = conn, params) do
|
|||
)
|
||||
end
|
||||
|
||||
defp restrict_unauthenticated?(true = _local_only) do
|
||||
Config.restrict_unauthenticated_access?(:timelines, :local)
|
||||
end
|
||||
|
||||
defp restrict_unauthenticated?(_) do
|
||||
Config.restrict_unauthenticated_access?(:timelines, :federated)
|
||||
defp restrict_unauthenticated?(type) do
|
||||
Config.restrict_unauthenticated_access?(:timelines, type)
|
||||
end
|
||||
|
||||
# GET /api/v1/timelines/public
|
||||
def public(%{assigns: %{user: user}} = conn, params) do
|
||||
local_only = params[:local]
|
||||
timeline_type = if local_only, do: :local, else: :federated
|
||||
|
||||
if is_nil(user) and restrict_unauthenticated?(local_only) do
|
||||
fail_on_bad_auth(conn)
|
||||
else
|
||||
with {:enabled, true} <-
|
||||
{:enabled, local_only || Config.get([:instance, :federated_timeline_available], true)},
|
||||
{:authenticated, true} <-
|
||||
{:authenticated, !(is_nil(user) and restrict_unauthenticated?(timeline_type))} do
|
||||
activities =
|
||||
params
|
||||
|> Map.put(:type, ["Create"])
|
||||
|
@ -134,16 +132,28 @@ def public(%{assigns: %{user: user}} = conn, params) do
|
|||
as: :activity,
|
||||
with_muted: Map.get(params, :with_muted, false)
|
||||
)
|
||||
else
|
||||
{:enabled, false} ->
|
||||
conn
|
||||
|> put_status(404)
|
||||
|> json(%{error: "Federated timeline is disabled"})
|
||||
|
||||
{:authenticated, false} ->
|
||||
fail_on_bad_auth(conn)
|
||||
end
|
||||
end
|
||||
|
||||
# GET /api/v1/timelines/bubble
|
||||
def bubble(%{assigns: %{user: user}} = conn, params) do
|
||||
bubble_instances = Config.get([:instance, :local_bubble], [])
|
||||
|
||||
if is_nil(user) do
|
||||
if is_nil(user) and restrict_unauthenticated?(:bubble) do
|
||||
fail_on_bad_auth(conn)
|
||||
else
|
||||
bubble_instances =
|
||||
Enum.uniq(
|
||||
Config.get([:instance, :local_bubble], []) ++
|
||||
[Pleroma.Web.Endpoint.host()]
|
||||
)
|
||||
|
||||
activities =
|
||||
params
|
||||
|> Map.put(:type, ["Create"])
|
||||
|
@ -195,7 +205,7 @@ defp hashtag_fetching(conn, params, user, local_only) do
|
|||
def hashtag(%{assigns: %{user: user}} = conn, params) do
|
||||
local_only = params[:local]
|
||||
|
||||
if is_nil(user) and restrict_unauthenticated?(local_only) do
|
||||
if is_nil(user) and restrict_unauthenticated?(if local_only, do: :local, else: :federated) do
|
||||
fail_on_bad_auth(conn)
|
||||
else
|
||||
activities = hashtag_fetching(conn, params, user, local_only)
|
||||
|
|
|
@ -73,7 +73,15 @@ def get_nodeinfo("2.0") do
|
|||
mailerEnabled: Config.get([Pleroma.Emails.Mailer, :enabled], false),
|
||||
features: features,
|
||||
restrictedNicknames: Config.get([Pleroma.User, :restricted_nicknames]),
|
||||
skipThreadContainment: Config.get([:instance, :skip_thread_containment], false)
|
||||
skipThreadContainment: Config.get([:instance, :skip_thread_containment], false),
|
||||
federatedTimelineAvailable: Config.get([:instance, :federated_timeline_available], true),
|
||||
publicTimelineVisibility: %{
|
||||
federated:
|
||||
!Config.restrict_unauthenticated_access?(:timelines, :federated) &&
|
||||
Config.get([:instance, :federated_timeline_available], true),
|
||||
local: !Config.restrict_unauthenticated_access?(:timelines, :local),
|
||||
bubble: !Config.restrict_unauthenticated_access?(:timelines, :bubble)
|
||||
}
|
||||
},
|
||||
operations: %{
|
||||
"com.shinolabs.api.bite": ["1.0.0"],
|
||||
|
|
|
@ -887,7 +887,6 @@ defmodule Pleroma.Web.Router do
|
|||
get("/timelines/home", TimelineController, :home)
|
||||
get("/timelines/direct", TimelineController, :direct)
|
||||
get("/timelines/list/:list_id", TimelineController, :list)
|
||||
get("/timelines/bubble", TimelineController, :bubble)
|
||||
|
||||
get("/announcements", AnnouncementController, :index)
|
||||
post("/announcements/:id/dismiss", AnnouncementController, :mark_read)
|
||||
|
@ -944,6 +943,7 @@ defmodule Pleroma.Web.Router do
|
|||
|
||||
get("/timelines/public", TimelineController, :public)
|
||||
get("/timelines/tag/:tag", TimelineController, :hashtag)
|
||||
get("/timelines/bubble", TimelineController, :bubble)
|
||||
|
||||
get("/polls/:id", PollController, :show)
|
||||
|
||||
|
|
|
@ -444,6 +444,26 @@ test "filtering local posts basing on domain", %{conn: conn} do
|
|||
|> get("http://pleroma.example.org/api/v1/timelines/public?local=true")
|
||||
|> json_response_and_validate_schema(200)
|
||||
end
|
||||
|
||||
test "should return 404 if disabled" do
|
||||
clear_config([:instance, :federated_timeline_available], false)
|
||||
|
||||
result =
|
||||
build_conn()
|
||||
|> get("/api/v1/timelines/public")
|
||||
|> json_response_and_validate_schema(404)
|
||||
|
||||
assert %{"error" => "Federated timeline is disabled"} = result
|
||||
end
|
||||
|
||||
test "should not return 404 if local is specified" do
|
||||
clear_config([:instance, :federated_timeline_available], false)
|
||||
|
||||
result =
|
||||
build_conn()
|
||||
|> get("/api/v1/timelines/public?local=true")
|
||||
|> json_response_and_validate_schema(200)
|
||||
end
|
||||
end
|
||||
|
||||
defp local_and_remote_activities do
|
||||
|
@ -1110,7 +1130,8 @@ test "filtering", %{conn: conn, user: user} do
|
|||
|
||||
assert local_activity.id in one_instance
|
||||
|
||||
clear_config([:instance, :local_bubble], ["localhost:4001", "example.com"])
|
||||
# If we have others, also include theirs
|
||||
clear_config([:instance, :local_bubble], ["example.com"])
|
||||
|
||||
two_instances =
|
||||
conn
|
||||
|
@ -1121,6 +1142,20 @@ test "filtering", %{conn: conn, user: user} do
|
|||
assert local_activity.id in two_instances
|
||||
assert remote_activity.id in two_instances
|
||||
end
|
||||
|
||||
test "restrict_unauthenticated with bubble timeline", %{conn: conn} do
|
||||
clear_config([:restrict_unauthenticated, :timelines, :bubble], true)
|
||||
|
||||
conn
|
||||
|> get("/api/v1/timelines/bubble")
|
||||
|> json_response_and_validate_schema(:unauthorized)
|
||||
|
||||
clear_config([:restrict_unauthenticated, :timelines, :bubble], false)
|
||||
|
||||
conn
|
||||
|> get("/api/v1/timelines/bubble")
|
||||
|> json_response_and_validate_schema(200)
|
||||
end
|
||||
end
|
||||
|
||||
defp create_remote_activity(user) do
|
||||
|
|
Loading…
Reference in a new issue