Merge branch 'develop' into frontend-switcher-9000
This commit is contained in:
commit
4c9c959bb3
|
@ -4,6 +4,13 @@ All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
|
|
||||||
|
## Unreleased
|
||||||
|
|
||||||
|
## Added
|
||||||
|
- Nodeinfo keys for unauthenticated timeline visibility
|
||||||
|
- Option to disable federated timeline
|
||||||
|
- Option to make the bubble timeline publicly accessible
|
||||||
|
|
||||||
## 2023.03
|
## 2023.03
|
||||||
|
|
||||||
## Fixed
|
## Fixed
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
FROM hexpm/elixir:1.13.4-erlang-24.3.4.5-alpine-3.15.6
|
FROM hexpm/elixir:1.14.3-erlang-25.3-alpine-3.17.2
|
||||||
|
|
||||||
ENV MIX_ENV=prod
|
ENV MIX_ENV=prod
|
||||||
ENV ERL_EPMD_ADDRESS=127.0.0.1
|
ENV ERL_EPMD_ADDRESS=127.0.0.1
|
||||||
|
|
|
@ -54,6 +54,9 @@ If your platform is not supported, or you just want to be able to edit the sourc
|
||||||
### Docker
|
### Docker
|
||||||
Docker installation is supported via [this setup](https://docs.akkoma.dev/stable/installation/docker_en/)
|
Docker installation is supported via [this setup](https://docs.akkoma.dev/stable/installation/docker_en/)
|
||||||
|
|
||||||
|
### Packages
|
||||||
|
Akkoma is packaged for [YunoHost](https://yunohost.org) and can be found and installed from the [YunoHost app catalogue](https://yunohost.org/#/apps).
|
||||||
|
|
||||||
### Compilation Troubleshooting
|
### Compilation Troubleshooting
|
||||||
If you ever encounter compilation issues during the updating of Akkoma, you can try these commands and see if they fix things:
|
If you ever encounter compilation issues during the updating of Akkoma, you can try these commands and see if they fix things:
|
||||||
|
|
||||||
|
|
|
@ -261,7 +261,8 @@
|
||||||
privileged_staff: false,
|
privileged_staff: false,
|
||||||
local_bubble: [],
|
local_bubble: [],
|
||||||
max_frontend_settings_json_chars: 100_000,
|
max_frontend_settings_json_chars: 100_000,
|
||||||
export_prometheus_metrics: true
|
export_prometheus_metrics: true,
|
||||||
|
federated_timeline_available: true
|
||||||
|
|
||||||
config :pleroma, :welcome,
|
config :pleroma, :welcome,
|
||||||
direct_message: [
|
direct_message: [
|
||||||
|
@ -813,7 +814,7 @@
|
||||||
private_instance? = :if_instance_is_private
|
private_instance? = :if_instance_is_private
|
||||||
|
|
||||||
config :pleroma, :restrict_unauthenticated,
|
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?},
|
profiles: %{local: private_instance?, remote: private_instance?},
|
||||||
activities: %{local: private_instance?, remote: private_instance?}
|
activities: %{local: private_instance?, remote: private_instance?}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
hehe, /emoji/hehe.png, Akkoma
|
||||||
|
nothehe, /emoji/nothehe.png, Akkoma
|
|
@ -969,6 +969,12 @@
|
||||||
key: :export_prometheus_metrics,
|
key: :export_prometheus_metrics,
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
description: "Enable prometheus metrics (at /api/v1/akkoma/metrics)"
|
description: "Enable prometheus metrics (at /api/v1/akkoma/metrics)"
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
key: :federated_timeline_available,
|
||||||
|
type: :boolean,
|
||||||
|
description:
|
||||||
|
"Let people view the 'firehose' feed of all public statuses from all instances."
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -2993,6 +2999,11 @@
|
||||||
key: :federated,
|
key: :federated,
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
description: "Disallow viewing the whole known network timeline."
|
description: "Disallow viewing the whole known network timeline."
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
key: :bubble,
|
||||||
|
type: :boolean,
|
||||||
|
description: "Disallow viewing the bubble timeline."
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
## Required dependencies
|
## Required dependencies
|
||||||
|
|
||||||
* PostgreSQL 9.6+
|
* PostgreSQL 9.6+
|
||||||
* Elixir 1.12+ (1.13+ recommended)
|
* Elixir 1.14+
|
||||||
* Erlang OTP 22.2+
|
* Erlang OTP 24+
|
||||||
* git
|
* git
|
||||||
* file / libmagic
|
* file / libmagic
|
||||||
* gcc (clang might also work)
|
* gcc (clang might also work)
|
||||||
|
|
9
docs/docs/installation/yunohost_en.md
Normal file
9
docs/docs/installation/yunohost_en.md
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
# Installing on Yunohost
|
||||||
|
|
||||||
|
[YunoHost](https://yunohost.org) is a server operating system aimed at self-hosting. The YunoHost community maintains a package of Akkoma which allows you to install Akkoma on YunoHost. You can install it via the normal way through the admin web interface, or through the CLI. More information can be found at [the repo of the package](https://github.com/YunoHost-Apps/akkoma_ynh).
|
||||||
|
|
||||||
|
## Questions
|
||||||
|
|
||||||
|
Questions and problems related to the YunoHost parts can be done through the [YunoHost channels](https://yunohost.org/en/help).
|
||||||
|
|
||||||
|
For questions about Akkoma, check out the [Akkoma community channels](../../#community-channels).
|
|
@ -1,2 +1,2 @@
|
||||||
elixir_version=1.9.4
|
elixir_version=1.14.3
|
||||||
erlang_version=22.3.4.1
|
erlang_version=25.3
|
||||||
|
|
|
@ -82,4 +82,46 @@ def run(["user_timeline", nickname, reading_nickname]) do
|
||||||
Ecto.Adapters.SQL.explain(Repo, :all, query, analyze: true, timeout: :infinity)
|
Ecto.Adapters.SQL.explain(Repo, :all, query, analyze: true, timeout: :infinity)
|
||||||
|> IO.puts()
|
|> IO.puts()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def run(["notifications", nickname]) do
|
||||||
|
start_pleroma()
|
||||||
|
user = Repo.get_by!(User, nickname: nickname)
|
||||||
|
account_ap_id = user.ap_id
|
||||||
|
options = %{account_ap_id: user.ap_id}
|
||||||
|
|
||||||
|
query =
|
||||||
|
user
|
||||||
|
|> Pleroma.Notification.for_user_query(options)
|
||||||
|
|> where([n, a], a.actor == ^account_ap_id)
|
||||||
|
|> limit(20)
|
||||||
|
|
||||||
|
Ecto.Adapters.SQL.explain(Repo, :all, query, analyze: true, timeout: :infinity)
|
||||||
|
|> IO.puts()
|
||||||
|
end
|
||||||
|
|
||||||
|
def run(["known_network", nickname]) do
|
||||||
|
start_pleroma()
|
||||||
|
user = Repo.get_by!(User, nickname: nickname)
|
||||||
|
|
||||||
|
params =
|
||||||
|
%{}
|
||||||
|
|> Map.put(:type, ["Create"])
|
||||||
|
|> Map.put(:local_only, false)
|
||||||
|
|> Map.put(:blocking_user, user)
|
||||||
|
|> Map.put(:muting_user, user)
|
||||||
|
|> Map.put(:reply_filtering_user, user)
|
||||||
|
# Restricts unfederated content to authenticated users
|
||||||
|
|> Map.put(:includes_local_public, not is_nil(user))
|
||||||
|
|> Map.put(:restrict_unlisted, true)
|
||||||
|
|
||||||
|
query =
|
||||||
|
Pleroma.Web.ActivityPub.ActivityPub.fetch_activities_query(
|
||||||
|
[Pleroma.Constants.as_public()],
|
||||||
|
params
|
||||||
|
)
|
||||||
|
|> limit(20)
|
||||||
|
|
||||||
|
Ecto.Adapters.SQL.explain(Repo, :all, query, analyze: true, timeout: :infinity)
|
||||||
|
|> IO.puts()
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -277,6 +277,13 @@ def get_create_by_object_ap_id_with_object(ap_id) when is_binary(ap_id) do
|
||||||
|
|
||||||
def get_create_by_object_ap_id_with_object(_), do: nil
|
def get_create_by_object_ap_id_with_object(_), do: nil
|
||||||
|
|
||||||
|
def get_local_create_by_object_ap_id(ap_id) when is_binary(ap_id) do
|
||||||
|
ap_id
|
||||||
|
|> create_by_object_ap_id()
|
||||||
|
|> where(local: true)
|
||||||
|
|> Repo.one()
|
||||||
|
end
|
||||||
|
|
||||||
@spec create_by_id_with_object(String.t()) :: t() | nil
|
@spec create_by_id_with_object(String.t()) :: t() | nil
|
||||||
def create_by_id_with_object(id) do
|
def create_by_id_with_object(id) do
|
||||||
get_by_id_with_opts(id, preload: [:object], filter: [type: "Create"])
|
get_by_id_with_opts(id, preload: [:object], filter: [type: "Create"])
|
||||||
|
|
|
@ -162,7 +162,7 @@ def local do
|
||||||
%Instance{
|
%Instance{
|
||||||
host: Pleroma.Web.Endpoint.host(),
|
host: Pleroma.Web.Endpoint.host(),
|
||||||
favicon: Pleroma.Web.Endpoint.url() <> "/favicon.png",
|
favicon: Pleroma.Web.Endpoint.url() <> "/favicon.png",
|
||||||
nodeinfo: Pleroma.Web.Nodeinfo.NodeinfoController.raw_nodeinfo()
|
nodeinfo: Pleroma.Web.Nodeinfo.Nodeinfo.get_nodeinfo("2.1")
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -366,21 +366,21 @@ def invisible?(%User{invisible: true}), do: true
|
||||||
def invisible?(_), do: false
|
def invisible?(_), do: false
|
||||||
|
|
||||||
def avatar_url(user, options \\ []) do
|
def avatar_url(user, options \\ []) do
|
||||||
case user.avatar do
|
default = Config.get([:assets, :default_user_avatar], "#{Endpoint.url()}/images/avi.png")
|
||||||
%{"url" => [%{"href" => href} | _]} ->
|
do_optional_url(user.avatar, default, options)
|
||||||
href
|
|
||||||
|
|
||||||
_ ->
|
|
||||||
unless options[:no_default] do
|
|
||||||
Config.get([:assets, :default_user_avatar], "#{Endpoint.url()}/images/avi.png")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def banner_url(user, options \\ []) do
|
def banner_url(user, options \\ []) do
|
||||||
case user.banner do
|
do_optional_url(user.banner, "#{Endpoint.url()}/images/banner.png", options)
|
||||||
%{"url" => [%{"href" => href} | _]} -> href
|
end
|
||||||
_ -> !options[:no_default] && "#{Endpoint.url()}/images/banner.png"
|
|
||||||
|
defp do_optional_url(field, default, options) do
|
||||||
|
case field do
|
||||||
|
%{"url" => [%{"href" => href} | _]} when is_binary(href) ->
|
||||||
|
href
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
unless options[:no_default], do: default
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1502,13 +1502,22 @@ def fetch_activities_bounded(
|
||||||
|
|
||||||
@spec upload(Upload.source(), keyword()) :: {:ok, Object.t()} | {:error, any()}
|
@spec upload(Upload.source(), keyword()) :: {:ok, Object.t()} | {:error, any()}
|
||||||
def upload(file, opts \\ []) do
|
def upload(file, opts \\ []) do
|
||||||
with {:ok, data} <- Upload.store(file, opts) do
|
with {:ok, data} <- Upload.store(sanitize_upload_file(file), opts) do
|
||||||
obj_data = Maps.put_if_present(data, "actor", opts[:actor])
|
obj_data = Maps.put_if_present(data, "actor", opts[:actor])
|
||||||
|
|
||||||
Repo.insert(%Object{data: obj_data})
|
Repo.insert(%Object{data: obj_data})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp sanitize_upload_file(%Plug.Upload{filename: filename} = upload) when is_binary(filename) do
|
||||||
|
%Plug.Upload{
|
||||||
|
upload
|
||||||
|
| filename: Path.basename(filename)
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
defp sanitize_upload_file(upload), do: upload
|
||||||
|
|
||||||
@spec get_actor_url(any()) :: binary() | nil
|
@spec get_actor_url(any()) :: binary() | nil
|
||||||
defp get_actor_url(url) when is_binary(url), do: url
|
defp get_actor_url(url) when is_binary(url), do: url
|
||||||
defp get_actor_url(%{"href" => href}) when is_binary(href), do: href
|
defp get_actor_url(%{"href" => href}) when is_binary(href), do: href
|
||||||
|
|
|
@ -70,7 +70,8 @@ def public_operation do
|
||||||
operationId: "TimelineController.public",
|
operationId: "TimelineController.public",
|
||||||
responses: %{
|
responses: %{
|
||||||
200 => Operation.response("Array of Status", "application/json", array_of_statuses()),
|
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
|
end
|
||||||
|
|
|
@ -16,7 +16,7 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
|
||||||
alias Pleroma.Web.Plugs.RateLimiter
|
alias Pleroma.Web.Plugs.RateLimiter
|
||||||
|
|
||||||
plug(Pleroma.Web.ApiSpec.CastAndValidate)
|
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:
|
# TODO: Replace with a macro when there is a Phoenix release with the following commit in it:
|
||||||
# https://github.com/phoenixframework/phoenix/commit/2e8c63c01fec4dde5467dbbbf9705ff9e780735e
|
# https://github.com/phoenixframework/phoenix/commit/2e8c63c01fec4dde5467dbbbf9705ff9e780735e
|
||||||
|
@ -28,19 +28,25 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
|
||||||
plug(RateLimiter, [name: :timeline, bucket_name: :list_timeline] when action == :list)
|
plug(RateLimiter, [name: :timeline, bucket_name: :list_timeline] when action == :list)
|
||||||
plug(RateLimiter, [name: :timeline, bucket_name: :bubble_timeline] when action == :bubble)
|
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:lists"]} when action == :list)
|
||||||
|
|
||||||
plug(
|
plug(
|
||||||
OAuthScopesPlug,
|
OAuthScopesPlug,
|
||||||
%{scopes: ["read:statuses"], fallback: :proceed_unauthenticated}
|
%{scopes: ["read:statuses"], fallback: :proceed_unauthenticated}
|
||||||
when action in [:public, :hashtag]
|
when action in [:public, :hashtag, :bubble]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
require Logger
|
||||||
|
|
||||||
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.TimelineOperation
|
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.TimelineOperation
|
||||||
|
|
||||||
# GET /api/v1/timelines/home
|
# GET /api/v1/timelines/home
|
||||||
def home(%{assigns: %{user: user}} = conn, params) do
|
def home(%{assigns: %{user: user}} = conn, params) do
|
||||||
|
%{nickname: nickname} = user
|
||||||
|
|
||||||
|
Logger.debug("TimelineController.home: #{nickname}")
|
||||||
|
|
||||||
followed_hashtags =
|
followed_hashtags =
|
||||||
user
|
user
|
||||||
|> User.followed_hashtags()
|
|> User.followed_hashtags()
|
||||||
|
@ -58,11 +64,15 @@ def home(%{assigns: %{user: user}} = conn, params) do
|
||||||
|> Map.put(:followed_hashtags, followed_hashtags)
|
|> Map.put(:followed_hashtags, followed_hashtags)
|
||||||
|> Map.delete(:local)
|
|> Map.delete(:local)
|
||||||
|
|
||||||
|
Logger.debug("TimelineController.home: #{nickname} - fetching activities")
|
||||||
|
|
||||||
activities =
|
activities =
|
||||||
[user.ap_id | User.following(user)]
|
[user.ap_id | User.following(user)]
|
||||||
|> ActivityPub.fetch_activities(params)
|
|> ActivityPub.fetch_activities(params)
|
||||||
|> Enum.reverse()
|
|> Enum.reverse()
|
||||||
|
|
||||||
|
Logger.debug("TimelineController.home: #{nickname} - rendering")
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> add_link_headers(activities)
|
|> add_link_headers(activities)
|
||||||
|> render("index.json",
|
|> render("index.json",
|
||||||
|
@ -75,6 +85,8 @@ def home(%{assigns: %{user: user}} = conn, params) do
|
||||||
|
|
||||||
# GET /api/v1/timelines/direct
|
# GET /api/v1/timelines/direct
|
||||||
def direct(%{assigns: %{user: user}} = conn, params) do
|
def direct(%{assigns: %{user: user}} = conn, params) do
|
||||||
|
Logger.debug("TimelineController.direct: #{user.nickname}")
|
||||||
|
|
||||||
params =
|
params =
|
||||||
params
|
params
|
||||||
|> Map.put(:type, "Create")
|
|> Map.put(:type, "Create")
|
||||||
|
@ -82,11 +94,15 @@ def direct(%{assigns: %{user: user}} = conn, params) do
|
||||||
|> Map.put(:user, user)
|
|> Map.put(:user, user)
|
||||||
|> Map.put(:visibility, "direct")
|
|> Map.put(:visibility, "direct")
|
||||||
|
|
||||||
|
Logger.debug("TimelineController.direct: #{user.nickname} - fetching activities")
|
||||||
|
|
||||||
activities =
|
activities =
|
||||||
[user.ap_id]
|
[user.ap_id]
|
||||||
|> ActivityPub.fetch_activities_query(params)
|
|> ActivityPub.fetch_activities_query(params)
|
||||||
|> Pagination.fetch_paginated(params)
|
|> Pagination.fetch_paginated(params)
|
||||||
|
|
||||||
|
Logger.debug("TimelineController.direct: #{user.nickname} - rendering")
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> add_link_headers(activities)
|
|> add_link_headers(activities)
|
||||||
|> render("index.json",
|
|> render("index.json",
|
||||||
|
@ -96,21 +112,22 @@ def direct(%{assigns: %{user: user}} = conn, params) do
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp restrict_unauthenticated?(true = _local_only) do
|
defp restrict_unauthenticated?(type) do
|
||||||
Config.restrict_unauthenticated_access?(:timelines, :local)
|
Config.restrict_unauthenticated_access?(:timelines, type)
|
||||||
end
|
|
||||||
|
|
||||||
defp restrict_unauthenticated?(_) do
|
|
||||||
Config.restrict_unauthenticated_access?(:timelines, :federated)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# GET /api/v1/timelines/public
|
# GET /api/v1/timelines/public
|
||||||
def public(%{assigns: %{user: user}} = conn, params) do
|
def public(%{assigns: %{user: user}} = conn, params) do
|
||||||
|
Logger.debug("TimelineController.public")
|
||||||
local_only = params[:local]
|
local_only = params[:local]
|
||||||
|
timeline_type = if local_only, do: :local, else: :federated
|
||||||
|
|
||||||
|
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
|
||||||
|
Logger.debug("TimelineController.public: fetching activities")
|
||||||
|
|
||||||
if is_nil(user) and restrict_unauthenticated?(local_only) do
|
|
||||||
fail_on_bad_auth(conn)
|
|
||||||
else
|
|
||||||
activities =
|
activities =
|
||||||
params
|
params
|
||||||
|> Map.put(:type, ["Create"])
|
|> Map.put(:type, ["Create"])
|
||||||
|
@ -123,6 +140,8 @@ def public(%{assigns: %{user: user}} = conn, params) do
|
||||||
|> Map.put(:includes_local_public, not is_nil(user))
|
|> Map.put(:includes_local_public, not is_nil(user))
|
||||||
|> ActivityPub.fetch_public_activities()
|
|> ActivityPub.fetch_public_activities()
|
||||||
|
|
||||||
|
Logger.debug("TimelineController.public: rendering")
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> add_link_headers(activities, %{"local" => local_only})
|
|> add_link_headers(activities, %{"local" => local_only})
|
||||||
|> render("index.json",
|
|> render("index.json",
|
||||||
|
@ -131,20 +150,32 @@ def public(%{assigns: %{user: user}} = conn, params) do
|
||||||
as: :activity,
|
as: :activity,
|
||||||
with_muted: Map.get(params, :with_muted, false)
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
# GET /api/v1/timelines/bubble
|
# GET /api/v1/timelines/bubble
|
||||||
def bubble(%{assigns: %{user: user}} = conn, params) do
|
def bubble(%{assigns: %{user: user}} = conn, params) do
|
||||||
|
Logger.debug("TimelineController.bubble")
|
||||||
|
|
||||||
|
if is_nil(user) and restrict_unauthenticated?(:bubble) do
|
||||||
|
fail_on_bad_auth(conn)
|
||||||
|
else
|
||||||
bubble_instances =
|
bubble_instances =
|
||||||
Enum.uniq(
|
Enum.uniq(
|
||||||
Config.get([:instance, :local_bubble], []) ++
|
Config.get([:instance, :local_bubble], []) ++
|
||||||
[Pleroma.Web.Endpoint.host()]
|
[Pleroma.Web.Endpoint.host()]
|
||||||
)
|
)
|
||||||
|
|
||||||
if is_nil(user) do
|
Logger.debug("TimelineController.bubble: fetching activities")
|
||||||
fail_on_bad_auth(conn)
|
|
||||||
else
|
|
||||||
activities =
|
activities =
|
||||||
params
|
params
|
||||||
|> Map.put(:type, ["Create"])
|
|> Map.put(:type, ["Create"])
|
||||||
|
@ -154,6 +185,8 @@ def bubble(%{assigns: %{user: user}} = conn, params) do
|
||||||
|> Map.put(:instance, bubble_instances)
|
|> Map.put(:instance, bubble_instances)
|
||||||
|> ActivityPub.fetch_public_activities()
|
|> ActivityPub.fetch_public_activities()
|
||||||
|
|
||||||
|
Logger.debug("TimelineController.bubble: rendering")
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> add_link_headers(activities)
|
|> add_link_headers(activities)
|
||||||
|> render("index.json",
|
|> render("index.json",
|
||||||
|
@ -195,7 +228,7 @@ defp hashtag_fetching(params, user, local_only) do
|
||||||
def hashtag(%{assigns: %{user: user}} = conn, params) do
|
def hashtag(%{assigns: %{user: user}} = conn, params) do
|
||||||
local_only = params[:local]
|
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)
|
fail_on_bad_auth(conn)
|
||||||
else
|
else
|
||||||
activities = hashtag_fetching(params, user, local_only)
|
activities = hashtag_fetching(params, user, local_only)
|
||||||
|
|
|
@ -67,6 +67,9 @@ def features do
|
||||||
"pleroma:api/v1/notifications:include_types_filter",
|
"pleroma:api/v1/notifications:include_types_filter",
|
||||||
"quote_posting",
|
"quote_posting",
|
||||||
"editing",
|
"editing",
|
||||||
|
if !Enum.empty?(Config.get([:instance, :local_bubble], [])) do
|
||||||
|
"bubble_timeline"
|
||||||
|
end,
|
||||||
if Config.get([:media_proxy, :enabled]) do
|
if Config.get([:media_proxy, :enabled]) do
|
||||||
"media_proxy"
|
"media_proxy"
|
||||||
end,
|
end,
|
||||||
|
|
|
@ -21,6 +21,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
|
||||||
alias Pleroma.Web.MastodonAPI.StatusView
|
alias Pleroma.Web.MastodonAPI.StatusView
|
||||||
alias Pleroma.Web.MediaProxy
|
alias Pleroma.Web.MediaProxy
|
||||||
alias Pleroma.Web.PleromaAPI.EmojiReactionController
|
alias Pleroma.Web.PleromaAPI.EmojiReactionController
|
||||||
|
require Logger
|
||||||
|
|
||||||
import Pleroma.Web.ActivityPub.Visibility, only: [get_visibility: 1, visible_for_user?: 2]
|
import Pleroma.Web.ActivityPub.Visibility, only: [get_visibility: 1, visible_for_user?: 2]
|
||||||
|
|
||||||
|
@ -87,6 +88,7 @@ defp reblogged?(activity, %User{ap_id: ap_id}) do
|
||||||
defp reblogged?(_activity, _user), do: false
|
defp reblogged?(_activity, _user), do: false
|
||||||
|
|
||||||
def render("index.json", opts) do
|
def render("index.json", opts) do
|
||||||
|
Logger.debug("Rendering index")
|
||||||
reading_user = opts[:for]
|
reading_user = opts[:for]
|
||||||
# To do: check AdminAPIControllerTest on the reasons behind nil activities in the list
|
# To do: check AdminAPIControllerTest on the reasons behind nil activities in the list
|
||||||
activities = Enum.filter(opts.activities, & &1)
|
activities = Enum.filter(opts.activities, & &1)
|
||||||
|
@ -136,8 +138,10 @@ def render("index.json", opts) do
|
||||||
|
|
||||||
def render(
|
def render(
|
||||||
"show.json",
|
"show.json",
|
||||||
%{activity: %{data: %{"type" => "Announce", "object" => _object}} = activity} = opts
|
%{activity: %{id: id, data: %{"type" => "Announce", "object" => _object}} = activity} =
|
||||||
|
opts
|
||||||
) do
|
) do
|
||||||
|
Logger.debug("Rendering reblog #{id}")
|
||||||
user = CommonAPI.get_user(activity.data["actor"])
|
user = CommonAPI.get_user(activity.data["actor"])
|
||||||
created_at = Utils.to_masto_date(activity.data["published"])
|
created_at = Utils.to_masto_date(activity.data["published"])
|
||||||
object = Object.normalize(activity, fetch: false)
|
object = Object.normalize(activity, fetch: false)
|
||||||
|
@ -209,7 +213,9 @@ def render(
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
def render("show.json", %{activity: %{data: %{"object" => _object}} = activity} = opts) do
|
def render("show.json", %{activity: %{id: id, data: %{"object" => _object}} = activity} = opts) do
|
||||||
|
Logger.debug("Rendering status #{id}")
|
||||||
|
|
||||||
with %Object{} = object <- Object.normalize(activity, fetch: false) do
|
with %Object{} = object <- Object.normalize(activity, fetch: false) do
|
||||||
user = CommonAPI.get_user(activity.data["actor"])
|
user = CommonAPI.get_user(activity.data["actor"])
|
||||||
user_follower_address = user.follower_address
|
user_follower_address = user.follower_address
|
||||||
|
@ -428,6 +434,7 @@ def render("show.json", _) do
|
||||||
end
|
end
|
||||||
|
|
||||||
def render("history.json", %{activity: %{data: %{"object" => _object}} = activity} = opts) do
|
def render("history.json", %{activity: %{data: %{"object" => _object}} = activity} = opts) do
|
||||||
|
Logger.debug("Rendering history for #{activity.id}")
|
||||||
object = Object.normalize(activity, fetch: false)
|
object = Object.normalize(activity, fetch: false)
|
||||||
|
|
||||||
hashtags = Object.hashtags(object)
|
hashtags = Object.hashtags(object)
|
||||||
|
@ -614,6 +621,8 @@ def render("attachment_meta.json", %{
|
||||||
def render("attachment_meta.json", _), do: nil
|
def render("attachment_meta.json", _), do: nil
|
||||||
|
|
||||||
def render("context.json", %{activity: activity, activities: activities, user: user}) do
|
def render("context.json", %{activity: activity, activities: activities, user: user}) do
|
||||||
|
Logger.debug("Rendering context for #{activity.id}")
|
||||||
|
|
||||||
%{ancestors: ancestors, descendants: descendants} =
|
%{ancestors: ancestors, descendants: descendants} =
|
||||||
activities
|
activities
|
||||||
|> Enum.reverse()
|
|> Enum.reverse()
|
||||||
|
|
|
@ -71,7 +71,15 @@ def get_nodeinfo("2.0") do
|
||||||
restrictedNicknames: Config.get([Pleroma.User, :restricted_nicknames]),
|
restrictedNicknames: Config.get([Pleroma.User, :restricted_nicknames]),
|
||||||
skipThreadContainment: Config.get([:instance, :skip_thread_containment], false),
|
skipThreadContainment: Config.get([:instance, :skip_thread_containment], false),
|
||||||
privilegedStaff: Config.get([:instance, :privileged_staff]),
|
privilegedStaff: Config.get([:instance, :privileged_staff]),
|
||||||
localBubbleInstances: Config.get([:instance, :local_bubble], [])
|
localBubbleInstances: Config.get([:instance, :local_bubble], []),
|
||||||
|
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)
|
||||||
|
},
|
||||||
|
federatedTimelineAvailable: Config.get([:instance, :federated_timeline_available], true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
|
@ -11,6 +11,7 @@ defmodule Pleroma.Web.Nodeinfo.NodeinfoController do
|
||||||
alias Pleroma.Web.Federator.Publisher
|
alias Pleroma.Web.Federator.Publisher
|
||||||
alias Pleroma.Web.MastodonAPI.InstanceView
|
alias Pleroma.Web.MastodonAPI.InstanceView
|
||||||
alias Pleroma.Web.Endpoint
|
alias Pleroma.Web.Endpoint
|
||||||
|
alias Pleroma.Web.Nodeinfo.Nodeinfo
|
||||||
|
|
||||||
def schemas(conn, _params) do
|
def schemas(conn, _params) do
|
||||||
response = %{
|
response = %{
|
||||||
|
@ -29,101 +30,15 @@ def schemas(conn, _params) do
|
||||||
json(conn, response)
|
json(conn, response)
|
||||||
end
|
end
|
||||||
|
|
||||||
# returns a nodeinfo 2.0 map, since 2.1 just adds a repository field
|
|
||||||
# under software.
|
|
||||||
def raw_nodeinfo do
|
|
||||||
stats = Stats.get_stats()
|
|
||||||
|
|
||||||
staff_accounts =
|
|
||||||
User.all_superusers()
|
|
||||||
|> Enum.map(fn u -> u.ap_id end)
|
|
||||||
|> Enum.filter(fn u -> not Enum.member?(Config.get([:instance, :staff_transparency]), u) end)
|
|
||||||
|
|
||||||
features = InstanceView.features()
|
|
||||||
federation = InstanceView.federation()
|
|
||||||
|
|
||||||
%{
|
|
||||||
version: "2.0",
|
|
||||||
software: %{
|
|
||||||
name: Pleroma.Application.name() |> String.downcase(),
|
|
||||||
version: Pleroma.Application.version()
|
|
||||||
},
|
|
||||||
protocols: Publisher.gather_nodeinfo_protocol_names(),
|
|
||||||
services: %{
|
|
||||||
inbound: [],
|
|
||||||
outbound: []
|
|
||||||
},
|
|
||||||
openRegistrations: Config.get([:instance, :registrations_open]),
|
|
||||||
usage: %{
|
|
||||||
users: %{
|
|
||||||
total: Map.get(stats, :user_count, 0)
|
|
||||||
},
|
|
||||||
localPosts: Map.get(stats, :status_count, 0)
|
|
||||||
},
|
|
||||||
metadata: %{
|
|
||||||
nodeName: Config.get([:instance, :name]),
|
|
||||||
nodeDescription: Config.get([:instance, :description]),
|
|
||||||
private: !Config.get([:instance, :public], true),
|
|
||||||
suggestions: %{
|
|
||||||
enabled: false
|
|
||||||
},
|
|
||||||
staffAccounts: staff_accounts,
|
|
||||||
federation: federation,
|
|
||||||
pollLimits: Config.get([:instance, :poll_limits]),
|
|
||||||
postFormats: Config.get([:instance, :allowed_post_formats]),
|
|
||||||
uploadLimits: %{
|
|
||||||
general: Config.get([:instance, :upload_limit]),
|
|
||||||
avatar: Config.get([:instance, :avatar_upload_limit]),
|
|
||||||
banner: Config.get([:instance, :banner_upload_limit]),
|
|
||||||
background: Config.get([:instance, :background_upload_limit])
|
|
||||||
},
|
|
||||||
fieldsLimits: %{
|
|
||||||
maxFields: Config.get([:instance, :max_account_fields]),
|
|
||||||
maxRemoteFields: Config.get([:instance, :max_remote_account_fields]),
|
|
||||||
nameLength: Config.get([:instance, :account_field_name_length]),
|
|
||||||
valueLength: Config.get([:instance, :account_field_value_length])
|
|
||||||
},
|
|
||||||
accountActivationRequired: Config.get([:instance, :account_activation_required], false),
|
|
||||||
invitesEnabled: Config.get([:instance, :invites_enabled], false),
|
|
||||||
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),
|
|
||||||
localBubbleInstances: Config.get([:instance, :local_bubble], [])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
# Schema definition: https://github.com/jhass/nodeinfo/blob/master/schemas/2.0/schema.json
|
# Schema definition: https://github.com/jhass/nodeinfo/blob/master/schemas/2.0/schema.json
|
||||||
# and https://github.com/jhass/nodeinfo/blob/master/schemas/2.1/schema.json
|
# and https://github.com/jhass/nodeinfo/blob/master/schemas/2.1/schema.json
|
||||||
def nodeinfo(conn, %{"version" => "2.0"}) do
|
def nodeinfo(conn, %{"version" => version}) when version in ["2.0", "2.1"] do
|
||||||
conn
|
conn
|
||||||
|> put_resp_header(
|
|> put_resp_header(
|
||||||
"content-type",
|
"content-type",
|
||||||
"application/json; profile=http://nodeinfo.diaspora.software/ns/schema/2.0#; charset=utf-8"
|
"application/json; profile=http://nodeinfo.diaspora.software/ns/schema/2.0#; charset=utf-8"
|
||||||
)
|
)
|
||||||
|> json(raw_nodeinfo())
|
|> json(Nodeinfo.get_nodeinfo(version))
|
||||||
end
|
|
||||||
|
|
||||||
def nodeinfo(conn, %{"version" => "2.1"}) do
|
|
||||||
raw_response = raw_nodeinfo()
|
|
||||||
|
|
||||||
updated_software =
|
|
||||||
raw_response
|
|
||||||
|> Map.get(:software)
|
|
||||||
|> Map.put(:repository, Pleroma.Application.repository())
|
|
||||||
|
|
||||||
response =
|
|
||||||
raw_response
|
|
||||||
|> Map.put(:software, updated_software)
|
|
||||||
|> Map.put(:version, "2.1")
|
|
||||||
|
|
||||||
conn
|
|
||||||
|> put_resp_header(
|
|
||||||
"content-type",
|
|
||||||
"application/json; profile=http://nodeinfo.diaspora.software/ns/schema/2.1#; charset=utf-8"
|
|
||||||
)
|
|
||||||
|> json(response)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def nodeinfo(conn, _) do
|
def nodeinfo(conn, _) do
|
||||||
|
|
|
@ -36,7 +36,7 @@ def object(%{assigns: %{format: format}} = conn, _params)
|
||||||
def object(conn, _params) do
|
def object(conn, _params) do
|
||||||
with id <- Endpoint.url() <> conn.request_path,
|
with id <- Endpoint.url() <> conn.request_path,
|
||||||
{_, %Activity{} = activity} <-
|
{_, %Activity{} = activity} <-
|
||||||
{:activity, Activity.get_create_by_object_ap_id_with_object(id)},
|
{:activity, Activity.get_local_create_by_object_ap_id(id)},
|
||||||
{_, true} <- {:public?, Visibility.is_public?(activity)},
|
{_, true} <- {:public?, Visibility.is_public?(activity)},
|
||||||
{_, false} <- {:local_public?, Visibility.is_local_public?(activity)} do
|
{_, false} <- {:local_public?, Visibility.is_local_public?(activity)} do
|
||||||
redirect(conn, to: "/notice/#{activity.id}")
|
redirect(conn, to: "/notice/#{activity.id}")
|
||||||
|
|
|
@ -621,7 +621,6 @@ defmodule Pleroma.Web.Router do
|
||||||
get("/timelines/home", TimelineController, :home)
|
get("/timelines/home", TimelineController, :home)
|
||||||
get("/timelines/direct", TimelineController, :direct)
|
get("/timelines/direct", TimelineController, :direct)
|
||||||
get("/timelines/list/:list_id", TimelineController, :list)
|
get("/timelines/list/:list_id", TimelineController, :list)
|
||||||
get("/timelines/bubble", TimelineController, :bubble)
|
|
||||||
|
|
||||||
get("/announcements", AnnouncementController, :index)
|
get("/announcements", AnnouncementController, :index)
|
||||||
post("/announcements/:id/dismiss", AnnouncementController, :mark_read)
|
post("/announcements/:id/dismiss", AnnouncementController, :mark_read)
|
||||||
|
@ -676,6 +675,7 @@ defmodule Pleroma.Web.Router do
|
||||||
|
|
||||||
get("/timelines/public", TimelineController, :public)
|
get("/timelines/public", TimelineController, :public)
|
||||||
get("/timelines/tag/:tag", TimelineController, :hashtag)
|
get("/timelines/tag/:tag", TimelineController, :hashtag)
|
||||||
|
get("/timelines/bubble", TimelineController, :bubble)
|
||||||
|
|
||||||
get("/polls/:id", PollController, :show)
|
get("/polls/:id", PollController, :show)
|
||||||
|
|
||||||
|
|
2
mix.exs
2
mix.exs
|
@ -5,7 +5,7 @@ def project do
|
||||||
[
|
[
|
||||||
app: :pleroma,
|
app: :pleroma,
|
||||||
version: version("3.7.1"),
|
version: version("3.7.1"),
|
||||||
elixir: "~> 1.12",
|
elixir: "~> 1.14",
|
||||||
elixirc_paths: elixirc_paths(Mix.env()),
|
elixirc_paths: elixirc_paths(Mix.env()),
|
||||||
compilers: [:phoenix] ++ Mix.compilers(),
|
compilers: [:phoenix] ++ Mix.compilers(),
|
||||||
elixirc_options: [warnings_as_errors: warnings_as_errors()],
|
elixirc_options: [warnings_as_errors: warnings_as_errors()],
|
||||||
|
|
14
mix.lock
14
mix.lock
|
@ -27,7 +27,7 @@
|
||||||
"earmark": {:hex, :earmark, "1.4.37", "56ce845c543393aa3f9b294c818c3d783452a4a67e4ab18c4303a954a8b59363", [:mix], [{:earmark_parser, "~> 1.4.31", [hex: :earmark_parser, repo: "hexpm", optional: false]}], "hexpm", "d86d5e12868db86d5321b00e62a4bbcb4150346e4acc9a90a041fb188a5cb106"},
|
"earmark": {:hex, :earmark, "1.4.37", "56ce845c543393aa3f9b294c818c3d783452a4a67e4ab18c4303a954a8b59363", [:mix], [{:earmark_parser, "~> 1.4.31", [hex: :earmark_parser, repo: "hexpm", optional: false]}], "hexpm", "d86d5e12868db86d5321b00e62a4bbcb4150346e4acc9a90a041fb188a5cb106"},
|
||||||
"earmark_parser": {:hex, :earmark_parser, "1.4.31", "a93921cdc6b9b869f519213d5bc79d9e218ba768d7270d46fdcf1c01bacff9e2", [:mix], [], "hexpm", "317d367ee0335ef037a87e46c91a2269fef6306413f731e8ec11fc45a7efd059"},
|
"earmark_parser": {:hex, :earmark_parser, "1.4.31", "a93921cdc6b9b869f519213d5bc79d9e218ba768d7270d46fdcf1c01bacff9e2", [:mix], [], "hexpm", "317d367ee0335ef037a87e46c91a2269fef6306413f731e8ec11fc45a7efd059"},
|
||||||
"eblurhash": {:hex, :eblurhash, "1.2.2", "7da4255aaea984b31bb71155f673257353b0e0554d0d30dcf859547e74602582", [:rebar3], [], "hexpm", "8c20ca00904de023a835a9dcb7b7762fed32264c85a80c3cafa85288e405044c"},
|
"eblurhash": {:hex, :eblurhash, "1.2.2", "7da4255aaea984b31bb71155f673257353b0e0554d0d30dcf859547e74602582", [:rebar3], [], "hexpm", "8c20ca00904de023a835a9dcb7b7762fed32264c85a80c3cafa85288e405044c"},
|
||||||
"ecto": {:hex, :ecto, "3.9.4", "3ee68e25dbe0c36f980f1ba5dd41ee0d3eb0873bccae8aeaf1a2647242bffa35", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "de5f988c142a3aa4ec18b85a4ec34a2390b65b24f02385c1144252ff6ff8ee75"},
|
"ecto": {:hex, :ecto, "3.9.5", "9f0aa7ae44a1577b651c98791c6988cd1b69b21bc724e3fd67090b97f7604263", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d4f3115d8cbacdc0bfa4b742865459fb1371d0715515842a1fb17fe31920b74c"},
|
||||||
"ecto_enum": {:hex, :ecto_enum, "1.4.0", "d14b00e04b974afc69c251632d1e49594d899067ee2b376277efd8233027aec8", [:mix], [{:ecto, ">= 3.0.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "> 3.0.0", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:mariaex, ">= 0.0.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:postgrex, ">= 0.0.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "8fb55c087181c2b15eee406519dc22578fa60dd82c088be376d0010172764ee4"},
|
"ecto_enum": {:hex, :ecto_enum, "1.4.0", "d14b00e04b974afc69c251632d1e49594d899067ee2b376277efd8233027aec8", [:mix], [{:ecto, ">= 3.0.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "> 3.0.0", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:mariaex, ">= 0.0.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:postgrex, ">= 0.0.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "8fb55c087181c2b15eee406519dc22578fa60dd82c088be376d0010172764ee4"},
|
||||||
"ecto_psql_extras": {:hex, :ecto_psql_extras, "0.7.10", "e14d400930f401ca9f541b3349212634e44027d7f919bbb71224d7ac0d0e8acd", [:mix], [{:ecto_sql, "~> 3.4", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.15.7 or ~> 0.16.0", [hex: :postgrex, repo: "hexpm", optional: false]}, {:table_rex, "~> 3.1.1", [hex: :table_rex, repo: "hexpm", optional: false]}], "hexpm", "505e8cd81e4f17c090be0f99e92b1b3f0fd915f98e76965130b8ccfb891e7088"},
|
"ecto_psql_extras": {:hex, :ecto_psql_extras, "0.7.10", "e14d400930f401ca9f541b3349212634e44027d7f919bbb71224d7ac0d0e8acd", [:mix], [{:ecto_sql, "~> 3.4", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.15.7 or ~> 0.16.0", [hex: :postgrex, repo: "hexpm", optional: false]}, {:table_rex, "~> 3.1.1", [hex: :table_rex, repo: "hexpm", optional: false]}], "hexpm", "505e8cd81e4f17c090be0f99e92b1b3f0fd915f98e76965130b8ccfb891e7088"},
|
||||||
"ecto_sql": {:hex, :ecto_sql, "3.9.2", "34227501abe92dba10d9c3495ab6770e75e79b836d114c41108a4bf2ce200ad5", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.9.2", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "1eb5eeb4358fdbcd42eac11c1fbd87e3affd7904e639d77903c1358b2abd3f70"},
|
"ecto_sql": {:hex, :ecto_sql, "3.9.2", "34227501abe92dba10d9c3495ab6770e75e79b836d114c41108a4bf2ce200ad5", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.9.2", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "1eb5eeb4358fdbcd42eac11c1fbd87e3affd7904e639d77903c1358b2abd3f70"},
|
||||||
|
@ -38,7 +38,7 @@
|
||||||
"ex_aws": {:hex, :ex_aws, "2.1.9", "dc4865ecc20a05190a34a0ac5213e3e5e2b0a75a0c2835e923ae7bfeac5e3c31", [:mix], [{:configparser_ex, "~> 4.0", [hex: :configparser_ex, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: true]}, {:jsx, "~> 3.0", [hex: :jsx, repo: "hexpm", optional: true]}, {:sweet_xml, "~> 0.6", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm", "3e6c776703c9076001fbe1f7c049535f042cb2afa0d2cbd3b47cbc4e92ac0d10"},
|
"ex_aws": {:hex, :ex_aws, "2.1.9", "dc4865ecc20a05190a34a0ac5213e3e5e2b0a75a0c2835e923ae7bfeac5e3c31", [:mix], [{:configparser_ex, "~> 4.0", [hex: :configparser_ex, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: true]}, {:jsx, "~> 3.0", [hex: :jsx, repo: "hexpm", optional: true]}, {:sweet_xml, "~> 0.6", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm", "3e6c776703c9076001fbe1f7c049535f042cb2afa0d2cbd3b47cbc4e92ac0d10"},
|
||||||
"ex_aws_s3": {:hex, :ex_aws_s3, "2.4.0", "ce8decb6b523381812798396bc0e3aaa62282e1b40520125d1f4eff4abdff0f4", [:mix], [{:ex_aws, "~> 2.0", [hex: :ex_aws, repo: "hexpm", optional: false]}, {:sweet_xml, ">= 0.0.0", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm", "85dda6e27754d94582869d39cba3241d9ea60b6aa4167f9c88e309dc687e56bb"},
|
"ex_aws_s3": {:hex, :ex_aws_s3, "2.4.0", "ce8decb6b523381812798396bc0e3aaa62282e1b40520125d1f4eff4abdff0f4", [:mix], [{:ex_aws, "~> 2.0", [hex: :ex_aws, repo: "hexpm", optional: false]}, {:sweet_xml, ">= 0.0.0", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm", "85dda6e27754d94582869d39cba3241d9ea60b6aa4167f9c88e309dc687e56bb"},
|
||||||
"ex_const": {:hex, :ex_const, "0.2.4", "d06e540c9d834865b012a17407761455efa71d0ce91e5831e86881b9c9d82448", [:mix], [], "hexpm", "96fd346610cc992b8f896ed26a98be82ac4efb065a0578f334a32d60a3ba9767"},
|
"ex_const": {:hex, :ex_const, "0.2.4", "d06e540c9d834865b012a17407761455efa71d0ce91e5831e86881b9c9d82448", [:mix], [], "hexpm", "96fd346610cc992b8f896ed26a98be82ac4efb065a0578f334a32d60a3ba9767"},
|
||||||
"ex_doc": {:hex, :ex_doc, "0.29.2", "dfa97532ba66910b2a3016a4bbd796f41a86fc71dd5227e96f4c8581fdf0fdf0", [:mix], [{:earmark_parser, "~> 1.4.19", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "6b5d7139eda18a753e3250e27e4a929f8d2c880dd0d460cb9986305dea3e03af"},
|
"ex_doc": {:hex, :ex_doc, "0.29.3", "f07444bcafb302db86e4f02d8bbcd82f2e881a0dcf4f3e4740e4b8128b9353f7", [:mix], [{:earmark_parser, "~> 1.4.31", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "3dc6787d7b08801ec3b51e9bd26be5e8826fbf1a17e92d1ebc252e1a1c75bfe1"},
|
||||||
"ex_machina": {:hex, :ex_machina, "2.7.0", "b792cc3127fd0680fecdb6299235b4727a4944a09ff0fa904cc639272cd92dc7", [:mix], [{:ecto, "~> 2.2 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_sql, "~> 3.0", [hex: :ecto_sql, repo: "hexpm", optional: true]}], "hexpm", "419aa7a39bde11894c87a615c4ecaa52d8f107bbdd81d810465186f783245bf8"},
|
"ex_machina": {:hex, :ex_machina, "2.7.0", "b792cc3127fd0680fecdb6299235b4727a4944a09ff0fa904cc639272cd92dc7", [:mix], [{:ecto, "~> 2.2 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_sql, "~> 3.0", [hex: :ecto_sql, repo: "hexpm", optional: true]}], "hexpm", "419aa7a39bde11894c87a615c4ecaa52d8f107bbdd81d810465186f783245bf8"},
|
||||||
"ex_syslogger": {:hex, :ex_syslogger, "1.5.2", "72b6aa2d47a236e999171f2e1ec18698740f40af0bd02c8c650bf5f1fd1bac79", [:mix], [{:poison, ">= 1.5.0", [hex: :poison, repo: "hexpm", optional: true]}, {:syslog, "~> 1.1.0", [hex: :syslog, repo: "hexpm", optional: false]}], "hexpm", "ab9fab4136dbc62651ec6f16fa4842f10cf02ab4433fa3d0976c01be99398399"},
|
"ex_syslogger": {:hex, :ex_syslogger, "1.5.2", "72b6aa2d47a236e999171f2e1ec18698740f40af0bd02c8c650bf5f1fd1bac79", [:mix], [{:poison, ">= 1.5.0", [hex: :poison, repo: "hexpm", optional: true]}, {:syslog, "~> 1.1.0", [hex: :syslog, repo: "hexpm", optional: false]}], "hexpm", "ab9fab4136dbc62651ec6f16fa4842f10cf02ab4433fa3d0976c01be99398399"},
|
||||||
"excoveralls": {:hex, :excoveralls, "0.15.1", "83c8cf7973dd9d1d853dce37a2fb98aaf29b564bf7d01866e409abf59dac2c0e", [:mix], [{:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "f8416bd90c0082d56a2178cf46c837595a06575f70a5624f164a1ffe37de07e7"},
|
"excoveralls": {:hex, :excoveralls, "0.15.1", "83c8cf7973dd9d1d853dce37a2fb98aaf29b564bf7d01866e409abf59dac2c0e", [:mix], [{:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "f8416bd90c0082d56a2178cf46c837595a06575f70a5624f164a1ffe37de07e7"},
|
||||||
|
@ -86,14 +86,14 @@
|
||||||
"phoenix_ecto": {:hex, :phoenix_ecto, "4.4.0", "0672ed4e4808b3fbed494dded89958e22fb882de47a97634c0b13e7b0b5f7720", [:mix], [{:ecto, "~> 3.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "09864e558ed31ee00bd48fcc1d4fc58ae9678c9e81649075431e69dbabb43cc1"},
|
"phoenix_ecto": {:hex, :phoenix_ecto, "4.4.0", "0672ed4e4808b3fbed494dded89958e22fb882de47a97634c0b13e7b0b5f7720", [:mix], [{:ecto, "~> 3.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "09864e558ed31ee00bd48fcc1d4fc58ae9678c9e81649075431e69dbabb43cc1"},
|
||||||
"phoenix_html": {:hex, :phoenix_html, "3.3.1", "4788757e804a30baac6b3fc9695bf5562465dd3f1da8eb8460ad5b404d9a2178", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "bed1906edd4906a15fd7b412b85b05e521e1f67c9a85418c55999277e553d0d3"},
|
"phoenix_html": {:hex, :phoenix_html, "3.3.1", "4788757e804a30baac6b3fc9695bf5562465dd3f1da8eb8460ad5b404d9a2178", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "bed1906edd4906a15fd7b412b85b05e521e1f67c9a85418c55999277e553d0d3"},
|
||||||
"phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.7.2", "97cc4ff2dba1ebe504db72cb45098cb8e91f11160528b980bd282cc45c73b29c", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.5", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.18.3", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6 or ~> 1.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "0e5fdf063c7a3b620c566a30fcf68b7ee02e5e46fe48ee46a6ec3ba382dc05b7"},
|
"phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.7.2", "97cc4ff2dba1ebe504db72cb45098cb8e91f11160528b980bd282cc45c73b29c", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.5", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.18.3", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6 or ~> 1.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "0e5fdf063c7a3b620c566a30fcf68b7ee02e5e46fe48ee46a6ec3ba382dc05b7"},
|
||||||
"phoenix_live_view": {:hex, :phoenix_live_view, "0.18.17", "74938b02f3c531bed3f87fe1ea39af6b5b2d26ab1405e77e76b8ef5df9ffa8a1", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "f4b5710e19a29b8dc93b7af4bab4739c067a3cb759af01ffc3057165453dce38"},
|
"phoenix_live_view": {:hex, :phoenix_live_view, "0.18.18", "1f38fbd7c363723f19aad1a04b5490ff3a178e37daaf6999594d5f34796c47fc", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a5810d0472f3189ede6d2a95bda7f31c6113156b91784a3426cb0ab6a6d85214"},
|
||||||
"phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.1", "ba04e489ef03763bf28a17eb2eaddc2c20c6d217e2150a61e3298b0f4c2012b5", [:mix], [], "hexpm", "81367c6d1eea5878ad726be80808eb5a787a23dee699f96e72b1109c57cdd8d9"},
|
"phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.1", "ba04e489ef03763bf28a17eb2eaddc2c20c6d217e2150a61e3298b0f4c2012b5", [:mix], [], "hexpm", "81367c6d1eea5878ad726be80808eb5a787a23dee699f96e72b1109c57cdd8d9"},
|
||||||
"phoenix_swoosh": {:hex, :phoenix_swoosh, "0.3.4", "615f8f393135de7e0cbb4bd00ba238b1e0cd324b0d90efbaee613c2f02ca5e5c", [:mix], [{:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:swoosh, "~> 1.0", [hex: :swoosh, repo: "hexpm", optional: false]}], "hexpm", "3971221846232021ab5e3c7489fd62ec5bfd6a2e01cae10a317ccf6fb350571c"},
|
"phoenix_swoosh": {:hex, :phoenix_swoosh, "0.3.4", "615f8f393135de7e0cbb4bd00ba238b1e0cd324b0d90efbaee613c2f02ca5e5c", [:mix], [{:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:swoosh, "~> 1.0", [hex: :swoosh, repo: "hexpm", optional: false]}], "hexpm", "3971221846232021ab5e3c7489fd62ec5bfd6a2e01cae10a317ccf6fb350571c"},
|
||||||
"phoenix_template": {:hex, :phoenix_template, "1.0.1", "85f79e3ad1b0180abb43f9725973e3b8c2c3354a87245f91431eec60553ed3ef", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "157dc078f6226334c91cb32c1865bf3911686f8bcd6bcff86736f6253e6993ee"},
|
"phoenix_template": {:hex, :phoenix_template, "1.0.1", "85f79e3ad1b0180abb43f9725973e3b8c2c3354a87245f91431eec60553ed3ef", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "157dc078f6226334c91cb32c1865bf3911686f8bcd6bcff86736f6253e6993ee"},
|
||||||
"phoenix_view": {:hex, :phoenix_view, "2.0.2", "6bd4d2fd595ef80d33b439ede6a19326b78f0f1d8d62b9a318e3d9c1af351098", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}], "hexpm", "a929e7230ea5c7ee0e149ffcf44ce7cf7f4b6d2bfe1752dd7c084cdff152d36f"},
|
"phoenix_view": {:hex, :phoenix_view, "2.0.2", "6bd4d2fd595ef80d33b439ede6a19326b78f0f1d8d62b9a318e3d9c1af351098", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}], "hexpm", "a929e7230ea5c7ee0e149ffcf44ce7cf7f4b6d2bfe1752dd7c084cdff152d36f"},
|
||||||
"plug": {:hex, :plug, "1.14.0", "ba4f558468f69cbd9f6b356d25443d0b796fbdc887e03fa89001384a9cac638f", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "bf020432c7d4feb7b3af16a0c2701455cbbbb95e5b6866132cb09eb0c29adc14"},
|
"plug": {:hex, :plug, "1.14.2", "cff7d4ec45b4ae176a227acd94a7ab536d9b37b942c8e8fa6dfc0fff98ff4d80", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "842fc50187e13cf4ac3b253d47d9474ed6c296a8732752835ce4a86acdf68d13"},
|
||||||
"plug_cowboy": {:hex, :plug_cowboy, "2.6.0", "d1cf12ff96a1ca4f52207c5271a6c351a4733f413803488d75b70ccf44aebec2", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "073cf20b753ce6682ed72905cd62a2d4bd9bad1bf9f7feb02a1b8e525bd94fa6"},
|
"plug_cowboy": {:hex, :plug_cowboy, "2.6.1", "9a3bbfceeb65eff5f39dab529e5cd79137ac36e913c02067dba3963a26efe9b2", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "de36e1a21f451a18b790f37765db198075c25875c64834bcc82d90b309eb6613"},
|
||||||
"plug_crypto": {:hex, :plug_crypto, "1.2.4", "34c380ef387cc7e8d537854ddd4b7096c79a4397d53587cb80419c782b03fdbc", [:mix], [], "hexpm", "4de415f03faec94d9da9be8c12cb51e9c98cbf66d732b6df669d4562d8e91acc"},
|
"plug_crypto": {:hex, :plug_crypto, "1.2.5", "918772575e48e81e455818229bf719d4ab4181fcbf7f85b68a35620f78d89ced", [:mix], [], "hexpm", "26549a1d6345e2172eb1c233866756ae44a9609bd33ee6f99147ab3fd87fd842"},
|
||||||
"plug_static_index_html": {:hex, :plug_static_index_html, "1.0.0", "840123d4d3975585133485ea86af73cb2600afd7f2a976f9f5fd8b3808e636a0", [:mix], [{:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "79fd4fcf34d110605c26560cbae8f23c603ec4158c08298bd4360fdea90bb5cf"},
|
"plug_static_index_html": {:hex, :plug_static_index_html, "1.0.0", "840123d4d3975585133485ea86af73cb2600afd7f2a976f9f5fd8b3808e636a0", [:mix], [{:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "79fd4fcf34d110605c26560cbae8f23c603ec4158c08298bd4360fdea90bb5cf"},
|
||||||
"poison": {:hex, :poison, "5.0.0", "d2b54589ab4157bbb82ec2050757779bfed724463a544b6e20d79855a9e43b24", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "11dc6117c501b80c62a7594f941d043982a1bd05a1184280c0d9166eb4d8d3fc"},
|
"poison": {:hex, :poison, "5.0.0", "d2b54589ab4157bbb82ec2050757779bfed724463a544b6e20d79855a9e43b24", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "11dc6117c501b80c62a7594f941d043982a1bd05a1184280c0d9166eb4d8d3fc"},
|
||||||
"poolboy": {:hex, :poolboy, "1.5.2", "392b007a1693a64540cead79830443abf5762f5d30cf50bc95cb2c1aaafa006b", [:rebar3], [], "hexpm", "dad79704ce5440f3d5a3681c8590b9dc25d1a561e8f5a9c995281012860901e3"},
|
"poolboy": {:hex, :poolboy, "1.5.2", "392b007a1693a64540cead79830443abf5762f5d30cf50bc95cb2c1aaafa006b", [:rebar3], [], "hexpm", "dad79704ce5440f3d5a3681c8590b9dc25d1a561e8f5a9c995281012860901e3"},
|
||||||
|
@ -117,7 +117,7 @@
|
||||||
"telemetry_poller": {:hex, :telemetry_poller, "0.5.1", "21071cc2e536810bac5628b935521ff3e28f0303e770951158c73eaaa01e962a", [:rebar3], [{:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "4cab72069210bc6e7a080cec9afffad1b33370149ed5d379b81c7c5f0c663fd4"},
|
"telemetry_poller": {:hex, :telemetry_poller, "0.5.1", "21071cc2e536810bac5628b935521ff3e28f0303e770951158c73eaaa01e962a", [:rebar3], [{:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "4cab72069210bc6e7a080cec9afffad1b33370149ed5d379b81c7c5f0c663fd4"},
|
||||||
"temple": {:git, "https://akkoma.dev/AkkomaGang/temple.git", "066a699ade472d8fa42a9d730b29a61af9bc8b59", [ref: "066a699ade472d8fa42a9d730b29a61af9bc8b59"]},
|
"temple": {:git, "https://akkoma.dev/AkkomaGang/temple.git", "066a699ade472d8fa42a9d730b29a61af9bc8b59", [ref: "066a699ade472d8fa42a9d730b29a61af9bc8b59"]},
|
||||||
"tesla": {:hex, :tesla, "1.4.4", "bb89aa0c9745190930366f6a2ac612cdf2d0e4d7fff449861baa7875afd797b2", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: true]}, {:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:finch, "~> 0.3", [hex: :finch, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:gun, "~> 1.3", [hex: :gun, repo: "hexpm", optional: true]}, {:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "4.4.0", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.0", [hex: :mint, repo: "hexpm", optional: true]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "d5503a49f9dec1b287567ea8712d085947e247cb11b06bc54adb05bfde466457"},
|
"tesla": {:hex, :tesla, "1.4.4", "bb89aa0c9745190930366f6a2ac612cdf2d0e4d7fff449861baa7875afd797b2", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: true]}, {:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:finch, "~> 0.3", [hex: :finch, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:gun, "~> 1.3", [hex: :gun, repo: "hexpm", optional: true]}, {:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "4.4.0", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.0", [hex: :mint, repo: "hexpm", optional: true]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "d5503a49f9dec1b287567ea8712d085947e247cb11b06bc54adb05bfde466457"},
|
||||||
"timex": {:hex, :timex, "3.7.9", "790cdfc4acfce434e442f98c02ea6d84d0239073bfd668968f82ac63e9a6788d", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 1.1", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "64691582e5bb87130f721fc709acfb70f24405833998fabf35be968984860ce1"},
|
"timex": {:hex, :timex, "3.7.11", "bb95cb4eb1d06e27346325de506bcc6c30f9c6dea40d1ebe390b262fad1862d1", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.20", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 1.1", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "8b9024f7efbabaf9bd7aa04f65cf8dcd7c9818ca5737677c7b76acbc6a94d1aa"},
|
||||||
"trailing_format_plug": {:hex, :trailing_format_plug, "0.0.7", "64b877f912cf7273bed03379936df39894149e35137ac9509117e59866e10e45", [:mix], [{:plug, "> 0.12.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "bd4fde4c15f3e993a999e019d64347489b91b7a9096af68b2bdadd192afa693f"},
|
"trailing_format_plug": {:hex, :trailing_format_plug, "0.0.7", "64b877f912cf7273bed03379936df39894149e35137ac9509117e59866e10e45", [:mix], [{:plug, "> 0.12.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "bd4fde4c15f3e993a999e019d64347489b91b7a9096af68b2bdadd192afa693f"},
|
||||||
"tzdata": {:hex, :tzdata, "1.1.1", "20c8043476dfda8504952d00adac41c6eda23912278add38edc140ae0c5bcc46", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "a69cec8352eafcd2e198dea28a34113b60fdc6cb57eb5ad65c10292a6ba89787"},
|
"tzdata": {:hex, :tzdata, "1.1.1", "20c8043476dfda8504952d00adac41c6eda23912278add38edc140ae0c5bcc46", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "a69cec8352eafcd2e198dea28a34113b60fdc6cb57eb5ad65c10292a6ba89787"},
|
||||||
"ueberauth": {:hex, :ueberauth, "0.10.5", "806adb703df87e55b5615cf365e809f84c20c68aa8c08ff8a416a5a6644c4b02", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "3efd1f31d490a125c7ed453b926f7c31d78b97b8a854c755f5c40064bf3ac9e1"},
|
"ueberauth": {:hex, :ueberauth, "0.10.5", "806adb703df87e55b5615cf365e809f84c20c68aa8c08ff8a416a5a6644c4b02", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "3efd1f31d490a125c7ed453b926f7c31d78b97b8a854c755f5c40064bf3ac9e1"},
|
||||||
|
|
BIN
priv/static/emoji/hehe.png
Normal file
BIN
priv/static/emoji/hehe.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
BIN
priv/static/emoji/nothehe.png
Normal file
BIN
priv/static/emoji/nothehe.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
|
@ -2509,6 +2509,16 @@ test "avatar fallback" do
|
||||||
assert User.avatar_url(user, no_default: true) == nil
|
assert User.avatar_url(user, no_default: true) == nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "avatar object with nil in href" do
|
||||||
|
user = insert(:user, avatar: %{"url" => [%{"href" => nil}]})
|
||||||
|
assert User.avatar_url(user) != nil
|
||||||
|
end
|
||||||
|
|
||||||
|
test "banner object with nil in href" do
|
||||||
|
user = insert(:user, banner: %{"url" => [%{"href" => nil}]})
|
||||||
|
assert User.banner_url(user) != nil
|
||||||
|
end
|
||||||
|
|
||||||
test "get_host/1" do
|
test "get_host/1" do
|
||||||
user = insert(:user, ap_id: "https://lain.com/users/lain", nickname: "lain")
|
user = insert(:user, ap_id: "https://lain.com/users/lain", nickname: "lain")
|
||||||
assert User.get_host(user) == "lain.com"
|
assert User.get_host(user) == "lain.com"
|
||||||
|
|
|
@ -1303,6 +1303,14 @@ test "returns reblogs for users for whom reblogs have not been muted" do
|
||||||
%{test_file: test_file}
|
%{test_file: test_file}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "strips / from filename", %{test_file: file} do
|
||||||
|
file = %Plug.Upload{file | filename: "../../../../../nested/bad.jpg"}
|
||||||
|
{:ok, %Object{} = object} = ActivityPub.upload(file)
|
||||||
|
[%{"href" => href}] = object.data["url"]
|
||||||
|
assert Regex.match?(~r"/bad.jpg$", href)
|
||||||
|
refute Regex.match?(~r"/nested/", href)
|
||||||
|
end
|
||||||
|
|
||||||
test "sets a description if given", %{test_file: file} do
|
test "sets a description if given", %{test_file: file} do
|
||||||
{:ok, %Object{} = object} = ActivityPub.upload(file, description: "a cool file")
|
{:ok, %Object{} = object} = ActivityPub.upload(file, description: "a cool file")
|
||||||
assert object.data["name"] == "a cool file"
|
assert object.data["name"] == "a cool file"
|
||||||
|
|
|
@ -124,6 +124,23 @@ test "/api/v2/media, upload_limit", %{conn: conn, user: user} do
|
||||||
|
|
||||||
assert :ok == File.rm(Path.absname("test/tmp/large_binary.data"))
|
assert :ok == File.rm(Path.absname("test/tmp/large_binary.data"))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "Do not allow nested filename", %{conn: conn, image: image} do
|
||||||
|
image = %Plug.Upload{
|
||||||
|
image
|
||||||
|
| filename: "../../../../../nested/file.jpg"
|
||||||
|
}
|
||||||
|
|
||||||
|
desc = "Description of the image"
|
||||||
|
|
||||||
|
media =
|
||||||
|
conn
|
||||||
|
|> put_req_header("content-type", "multipart/form-data")
|
||||||
|
|> post("/api/v1/media", %{"file" => image, "description" => desc})
|
||||||
|
|> json_response_and_validate_schema(:ok)
|
||||||
|
|
||||||
|
refute Regex.match?(~r"/nested/", media["url"])
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "Update media description" do
|
describe "Update media description" do
|
||||||
|
|
|
@ -408,6 +408,26 @@ test "should not return local-only posts for anonymous users" do
|
||||||
|
|
||||||
assert [] = result
|
assert [] = result
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
defp local_and_remote_activities do
|
defp local_and_remote_activities do
|
||||||
|
@ -1036,9 +1056,8 @@ test "with `%{local: true, federated: false}`, forbids unauthenticated access to
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "bubble" do
|
describe "bubble" do
|
||||||
setup do: oauth_access(["read:statuses"])
|
test "filtering" do
|
||||||
|
%{conn: conn, user: user} = oauth_access(["read:statuses"])
|
||||||
test "filtering", %{conn: conn, user: user} do
|
|
||||||
clear_config([:instance, :local_bubble], [])
|
clear_config([:instance, :local_bubble], [])
|
||||||
# our endpoint host has a port in it so let's set the AP ID
|
# our endpoint host has a port in it so let's set the AP ID
|
||||||
local_user = insert(:user, %{ap_id: "https://localhost/users/user"})
|
local_user = insert(:user, %{ap_id: "https://localhost/users/user"})
|
||||||
|
@ -1072,6 +1091,20 @@ test "filtering", %{conn: conn, user: user} do
|
||||||
assert local_activity.id in two_instances
|
assert local_activity.id in two_instances
|
||||||
assert remote_activity.id in two_instances
|
assert remote_activity.id in two_instances
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
defp create_remote_activity(user) do
|
defp create_remote_activity(user) do
|
||||||
|
|
|
@ -396,6 +396,34 @@ test "updates the user's background, upload_limit, returns a HTTP 413", %{
|
||||||
assert :ok == File.rm(Path.absname("test/tmp/large_binary.data"))
|
assert :ok == File.rm(Path.absname("test/tmp/large_binary.data"))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "Strip / from upload files", %{user: user, conn: conn} do
|
||||||
|
new_image = %Plug.Upload{
|
||||||
|
content_type: "image/jpeg",
|
||||||
|
path: Path.absname("test/fixtures/image.jpg"),
|
||||||
|
filename: "../../../../nested/an_image.jpg"
|
||||||
|
}
|
||||||
|
|
||||||
|
assert user.avatar == %{}
|
||||||
|
|
||||||
|
res =
|
||||||
|
patch(conn, "/api/v1/accounts/update_credentials", %{
|
||||||
|
"avatar" => new_image,
|
||||||
|
"header" => new_image,
|
||||||
|
"pleroma_background_image" => new_image
|
||||||
|
})
|
||||||
|
|
||||||
|
assert user_response = json_response_and_validate_schema(res, 200)
|
||||||
|
assert user_response["avatar"]
|
||||||
|
assert user_response["header"]
|
||||||
|
assert user_response["pleroma"]["background_image"]
|
||||||
|
refute Regex.match?(~r"/nested/", user_response["avatar"])
|
||||||
|
refute Regex.match?(~r"/nested/", user_response["header"])
|
||||||
|
refute Regex.match?(~r"/nested/", user_response["pleroma"]["background_image"])
|
||||||
|
|
||||||
|
user = User.get_by_id(user.id)
|
||||||
|
refute user.avatar == %{}
|
||||||
|
end
|
||||||
|
|
||||||
test "requires 'write:accounts' permission" do
|
test "requires 'write:accounts' permission" do
|
||||||
token1 = insert(:oauth_token, scopes: ["read"])
|
token1 = insert(:oauth_token, scopes: ["read"])
|
||||||
token2 = insert(:oauth_token, scopes: ["write", "follow"])
|
token2 = insert(:oauth_token, scopes: ["write", "follow"])
|
||||||
|
|
|
@ -269,8 +269,8 @@ test "Represent a Service(bot) account" do
|
||||||
}
|
}
|
||||||
|
|
||||||
with_mock(
|
with_mock(
|
||||||
Pleroma.Web.Nodeinfo.NodeinfoController,
|
Pleroma.Web.Nodeinfo.Nodeinfo,
|
||||||
raw_nodeinfo: fn -> %{version: "2.0"} end
|
get_nodeinfo: fn _ -> %{version: "2.0"} end
|
||||||
) do
|
) do
|
||||||
assert expected ==
|
assert expected ==
|
||||||
AccountView.render("show.json", %{user: user, skip_visibility_check: true})
|
AccountView.render("show.json", %{user: user, skip_visibility_check: true})
|
||||||
|
|
|
@ -292,4 +292,38 @@ test "shows extra information in the mrf_simple_info field for relevant entries"
|
||||||
assert response["metadata"]["federation"]["mrf_simple_info"] == expected_config
|
assert response["metadata"]["federation"]["mrf_simple_info"] == expected_config
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "public timeline visibility" do
|
||||||
|
test "shows public timeline visibility", %{conn: conn} do
|
||||||
|
clear_config([:restrict_unauthenticated, :timelines], %{local: false, federated: false})
|
||||||
|
|
||||||
|
response =
|
||||||
|
conn
|
||||||
|
|> get("/nodeinfo/2.1.json")
|
||||||
|
|> json_response(:ok)
|
||||||
|
|
||||||
|
assert response["metadata"]["publicTimelineVisibility"]["local"] == true
|
||||||
|
assert response["metadata"]["publicTimelineVisibility"]["federated"] == true
|
||||||
|
|
||||||
|
clear_config([:restrict_unauthenticated, :timelines], %{local: true, federated: false})
|
||||||
|
|
||||||
|
response =
|
||||||
|
conn
|
||||||
|
|> get("/nodeinfo/2.1.json")
|
||||||
|
|> json_response(:ok)
|
||||||
|
|
||||||
|
assert response["metadata"]["publicTimelineVisibility"]["local"] == false
|
||||||
|
assert response["metadata"]["publicTimelineVisibility"]["federated"] == true
|
||||||
|
|
||||||
|
clear_config([:restrict_unauthenticated, :timelines], %{local: false, federated: true})
|
||||||
|
|
||||||
|
response =
|
||||||
|
conn
|
||||||
|
|> get("/nodeinfo/2.1.json")
|
||||||
|
|> json_response(:ok)
|
||||||
|
|
||||||
|
assert response["metadata"]["publicTimelineVisibility"]["local"] == true
|
||||||
|
assert response["metadata"]["publicTimelineVisibility"]["federated"] == false
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue