Merge branch 'develop' of ssh://git.pleroma.social:2222/pleroma/pleroma into froth

This commit is contained in:
Sam Therapy 2023-03-23 13:14:43 +01:00
commit 5b7c7089a7
Signed by: sam
GPG key ID: 4D8B07C18F31ACBD
147 changed files with 1370 additions and 285 deletions

View file

@ -12,7 +12,28 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Fixed
- rel="me" was missing its cache
### Removed
- BREAKING: Support for passwords generated with `crypt(3)` (Gnu Social migration artifact)
## 2.5.1
### Added
- Allow customizing instance languages
### Fixed
- Security: uploading HTTP endpoint can no longer create directories in the upload dir (internal APIs, like backup, still can do it.)
- ~ character in urls in Markdown posts are handled properly
- Exiftool upload filter will now ignore SVG files
- Fix `block_from_stranger` setting
- Fix rel="me"
- Docker images will now run properly
- Fix inproper content being cached in report content
- Notification filter on object content will not operate on the ones that inherently have no content
- ZWNJ and double dots in links are parsed properly for Plain-text posts
- OTP releases will work on systems with a newer libcrypt
- Errors when running Exiftool.ReadDescription filter will not be filled into the image description
## 2.5.0 - 2022-12-23

View file

@ -1,4 +1,8 @@
FROM elixir:1.11.4-alpine as build
ARG ELIXIR_VER=1.11.4
ARG ERLANG_VER=24.2.1
ARG ALPINE_VER=3.17.0
FROM hexpm/elixir:${ELIXIR_VER}-erlang-${ERLANG_VER}-alpine-${ALPINE_VER} as build
COPY . .
@ -12,7 +16,7 @@ RUN apk add git gcc g++ musl-dev make cmake file-dev &&\
mkdir release &&\
mix release --path release
FROM alpine
FROM alpine:${ALPINE_VER}
ARG BUILD_DATE
ARG VCS_REF

View file

@ -1052,6 +1052,15 @@
description:
"Minimum required age (in days) for users to create account. Only used if birthday is required.",
suggestions: [6570]
},
%{
key: :languages,
type: {:list, :string},
description:
"Languages to be exposed in /api/v1/instance. Should be in the format of BCP47 language codes.",
suggestions: [
"en"
]
}
]
},

View file

@ -2,15 +2,16 @@
{! backend/installation/otp_vs_from_source.include !}
This guide covers a installation using an OTP release. To install Pleroma from source, please check out the corresponding guide for your distro.
This guide covers a installation using OTP releases as built by the Pleroma project, it is meant as a fallback to distribution packages/recipes which are the preferred installation method.
To install Pleroma from source, please check out the corresponding guide for your distro.
## Pre-requisites
* A machine running Linux with GNU (e.g. Debian, Ubuntu) or musl (e.g. Alpine) libc and `x86_64`, `aarch64` or `armv7l` CPU, you have root access to. If you are not sure if it's compatible see [Detecting flavour section](#detecting-flavour) below
* A machine you have root access to running Debian GNU/Linux or compatible (eg. Ubuntu), or Alpine on `x86_64`, `aarch64` or `armv7l` CPU. If you are not sure what you are running see [Detecting flavour section](#detecting-flavour) below
* A (sub)domain pointed to the machine
You will be running commands as root. If you aren't root already, please elevate your privileges by executing `sudo su`/`su`.
You will be running commands as root. If you aren't root already, please elevate your privileges by executing `sudo -i`/`su`.
While in theory OTP releases are possbile to install on any compatible machine, for the sake of simplicity this guide focuses only on Debian/Ubuntu and Alpine.
Similarly to other binaries, OTP releases tend to be only compatible with the distro they are built on, as such this guide focuses only on Debian/Ubuntu and Alpine.
### Detecting flavour
@ -19,7 +20,7 @@ Paste the following into the shell:
arch="$(uname -m)";if [ "$arch" = "x86_64" ];then arch="amd64";elif [ "$arch" = "armv7l" ];then arch="arm";elif [ "$arch" = "aarch64" ];then arch="arm64";else echo "Unsupported arch: $arch">&2;fi;if getconf GNU_LIBC_VERSION>/dev/null;then libc_postfix="";elif [ "$(ldd 2>&1|head -c 9)" = "musl libc" ];then libc_postfix="-musl";elif [ "$(find /lib/libc.musl*|wc -l)" ];then libc_postfix="-musl";else echo "Unsupported libc">&2;fi;echo "$arch$libc_postfix"
```
If your platform is supported the output will contain the flavour string, you will need it later. If not, this just means that we don't build releases for your platform, you can still try installing from source.
This should give your flavour string. If not this just means that we don't build releases for your platform, you can still try installing from source.
### Installing the required packages

View file

@ -6,7 +6,70 @@ defmodule Mix.Tasks.Pleroma.OpenapiSpec do
def run([path]) do
# Load Pleroma application to get version info
Application.load(:pleroma)
spec = Pleroma.Web.ApiSpec.spec(server_specific: false) |> Jason.encode!()
File.write(path, spec)
spec_json = Pleroma.Web.ApiSpec.spec(server_specific: false) |> Jason.encode!()
# to get rid of the structs
spec_regened = spec_json |> Jason.decode!()
check_specs!(spec_regened)
File.write(path, spec_json)
end
defp check_specs!(spec) do
with :ok <- check_specs(spec) do
:ok
else
{_, errors} ->
IO.puts(IO.ANSI.format([:red, :bright, "Spec check failed, errors:"]))
Enum.map(errors, &IO.puts/1)
raise "Spec check failed"
end
end
def check_specs(spec) do
errors =
spec["paths"]
|> Enum.flat_map(fn {path, %{} = endpoints} ->
Enum.map(
endpoints,
fn {method, endpoint} ->
with :ok <- check_endpoint(spec, endpoint) do
:ok
else
error ->
"#{endpoint["operationId"]} (#{method} #{path}): #{error}"
end
end
)
|> Enum.reject(fn res -> res == :ok end)
end)
if errors == [] do
:ok
else
{:error, errors}
end
end
defp check_endpoint(spec, endpoint) do
valid_tags = available_tags(spec)
with {_, [_ | _] = tags} <- {:tags, endpoint["tags"]},
{_, []} <- {:unavailable, Enum.reject(tags, &(&1 in valid_tags))} do
:ok
else
{:tags, _} ->
"No tags specified"
{:unavailable, tags} ->
"Tags #{inspect(tags)} not available. Please add it in \"x-tagGroups\" in Pleroma.Web.ApiSpec"
end
end
defp available_tags(spec) do
spec["x-tagGroups"]
|> Enum.flat_map(fn %{"tags" => tags} -> tags end)
end
end

View file

@ -209,7 +209,8 @@ defp cachex_children do
build_cachex("chat_message_id_idempotency_key",
expiration: chat_message_id_idempotency_key_expiration(),
limit: 500_000
)
),
build_cachex("rel_me", limit: 2500)
]
end

View file

@ -51,6 +51,8 @@ def reload do
@doc "Returns the path of the emoji `name`."
@spec get(String.t()) :: String.t() | nil
def get(name) do
name = maybe_strip_name(name)
case :ets.lookup(@ets, name) do
[{_, path}] -> path
_ -> nil
@ -139,6 +141,57 @@ def is_unicode_emoji?(unquote(emoji)), do: true
def is_unicode_emoji?(_), do: false
@emoji_regex ~r/:[A-Za-z0-9_-]+(@.+)?:/
def is_custom_emoji?(s) when is_binary(s), do: Regex.match?(@emoji_regex, s)
def is_custom_emoji?(_), do: false
def maybe_strip_name(name) when is_binary(name), do: String.trim(name, ":")
def maybe_strip_name(name), do: name
def maybe_quote(name) when is_binary(name) do
if is_unicode_emoji?(name) do
name
else
if String.starts_with?(name, ":") do
name
else
":#{name}:"
end
end
end
def maybe_quote(name), do: name
def emoji_url(%{"type" => "EmojiReact", "content" => _, "tag" => []}), do: nil
def emoji_url(%{"type" => "EmojiReact", "content" => emoji, "tag" => tags}) do
emoji = maybe_strip_name(emoji)
tag =
tags
|> Enum.find(fn tag ->
tag["type"] == "Emoji" && !is_nil(tag["name"]) && tag["name"] == emoji
end)
if is_nil(tag) do
nil
else
tag
|> Map.get("icon")
|> Map.get("url")
end
end
def emoji_url(_), do: nil
def emoji_name_with_instance(name, url) do
url = url |> URI.parse() |> Map.get(:host)
"#{name}@#{url}"
end
emoji_qualification_map =
emojis
|> Enum.filter(&String.contains?(&1, "\uFE0F"))

View file

@ -178,6 +178,7 @@ defp exclude_filtered(query, user) do
from([_n, a, o] in query,
where:
fragment("not(?->>'content' ~* ?)", o.data, ^regex) or
fragment("?->>'content' is null", o.data) or
fragment("?->>'actor' = ?", o.data, ^user.ap_id)
)
end
@ -679,7 +680,7 @@ def skip?(
cond do
opts[:type] == "poll" -> false
user.ap_id == actor -> false
!User.following?(follower, user) -> true
!User.following?(user, follower) -> true
true -> false
end
end

View file

@ -33,7 +33,10 @@ defp read_when_empty(current_description, _, _) when is_binary(current_descripti
defp read_when_empty(_, file, tag) do
try do
{tag_content, 0} =
System.cmd("exiftool", ["-b", "-s3", tag, file], stderr_to_stdout: true, parallelism: true)
System.cmd("exiftool", ["-b", "-s3", tag, file],
stderr_to_stdout: false,
parallelism: true
)
tag_content = String.trim(tag_content)

View file

@ -1453,13 +1453,22 @@ def fetch_activities_bounded(
@spec upload(Upload.source(), keyword()) :: {:ok, Object.t()} | {:error, any()}
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])
Repo.insert(%Object{data: obj_data})
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
defp get_actor_url(url) when is_binary(url), do: url
defp get_actor_url(%{"href" => href}) when is_binary(href), do: href

View file

@ -16,6 +16,7 @@ defmodule Pleroma.Web.ActivityPub.Builder do
alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.ActivityPub.Visibility
alias Pleroma.Web.CommonAPI.ActivityDraft
alias Pleroma.Web.Endpoint
require Pleroma.Constants
@ -54,13 +55,87 @@ def follow(follower, followed) do
{:ok, data, []}
end
defp unicode_emoji_react(_object, data, emoji) do
data
|> Map.put("content", emoji)
|> Map.put("type", "EmojiReact")
end
defp add_emoji_content(data, emoji, url) do
tag = [
%{
"id" => url,
"type" => "Emoji",
"name" => Emoji.maybe_quote(emoji),
"icon" => %{
"type" => "Image",
"url" => url
}
}
]
data
|> Map.put("content", Emoji.maybe_quote(emoji))
|> Map.put("type", "EmojiReact")
|> Map.put("tag", tag)
end
defp remote_custom_emoji_react(
%{data: %{"reactions" => existing_reactions}},
data,
emoji
) do
[emoji_code, instance] = String.split(Emoji.maybe_strip_name(emoji), "@")
matching_reaction =
Enum.find(
existing_reactions,
fn [name, _, url] ->
if url != nil do
url = URI.parse(url)
url.host == instance && name == emoji_code
end
end
)
if matching_reaction do
[name, _, url] = matching_reaction
add_emoji_content(data, name, url)
else
{:error, "Could not react"}
end
end
defp remote_custom_emoji_react(_object, _data, _emoji) do
{:error, "Could not react"}
end
defp local_custom_emoji_react(data, emoji) do
with %{file: path} = emojo <- Emoji.get(emoji) do
url = "#{Endpoint.url()}#{path}"
add_emoji_content(data, emojo.code, url)
else
_ -> {:error, "Emoji does not exist"}
end
end
defp custom_emoji_react(object, data, emoji) do
if String.contains?(emoji, "@") do
remote_custom_emoji_react(object, data, emoji)
else
local_custom_emoji_react(data, emoji)
end
end
@spec emoji_react(User.t(), Object.t(), String.t()) :: {:ok, map(), keyword()}
def emoji_react(actor, object, emoji) do
with {:ok, data, meta} <- object_action(actor, object) do
data =
data
|> Map.put("content", emoji)
|> Map.put("type", "EmojiReact")
if Emoji.is_unicode_emoji?(emoji) do
unicode_emoji_react(object, data, emoji)
else
custom_emoji_react(object, data, emoji)
end
{:ok, data, meta}
end

View file

@ -5,8 +5,10 @@
defmodule Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactValidator do
use Ecto.Schema
alias Pleroma.Emoji
alias Pleroma.Object
alias Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes
alias Pleroma.Web.ActivityPub.ObjectValidators.TagValidator
import Ecto.Changeset
import Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
@ -19,6 +21,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactValidator do
import Elixir.Pleroma.Web.ActivityPub.ObjectValidators.CommonFields
message_fields()
activity_fields()
embeds_many(:tag, TagValidator)
end
end
@ -43,7 +46,8 @@ def cast_data(data) do
def changeset(struct, data) do
struct
|> cast(data, __schema__(:fields))
|> cast(data, __schema__(:fields) -- [:tag])
|> cast_embed(:tag)
end
defp fix(data) do
@ -53,12 +57,16 @@ defp fix(data) do
|> CommonFixes.fix_actor()
|> CommonFixes.fix_activity_addressing()
with %Object{} = object <- Object.normalize(data["object"]) do
data
|> CommonFixes.fix_activity_context(object)
|> CommonFixes.fix_object_action_recipients(object)
else
_ -> data
data = Map.put_new(data, "tag", [])
case Object.normalize(data["object"]) do
%Object{} = object ->
data
|> CommonFixes.fix_activity_context(object)
|> CommonFixes.fix_object_action_recipients(object)
_ ->
data
end
end
@ -82,11 +90,31 @@ defp fix_emoji_qualification(data), do: data
defp validate_emoji(cng) do
content = get_field(cng, :content)
if Pleroma.Emoji.is_unicode_emoji?(content) do
if Emoji.is_unicode_emoji?(content) || Emoji.is_custom_emoji?(content) do
cng
else
cng
|> add_error(:content, "must be a single character emoji")
|> add_error(:content, "is not a valid emoji")
end
end
defp maybe_validate_tag_presence(cng) do
content = get_field(cng, :content)
if Emoji.is_unicode_emoji?(content) do
cng
else
tag = get_field(cng, :tag)
emoji_name = Emoji.maybe_strip_name(content)
case tag do
[%{name: ^emoji_name, type: "Emoji", icon: %{url: _}}] ->
cng
_ ->
cng
|> add_error(:tag, "does not contain an Emoji tag")
end
end
end
@ -97,5 +125,6 @@ defp validate_data(data_cng) do
|> validate_actor_presence()
|> validate_object_presence()
|> validate_emoji()
|> maybe_validate_tag_presence()
end
end

View file

@ -325,21 +325,29 @@ def update_element_in_object(property, element, object, count \\ nil) do
{:ok, Object.t()} | {:error, Ecto.Changeset.t()}
def add_emoji_reaction_to_object(
%Activity{data: %{"content" => emoji, "actor" => actor}},
%Activity{data: %{"content" => emoji, "actor" => actor}} = activity,
object
) do
reactions = get_cached_emoji_reactions(object)
emoji = Pleroma.Emoji.maybe_strip_name(emoji)
url = maybe_emoji_url(emoji, activity)
new_reactions =
case Enum.find_index(reactions, fn [candidate, _] -> emoji == candidate end) do
case Enum.find_index(reactions, fn [candidate, _, candidate_url] ->
if is_nil(candidate_url) do
emoji == candidate
else
url == candidate_url
end
end) do
nil ->
reactions ++ [[emoji, [actor]]]
reactions ++ [[emoji, [actor], url]]
index ->
List.update_at(
reactions,
index,
fn [emoji, users] -> [emoji, Enum.uniq([actor | users])] end
fn [emoji, users, url] -> [emoji, Enum.uniq([actor | users]), url] end
)
end
@ -348,18 +356,40 @@ def add_emoji_reaction_to_object(
update_element_in_object("reaction", new_reactions, object, count)
end
defp maybe_emoji_url(
name,
%Activity{
data: %{
"tag" => [
%{"type" => "Emoji", "name" => name, "icon" => %{"url" => url}}
]
}
}
),
do: url
defp maybe_emoji_url(_, _), do: nil
def emoji_count(reactions_list) do
Enum.reduce(reactions_list, 0, fn [_, users], acc -> acc + length(users) end)
Enum.reduce(reactions_list, 0, fn [_, users, _], acc -> acc + length(users) end)
end
def remove_emoji_reaction_from_object(
%Activity{data: %{"content" => emoji, "actor" => actor}},
%Activity{data: %{"content" => emoji, "actor" => actor}} = activity,
object
) do
emoji = Pleroma.Emoji.maybe_strip_name(emoji)
reactions = get_cached_emoji_reactions(object)
url = maybe_emoji_url(emoji, activity)
new_reactions =
case Enum.find_index(reactions, fn [candidate, _] -> emoji == candidate end) do
case Enum.find_index(reactions, fn [candidate, _, candidate_url] ->
if is_nil(candidate_url) do
emoji == candidate
else
url == candidate_url
end
end) do
nil ->
reactions
@ -367,9 +397,9 @@ def remove_emoji_reaction_from_object(
List.update_at(
reactions,
index,
fn [emoji, users] -> [emoji, List.delete(users, actor)] end
fn [emoji, users, url] -> [emoji, List.delete(users, actor), url] end
)
|> Enum.reject(fn [_, users] -> Enum.empty?(users) end)
|> Enum.reject(fn [_, users, _] -> Enum.empty?(users) end)
end
count = emoji_count(new_reactions)
@ -489,17 +519,37 @@ def fetch_latest_undo(%User{ap_id: ap_id}) do
def get_latest_reaction(internal_activity_id, %{ap_id: ap_id}, emoji) do
%{data: %{"object" => object_ap_id}} = Activity.get_by_id(internal_activity_id)
emoji = Pleroma.Emoji.maybe_quote(emoji)
"EmojiReact"
|> Activity.Queries.by_type()
|> where(actor: ^ap_id)
|> where([activity], fragment("?->>'content' = ?", activity.data, ^emoji))
|> custom_emoji_discriminator(emoji)
|> Activity.Queries.by_object_id(object_ap_id)
|> order_by([activity], fragment("? desc nulls last", activity.id))
|> limit(1)
|> Repo.one()
end
defp custom_emoji_discriminator(query, emoji) do
if String.contains?(emoji, "@") do
stripped = Pleroma.Emoji.maybe_strip_name(emoji)
[name, domain] = String.split(stripped, "@")
domain_pattern = "%/" <> domain <> "/%"
emoji_pattern = Pleroma.Emoji.maybe_quote(name)
query
|> where([activity], fragment("?->>'content' = ?
AND EXISTS (
SELECT FROM jsonb_array_elements(?->'tag') elem
WHERE elem->>'id' ILIKE ?
)", activity.data, ^emoji_pattern, activity.data, ^domain_pattern))
else
query
|> where([activity], fragment("?->>'content' = ?", activity.data, ^emoji))
end
end
#### Announce-related helpers
@doc """

View file

@ -31,7 +31,7 @@ def extract_report_info(
defp make_fake_activity(act, user) do
%Activity{
id: "pleroma:fake",
id: "pleroma:fake:#{act["id"]}",
data: %{
"actor" => user.ap_id,
"type" => "Create",

View file

@ -95,7 +95,8 @@ def spec(opts \\ []) do
"Relays",
"Report managment",
"Status administration",
"User administration"
"User administration",
"Announcement management"
]
},
%{"name" => "Applications", "tags" => ["Applications", "Push subscriptions"]},
@ -110,10 +111,12 @@ def spec(opts \\ []) do
"Follow requests",
"Mascot",
"Markers",
"Notifications"
"Notifications",
"Filters",
"Settings"
]
},
%{"name" => "Instance", "tags" => ["Custom emojis"]},
%{"name" => "Instance", "tags" => ["Custom emojis", "Instance misc"]},
%{"name" => "Messaging", "tags" => ["Chats", "Conversations"]},
%{
"name" => "Statuses",
@ -125,10 +128,21 @@ def spec(opts \\ []) do
"Retrieve status information",
"Scheduled statuses",
"Search",
"Status actions"
"Status actions",
"Media attachments"
]
},
%{"name" => "Miscellaneous", "tags" => ["Emoji packs", "Reports", "Suggestions"]}
%{
"name" => "Miscellaneous",
"tags" => [
"Emoji packs",
"Reports",
"Suggestions",
"Announcements",
"Remote interaction",
"Others"
]
}
]
}
}

View file

@ -452,7 +452,7 @@ def blocks_operation do
operationId: "AccountController.blocks",
description: "View your blocks. See also accounts/:id/{block,unblock}",
security: [%{"oAuth" => ["read:blocks"]}],
parameters: pagination_params(),
parameters: [with_relationships_param() | pagination_params()],
responses: %{
200 => Operation.response("Accounts", "application/json", array_of_accounts())
}
@ -461,7 +461,7 @@ def blocks_operation do
def lookup_operation do
%Operation{
tags: ["Account lookup"],
tags: ["Retrieve account information"],
summary: "Find a user by nickname",
operationId: "AccountController.lookup",
parameters: [

View file

@ -17,7 +17,7 @@ def open_api_operation(action) do
def index_operation do
%Operation{
tags: ["Announcement managment"],
tags: ["Announcement management"],
summary: "Retrieve a list of announcements",
operationId: "AdminAPI.AnnouncementController.index",
security: [%{"oAuth" => ["admin:read"]}],
@ -46,7 +46,7 @@ def index_operation do
def show_operation do
%Operation{
tags: ["Announcement managment"],
tags: ["Announcement management"],
summary: "Display one announcement",
operationId: "AdminAPI.AnnouncementController.show",
security: [%{"oAuth" => ["admin:read"]}],
@ -69,7 +69,7 @@ def show_operation do
def delete_operation do
%Operation{
tags: ["Announcement managment"],
tags: ["Announcement management"],
summary: "Delete one announcement",
operationId: "AdminAPI.AnnouncementController.delete",
security: [%{"oAuth" => ["admin:write"]}],
@ -92,7 +92,7 @@ def delete_operation do
def create_operation do
%Operation{
tags: ["Announcement managment"],
tags: ["Announcement management"],
summary: "Create one announcement",
operationId: "AdminAPI.AnnouncementController.create",
security: [%{"oAuth" => ["admin:write"]}],
@ -107,7 +107,7 @@ def create_operation do
def change_operation do
%Operation{
tags: ["Announcement managment"],
tags: ["Announcement management"],
summary: "Change one announcement",
operationId: "AdminAPI.AnnouncementController.change",
security: [%{"oAuth" => ["admin:write"]}],

View file

@ -70,7 +70,7 @@ def index_operation do
def show_operation do
%Operation{
tags: ["Status adminitration)"],
tags: ["Status administration"],
summary: "Get status",
operationId: "AdminAPI.StatusController.show",
parameters: [id_param() | admin_api_params()],
@ -84,7 +84,7 @@ def show_operation do
def update_operation do
%Operation{
tags: ["Status adminitration)"],
tags: ["Status administration"],
summary: "Change the scope of a status",
operationId: "AdminAPI.StatusController.update",
parameters: [id_param() | admin_api_params()],
@ -99,7 +99,7 @@ def update_operation do
def delete_operation do
%Operation{
tags: ["Status adminitration)"],
tags: ["Status administration"],
summary: "Delete status",
operationId: "AdminAPI.StatusController.delete",
parameters: [id_param() | admin_api_params()],
@ -143,7 +143,7 @@ def admin_account do
}
},
tags: %Schema{type: :string},
is_confirmed: %Schema{type: :string}
is_confirmed: %Schema{type: :boolean}
}
}
end

View file

@ -15,7 +15,7 @@ def open_api_operation(action) do
def index_operation do
%Operation{
tags: ["Announcement"],
tags: ["Announcements"],
summary: "Retrieve a list of announcements",
operationId: "MastodonAPI.AnnouncementController.index",
security: [%{"oAuth" => []}],
@ -28,7 +28,7 @@ def index_operation do
def mark_read_operation do
%Operation{
tags: ["Announcement"],
tags: ["Announcements"],
summary: "Mark one announcement as read",
operationId: "MastodonAPI.AnnouncementController.mark_read",
security: [%{"oAuth" => ["write:accounts"]}],

View file

@ -17,7 +17,7 @@ def open_api_operation(action) do
def index_operation do
%Operation{
tags: ["Directory"],
tags: ["Others"],
summary: "Profile directory",
operationId: "DirectoryController.index",
parameters:

View file

@ -13,7 +13,7 @@ def open_api_operation(action) do
def show_operation do
%Operation{
tags: ["Instance"],
tags: ["Instance misc"],
summary: "Retrieve instance information",
description: "Information about the server",
operationId: "InstanceController.show",
@ -25,7 +25,7 @@ def show_operation do
def peers_operation do
%Operation{
tags: ["Instance"],
tags: ["Instance misc"],
summary: "Retrieve list of known instances",
operationId: "InstanceController.peers",
responses: %{

View file

@ -133,7 +133,11 @@ defp name_param do
defp files_object do
%Schema{
type: :object,
additionalProperties: %Schema{type: :string},
additionalProperties: %Schema{
type: :string,
description: "Filename of the emoji",
extensions: %{"x-additionalPropertiesName": "Emoji name"}
},
description: "Object with emoji names as keys and filenames as values"
}
end

View file

@ -227,13 +227,29 @@ defp ok_response do
defp emoji_packs_response do
Operation.response(
"Object with pack names as keys and pack contents as values",
"Emoji packs and the count",
"application/json",
%Schema{
type: :object,
additionalProperties: emoji_pack(),
properties: %{
packs: %Schema{
type: :object,
description: "Object with pack names as keys and pack contents as values",
additionalProperties: %Schema{
emoji_pack()
| extensions: %{"x-additionalPropertiesName": "Pack name"}
}
},
count: %Schema{
type: :integer,
description: "Number of emoji packs"
}
},
example: %{
"emojos" => emoji_pack().example
"packs" => %{
"emojos" => emoji_pack().example
},
"count" => 1
}
}
)
@ -274,7 +290,11 @@ defp emoji_pack do
defp files_object do
%Schema{
type: :object,
additionalProperties: %Schema{type: :string},
additionalProperties: %Schema{
type: :string,
description: "Filename",
extensions: %{"x-additionalPropertiesName": "Emoji name"}
},
description: "Object with emoji names as keys and filenames as values"
}
end

View file

@ -13,7 +13,7 @@ def open_api_operation(action) do
def show_operation do
%Operation{
tags: ["Instance"],
tags: ["Instance misc"],
summary: "Retrieve federation status",
description: "Information about instances deemed unreachable by the server",
operationId: "PleromaInstances.show",

View file

@ -440,7 +440,7 @@ def bookmarks_operation do
def show_history_operation do
%Operation{
tags: ["Retrieve status history"],
tags: ["Retrieve status information"],
summary: "Status history",
description: "View history of a status",
operationId: "StatusController.show_history",
@ -457,7 +457,7 @@ def show_history_operation do
def show_source_operation do
%Operation{
tags: ["Retrieve status source"],
tags: ["Retrieve status information"],
summary: "Status source",
description: "View source of a status",
operationId: "StatusController.show_source",
@ -474,7 +474,7 @@ def show_source_operation do
def update_operation do
%Operation{
tags: ["Update status"],
tags: ["Status actions"],
summary: "Update status",
description: "Change the content of a status",
operationId: "StatusController.update",

View file

@ -17,7 +17,7 @@ def open_api_operation(action) do
def emoji_operation do
%Operation{
tags: ["Emojis"],
tags: ["Custom emojis"],
summary: "List all custom emojis",
operationId: "UtilController.emoji",
parameters: [],
@ -30,7 +30,8 @@ def emoji_operation do
properties: %{
image_url: %Schema{type: :string},
tags: %Schema{type: :array, items: %Schema{type: :string}}
}
},
extensions: %{"x-additionalPropertiesName": "Emoji name"}
},
example: %{
"firefox" => %{
@ -45,7 +46,7 @@ def emoji_operation do
def frontend_configurations_operation do
%Operation{
tags: ["Configuration"],
tags: ["Others"],
summary: "Dump frontend configurations",
operationId: "UtilController.frontend_configurations",
parameters: [],
@ -53,7 +54,12 @@ def frontend_configurations_operation do
200 =>
Operation.response("List", "application/json", %Schema{
type: :object,
additionalProperties: %Schema{type: :object}
additionalProperties: %Schema{
type: :object,
description:
"Opaque object representing the instance-wide configuration for the frontend",
extensions: %{"x-additionalPropertiesName": "Frontend name"}
}
})
}
}
@ -132,7 +138,7 @@ defp change_email_request do
def update_notificaton_settings_operation do
%Operation{
tags: ["Accounts"],
tags: ["Settings"],
summary: "Update Notification Settings",
security: [%{"oAuth" => ["write:accounts"]}],
operationId: "UtilController.update_notificaton_settings",
@ -207,6 +213,7 @@ def captcha_operation do
%Operation{
summary: "Get a captcha",
operationId: "UtilController.captcha",
tags: ["Others"],
parameters: [],
responses: %{
200 => Operation.response("Success", "application/json", %Schema{type: :object})
@ -356,7 +363,7 @@ defp delete_alias_request do
def healthcheck_operation do
%Operation{
tags: ["Accounts"],
tags: ["Others"],
summary: "Quick status check on the instance",
security: [%{"oAuth" => ["write:accounts"]}],
operationId: "UtilController.healthcheck",
@ -371,7 +378,7 @@ def healthcheck_operation do
def remote_subscribe_operation do
%Operation{
tags: ["Accounts"],
tags: ["Remote interaction"],
summary: "Remote Subscribe",
operationId: "UtilController.remote_subscribe",
parameters: [],
@ -381,7 +388,7 @@ def remote_subscribe_operation do
def remote_interaction_operation do
%Operation{
tags: ["Accounts"],
tags: ["Remote interaction"],
summary: "Remote interaction",
operationId: "UtilController.remote_interaction",
requestBody: request_body("Parameters", remote_interaction_request(), required: true),
@ -407,7 +414,7 @@ defp remote_interaction_request do
def show_subscribe_form_operation do
%Operation{
tags: ["Accounts"],
tags: ["Remote interaction"],
summary: "Show remote subscribe form",
operationId: "UtilController.show_subscribe_form",
parameters: [],

View file

@ -144,7 +144,11 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Status do
properties: %{
content: %Schema{
type: :object,
additionalProperties: %Schema{type: :string},
additionalProperties: %Schema{
type: :string,
description: "Alternate representation in the MIME type specified",
extensions: %{"x-additionalPropertiesName": "MIME type"}
},
description:
"A map consisting of alternate representations of the `content` property with the key being it's mimetype. Currently the only alternate representation supported is `text/plain`"
},
@ -195,7 +199,11 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Status do
},
spoiler_text: %Schema{
type: :object,
additionalProperties: %Schema{type: :string},
additionalProperties: %Schema{
type: :string,
description: "Alternate representation in the MIME type specified",
extensions: %{"x-additionalPropertiesName": "MIME type"}
},
description:
"A map consisting of alternate representations of the `spoiler_text` property with the key being it's mimetype. Currently the only alternate representation supported is `text/plain`."
},

View file

@ -6,7 +6,6 @@ defmodule Pleroma.Web.Feed.FeedView do
use Phoenix.HTML
use Pleroma.Web, :view
alias Pleroma.Formatter
alias Pleroma.Object
alias Pleroma.User
alias Pleroma.Web.Gettext
@ -72,7 +71,9 @@ def logo(user) do
def last_activity(activities), do: List.last(activities)
def activity_title(%{"content" => content, "summary" => summary} = data, opts \\ %{}) do
def activity_title(%{"content" => content} = data, opts \\ %{}) do
summary = Map.get(data, "summary", "")
title =
cond do
summary != "" -> summary
@ -81,9 +82,8 @@ def activity_title(%{"content" => content, "summary" => summary} = data, opts \\
end
title
|> Pleroma.Web.Metadata.Utils.scrub_html()
|> Pleroma.Emoji.Formatter.demojify()
|> Formatter.truncate(opts[:max_length], opts[:omission])
|> Pleroma.Web.Metadata.Utils.scrub_html_and_truncate(opts[:max_length], opts[:omission])
|> HtmlEntities.encode()
end
def activity_description(data) do

View file

@ -269,14 +269,11 @@ def update_credentials(%{assigns: %{user: user}, body_params: params} = conn, _p
end
defp normalize_fields_attributes(fields) do
if Enum.all?(fields, &is_tuple/1) do
Enum.map(fields, fn {_, v} -> v end)
else
Enum.map(fields, fn
%{} = field -> %{"name" => field.name, "value" => field.value}
field -> field
end)
end
if(Enum.all?(fields, &is_tuple/1), do: Enum.map(fields, fn {_, v} -> v end), else: fields)
|> Enum.map(fn
%{} = field -> %{"name" => field.name, "value" => field.value}
field -> field
end)
end
@doc "GET /api/v1/accounts/relationships"
@ -543,7 +540,12 @@ def blocks(%{assigns: %{user: user}} = conn, params) 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/accounts/lookup"

View file

@ -27,7 +27,7 @@ def render("show.json", _) do
thumbnail:
URI.merge(Pleroma.Web.Endpoint.url(), Keyword.get(instance, :instance_thumbnail))
|> to_string,
languages: ["en"],
languages: Keyword.get(instance, :languages, ["en"]),
registrations: Keyword.get(instance, :registrations_open),
approval_required: Keyword.get(instance, :account_approval_required),
# Extra (not present in Mastodon):
@ -92,6 +92,7 @@ def features do
"safe_dm_mentions"
end,
"pleroma_emoji_reactions",
"pleroma_custom_emoji_reactions",
"pleroma_chat_messages",
if Config.get([:instance, :show_reactions]) do
"exposable_reactions"

View file

@ -17,6 +17,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationView do
alias Pleroma.Web.MastodonAPI.AccountView
alias Pleroma.Web.MastodonAPI.NotificationView
alias Pleroma.Web.MastodonAPI.StatusView
alias Pleroma.Web.MediaProxy
alias Pleroma.Web.PleromaAPI.Chat.MessageReferenceView
defp object_id_for(%{data: %{"object" => %{"id" => id}}}) when is_binary(id), do: id
@ -145,7 +146,9 @@ defp put_report(response, activity) do
end
defp put_emoji(response, activity) do
Map.put(response, :emoji, activity.data["content"])
response
|> Map.put(:emoji, activity.data["content"])
|> Map.put(:emoji_url, MediaProxy.url(Pleroma.Emoji.emoji_url(activity.data)))
end
defp put_chat_message(response, activity, reading_user, opts) do

View file

@ -340,8 +340,8 @@ def render("show.json", %{activity: %{data: %{"object" => _object}} = activity}
opts[:for],
Map.get(opts, :with_muted, false)
)
|> Stream.map(fn {emoji, users} ->
build_emoji_map(emoji, users, opts[:for])
|> Stream.map(fn {emoji, users, url} ->
build_emoji_map(emoji, users, url, opts[:for])
end)
|> Enum.to_list()
@ -702,11 +702,13 @@ defp pin_data(%Object{data: %{"id" => object_id}}, %User{pinned_objects: pinned_
end
end
defp build_emoji_map(emoji, users, current_user) do
defp build_emoji_map(emoji, users, url, current_user) do
%{
name: emoji,
name: Pleroma.Web.PleromaAPI.EmojiReactionView.emoji_name(emoji, url),
count: length(users),
me: !!(current_user && current_user.ap_id in users)
url: MediaProxy.url(url),
me: !!(current_user && current_user.ap_id in users),
account_ids: Enum.map(users, fn user -> User.get_cached_by_ap_id(user).id end)
}
end

View file

@ -8,12 +8,20 @@ defmodule Pleroma.Web.Metadata.Providers.RelMe do
@impl Provider
def build_tags(%{user: user}) do
bio_tree = Floki.parse_fragment!(user.bio)
profile_tree =
user.bio
|> append_fields_tag(user.fields)
|> Floki.parse_fragment!()
(Floki.attribute(bio_tree, "link[rel~=me]", "href") ++
Floki.attribute(bio_tree, "a[rel~=me]", "href"))
(Floki.attribute(profile_tree, "link[rel~=me]", "href") ++
Floki.attribute(profile_tree, "a[rel~=me]", "href"))
|> Enum.map(fn link ->
{:link, [rel: "me", href: link], []}
end)
end
defp append_fields_tag(bio, fields) do
fields
|> Enum.reduce(bio, fn %{"value" => v}, res -> res <> v end)
end
end

View file

@ -30,12 +30,13 @@ def scrub_html_and_truncate(%{data: %{"content" => content}} = object) do
|> scrub_html_and_truncate_object_field(object)
end
def scrub_html_and_truncate(content, max_length \\ 200) when is_binary(content) do
def scrub_html_and_truncate(content, max_length \\ 200, omission \\ "...")
when is_binary(content) do
content
|> scrub_html
|> Emoji.Formatter.demojify()
|> HtmlEntities.decode()
|> Formatter.truncate(max_length)
|> Formatter.truncate(max_length, omission)
end
def scrub_html(content) when is_binary(content) do

View file

@ -50,29 +50,35 @@ def filter_allowed_users(reactions, user, with_muted) do
if not with_muted, do: User.cached_muted_users_ap_ids(user), else: []
end
filter_emoji = fn emoji, users ->
filter_emoji = fn emoji, users, url ->
case Enum.reject(users, &(&1 in exclude_ap_ids)) do
[] -> nil
users -> {emoji, users}
users -> {emoji, users, url}
end
end
reactions
|> Stream.map(fn
[emoji, users] when is_list(users) -> filter_emoji.(emoji, users)
{emoji, users} when is_list(users) -> filter_emoji.(emoji, users)
[emoji, users, url] when is_list(users) -> filter_emoji.(emoji, users, url)
{emoji, users, url} when is_list(users) -> filter_emoji.(emoji, users, url)
{emoji, users} when is_list(users) -> filter_emoji.(emoji, users, nil)
_ -> nil
end)
|> Stream.reject(&is_nil/1)
end
defp filter(reactions, %{emoji: emoji}) when is_binary(emoji) do
Enum.filter(reactions, fn [e, _] -> e == emoji end)
Enum.filter(reactions, fn [e, _, _] -> e == emoji end)
end
defp filter(reactions, _), do: reactions
def create(%{assigns: %{user: user}} = conn, %{id: activity_id, emoji: emoji}) do
emoji =
emoji
|> Pleroma.Emoji.fully_qualify_emoji()
|> Pleroma.Emoji.maybe_quote()
with {:ok, _activity} <- CommonAPI.react_with_emoji(activity_id, user, emoji) do
activity = Activity.get_by_id(activity_id)
@ -83,6 +89,11 @@ def create(%{assigns: %{user: user}} = conn, %{id: activity_id, emoji: emoji}) d
end
def delete(%{assigns: %{user: user}} = conn, %{id: activity_id, emoji: emoji}) do
emoji =
emoji
|> Pleroma.Emoji.fully_qualify_emoji()
|> Pleroma.Emoji.maybe_quote()
with {:ok, _activity} <- CommonAPI.unreact_with_emoji(activity_id, user, emoji) do
activity = Activity.get_by_id(activity_id)

View file

@ -7,17 +7,30 @@ defmodule Pleroma.Web.PleromaAPI.EmojiReactionView do
alias Pleroma.Web.MastodonAPI.AccountView
def emoji_name(emoji, nil), do: emoji
def emoji_name(emoji, url) do
url = URI.parse(url)
if url.host == Pleroma.Web.Endpoint.host() do
emoji
else
"#{emoji}@#{url.host}"
end
end
def render("index.json", %{emoji_reactions: emoji_reactions} = opts) do
render_many(emoji_reactions, __MODULE__, "show.json", opts)
end
def render("show.json", %{emoji_reaction: {emoji, user_ap_ids}, user: user}) do
def render("show.json", %{emoji_reaction: {emoji, user_ap_ids, url}, user: user}) do
users = fetch_users(user_ap_ids)
%{
name: emoji,
name: emoji_name(emoji, url),
count: length(users),
accounts: render(AccountView, "index.json", users: users, for: user),
url: Pleroma.Web.MediaProxy.url(url),
me: !!(user && user.ap_id in user_ap_ids)
}
end

View file

@ -38,10 +38,6 @@ def call(
def call(conn, _), do: conn
def checkpw(password, "$6" <> _ = password_hash) do
:crypt.crypt(password, password_hash) == password_hash
end
def checkpw(password, "$2" <> _ = password_hash) do
# Handle bcrypt passwords for Mastodon migration
Bcrypt.verify_pass(password, password_hash)
@ -60,10 +56,6 @@ def maybe_update_password(%User{password_hash: "$2" <> _} = user, password) do
do_update_password(user, password)
end
def maybe_update_password(%User{password_hash: "$6" <> _} = user, password) do
do_update_password(user, password)
end
def maybe_update_password(user, _), do: {:ok, user}
defp do_update_password(user, password) do

View file

@ -9,17 +9,13 @@ defmodule Pleroma.Web.RelMe do
recv_timeout: 2_000
]
if Pleroma.Config.get(:env) == :test do
def parse(url) when is_binary(url), do: parse_url(url)
else
@cachex Pleroma.Config.get([:cachex, :provider], Cachex)
def parse(url) when is_binary(url) do
@cachex.fetch!(:rel_me_cache, url, fn _ ->
{:commit, parse_url(url)}
end)
rescue
e -> {:error, "Cachex error: #{inspect(e)}"}
end
@cachex Pleroma.Config.get([:cachex, :provider], Cachex)
def parse(url) when is_binary(url) do
@cachex.fetch!(:rel_me_cache, url, fn _ ->
{:commit, parse_url(url)}
end)
rescue
e -> {:error, "Cachex error: #{inspect(e)}"}
end
def parse(_), do: {:error, "No URL provided"}

View file

@ -835,8 +835,7 @@ defmodule Pleroma.Web.Router do
end
scope "/", Pleroma.Web do
# Note: html format is supported only if static FE is enabled
pipe_through([:accepts_html_xml, :static_fe])
pipe_through([:accepts_html_xml])
get("/users/:nickname/feed", Feed.UserController, :feed, as: :user_feed)
end

View file

@ -4,8 +4,8 @@
<id><%= @data["id"] %></id>
<title><%= activity_title(@data, Keyword.get(@feed_config, :post_title, %{})) %></title>
<content type="html"><%= activity_description(@data) %></content>
<published><%= to_rfc3339(@activity.data["published"]) %></published>
<updated><%= to_rfc3339(@activity.data["published"]) %></updated>
<published><%= to_rfc3339(@data["published"]) %></published>
<updated><%= to_rfc3339(@data["published"]) %></updated>
<ostatus:conversation ref="<%= activity_context(@activity) %>">
<%= activity_context(@activity) %>
</ostatus:conversation>

View file

@ -4,7 +4,7 @@
<guid><%= @data["id"] %></guid>
<title><%= activity_title(@data, Keyword.get(@feed_config, :post_title, %{})) %></title>
<description><%= activity_description(@data) %></description>
<pubDate><%= to_rfc2822(@activity.data["published"]) %></pubDate>
<pubDate><%= to_rfc2822(@data["published"]) %></pubDate>
<ostatus:conversation ref="<%= activity_context(@activity) %>">
<%= activity_context(@activity) %>
</ostatus:conversation>

View file

@ -7,8 +7,8 @@
<id><%= @data["id"] %></id>
<title><%= activity_title(@data, Keyword.get(@feed_config, :post_title, %{})) %></title>
<content type="html"><%= activity_description(@data) %></content>
<published><%= to_rfc3339(@activity.data["published"]) %></published>
<updated><%= to_rfc3339(@activity.data["published"]) %></updated>
<published><%= to_rfc3339(@data["published"]) %></published>
<updated><%= to_rfc3339(@data["published"]) %></updated>
<ostatus:conversation ref="<%= activity_context(@activity) %>">
<%= activity_context(@activity) %>
</ostatus:conversation>

View file

@ -4,7 +4,7 @@
<guid isPermalink="true"><%= activity_context(@activity) %></guid>
<link><%= activity_context(@activity) %></link>
<pubDate><%= to_rfc2822(@activity.data["published"]) %></pubDate>
<pubDate><%= to_rfc2822(@data["published"]) %></pubDate>
<description><%= activity_description(@data) %></description>
<%= for attachment <- @data["attachment"] || [] do %>

View file

@ -13,6 +13,9 @@ def perform(%Job{args: %{"op" => "incoming_ap_doc", "params" => params}}) do
{:ok, res}
else
{:error, :origin_containment_failed} -> {:cancel, :origin_containment_failed}
{:error, :already_present} -> {:cancel, :already_present}
{:error, {:validate_object, reason}} -> {:cancel, reason}
{:error, {:error, {:validate, reason}}} -> {:cancel, reason}
{:error, {:reject, reason}} -> {:cancel, reason}
e -> e
end

View file

@ -4,7 +4,7 @@ defmodule Pleroma.Mixfile do
def project do
[
app: :pleroma,
version: version("2.5.50"),
version: version("2.5.51"),
elixir: "~> 1.11",
elixirc_paths: elixirc_paths(Mix.env()),
compilers: [:phoenix, :gettext] ++ Mix.compilers(),
@ -150,9 +150,6 @@ defp deps do
{:sweet_xml, "~> 0.7.2"},
{:earmark, "~> 1.4.22"},
{:bbcode_pleroma, "~> 0.2.0"},
{:crypt,
git: "https://github.com/msantos/crypt.git",
ref: "f75cd55325e33cbea198fb41fe41871392f8fb76"},
{:cors_plug, "~> 2.0"},
{:web_push_encryption, "~> 0.3.1"},
{:swoosh, "~> 1.0"},
@ -198,7 +195,7 @@ defp deps do
{:restarter, path: "./restarter"},
{:majic, "~> 1.0"},
{:eblurhash, "~> 1.2.2"},
{:open_api_spex, "~> 3.10"},
{:open_api_spex, "~> 3.16"},
{:ecto_psql_extras, "~> 0.6"},
# indirect dependency version override

View file

@ -21,7 +21,6 @@
"cowlib": {:hex, :cowlib, "2.11.0", "0b9ff9c346629256c42ebe1eeb769a83c6cb771a6ee5960bd110ab0b9b872063", [:make, :rebar3], [], "hexpm", "2b3e9da0b21c4565751a6d4901c20d1b4cc25cbb7fd50d91d2ab6dd287bc86a9"},
"credo": {:hex, :credo, "1.6.7", "323f5734350fd23a456f2688b9430e7d517afb313fbd38671b8a4449798a7854", [:mix], [{:bunt, "~> 0.2.1", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "41e110bfb007f7eda7f897c10bf019ceab9a0b269ce79f015d54b0dcf4fc7dd3"},
"crontab": {:hex, :crontab, "1.1.8", "2ce0e74777dfcadb28a1debbea707e58b879e6aa0ffbf9c9bb540887bce43617", [:mix], [{:ecto, "~> 1.0 or ~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm"},
"crypt": {:git, "https://github.com/msantos/crypt.git", "f75cd55325e33cbea198fb41fe41871392f8fb76", [ref: "f75cd55325e33cbea198fb41fe41871392f8fb76"]},
"custom_base": {:hex, :custom_base, "0.2.1", "4a832a42ea0552299d81652aa0b1f775d462175293e99dfbe4d7dbaab785a706", [:mix], [], "hexpm", "8df019facc5ec9603e94f7270f1ac73ddf339f56ade76a721eaa57c1493ba463"},
"db_connection": {:hex, :db_connection, "2.4.2", "f92e79aff2375299a16bcb069a14ee8615c3414863a6fef93156aee8e86c2ff3", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "4fe53ca91b99f55ea249693a0229356a08f4d1a7931d8ffa79289b145fe83668"},
"decimal": {:hex, :decimal, "2.0.0", "a78296e617b0f5dd4c6caf57c714431347912ffb1d0842e998e9792b5642d697", [:mix], [], "hexpm", "34666e9c55dea81013e77d9d87370fe6cb6291d1ef32f46a1600230b1d44f577"},
@ -83,7 +82,7 @@
"nimble_pool": {:hex, :nimble_pool, "0.2.6", "91f2f4c357da4c4a0a548286c84a3a28004f68f05609b4534526871a22053cde", [:mix], [], "hexpm", "1c715055095d3f2705c4e236c18b618420a35490da94149ff8b580a2144f653f"},
"nodex": {:git, "https://git.pleroma.social/pleroma/nodex", "cb6730f943cfc6aad674c92161be23a8411f15d1", [ref: "cb6730f943cfc6aad674c92161be23a8411f15d1"]},
"oban": {:hex, :oban, "2.13.4", "b4c4f48f4c89cc01036670eefa28aa9c03d09aadd402655475b936983d597006", [:mix], [{:ecto_sql, "~> 3.6", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16", [hex: :postgrex, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a7d26f82b409e2d7928fbb75a17716e06ad3f783ebe9af260e3dd23abed7f124"},
"open_api_spex": {:hex, :open_api_spex, "3.10.0", "94e9521ad525b3fcf6dc77da7c45f87fdac24756d4de588cb0816b413e7c1844", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:poison, "~> 3.1", [hex: :poison, repo: "hexpm", optional: true]}], "hexpm", "2dbb2bde3d2b821f06936e8dfaf3284331186556291946d84eeba3750ac28765"},
"open_api_spex": {:hex, :open_api_spex, "3.16.0", "9843af4e87550cd8ac5821b10e4c74f1d51f0d4e3310f824d780614743423b25", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:poison, "~> 3.0 or ~> 4.0 or ~> 5.0", [hex: :poison, repo: "hexpm", optional: true]}, {:ymlr, "~> 2.0 or ~> 3.0", [hex: :ymlr, repo: "hexpm", optional: true]}], "hexpm", "bb0be24a648b73e8fc8cbda17f514b8486262275e8b33e8b5ae66283df972129"},
"parse_trans": {:hex, :parse_trans, "3.3.1", "16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm", "07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"},
"pbkdf2_elixir": {:hex, :pbkdf2_elixir, "1.2.1", "9cbe354b58121075bd20eb83076900a3832324b7dd171a6895fab57b6bb2752c", [:mix], [{:comeonin, "~> 5.3", [hex: :comeonin, repo: "hexpm", optional: false]}], "hexpm", "d3b40a4a4630f0b442f19eca891fcfeeee4c40871936fed2f68e1c4faa30481f"},
"phoenix": {:hex, :phoenix, "1.6.15", "0a1d96bbc10747fd83525370d691953cdb6f3ccbac61aa01b4acb012474b047d", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 1.0 or ~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d70ab9fbf6b394755ea88b644d34d79d8b146e490973151f248cacd122d20672"},

View file

@ -6033,3 +6033,15 @@ msgstr ""
msgctxt "config label at :pleroma-:instance > :moderator_privileges"
msgid "Moderator privileges"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/pleroma/docs/translator.ex:5
msgctxt "config description at :pleroma-:instance > :languages"
msgid "Languages to be exposed in /api/v1/instance. Should be in the format of BCP47 language codes."
msgstr ""
#, elixir-autogen, elixir-format
#: lib/pleroma/docs/translator.ex:5
msgctxt "config label at :pleroma-:instance > :languages"
msgid "Languages"
msgstr ""

View file

@ -111,7 +111,7 @@ msgid "Can't display this activity"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:337
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:334
msgid "Can't find user"
msgstr ""
@ -236,7 +236,7 @@ msgid "Poll's author can't vote"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:502
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:499
#: lib/pleroma/web/mastodon_api/controllers/fallback_controller.ex:20
#: lib/pleroma/web/mastodon_api/controllers/poll_controller.ex:39
#: lib/pleroma/web/mastodon_api/controllers/poll_controller.ex:51
@ -558,7 +558,7 @@ msgid "Access denied"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:334
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:331
msgid "This API requires an authenticated user"
msgstr ""

View file

@ -1 +1 @@
<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1,user-scalable=no"><!--server-generated-meta--><link rel=icon type=image/png href=/favicon.png><script defer=defer src=/static/js/9169.335214f6ab57538eae0b.js></script><script defer=defer src=/static/js/app.4c23e08cf351a54f4177.js></script><link href=/static/css/app.86977512e08af1f17d78.css rel=stylesheet></head><body class=hidden><noscript>To use Pleroma, please enable JavaScript.</noscript><div id=app></div><div id=popovers></body></html>
<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1,user-scalable=no"><!--server-generated-meta--><link rel=icon type=image/png href=/favicon.png><script defer=defer src=/static/js/2724.e4840c73281069ba54ab.js></script><script defer=defer src=/static/js/app.8d2126d35dba9482db51.js></script><link href=/static/css/app.48e52505beba5b9ab69b.css rel=stylesheet></head><body class=hidden><noscript>To use Pleroma, please enable JavaScript.</noscript><div id=app></div><div id=modal></div><div id=popovers></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,2 +0,0 @@
.async-component-error{align-items:center;display:flex;height:100%;justify-content:center}.async-component-error .btn{margin:.5em;padding:.5em 2em}.settings-modal{overflow:hidden}.settings-modal .option-list,.settings-modal .setting-list{list-style-type:none;padding-left:2em}.settings-modal .option-list li,.settings-modal .setting-list li{margin-bottom:.5em}.settings-modal .option-list .suboptions,.settings-modal .setting-list .suboptions{margin-top:.3em}.settings-modal.peek .settings-modal-panel{transform:translateY(calc(50vh + 50% - 50px))}@media (max-width:800px){.settings-modal.peek .settings-modal-panel{transform:translateY(calc(100% - 50px))}}.settings-modal .settings-modal-panel{height:90vh;max-width:90vw;overflow:hidden;transition:transform;transition-duration:.3s;transition-timing-function:ease-in-out;width:1000px}@media (max-width:800px){.settings-modal .settings-modal-panel{height:100%;max-width:100vw}}.settings-modal .settings-modal-panel>.panel-body{height:100%;overflow-y:hidden}.settings-modal .settings-modal-panel>.panel-body .btn{min-height:2em;min-width:10em;padding:0 2em}.settings-modal .settings-footer{display:flex}.settings-modal .settings-footer>*{margin-right:.5em}.settings-modal .settings-footer .extra-content{display:flex;flex-grow:1}
/*# sourceMappingURL=1325.715a7f40cdd53f460ef4.css.map*/

View file

@ -1 +0,0 @@
{"version":3,"file":"static/css/1325.715a7f40cdd53f460ef4.css","mappings":"AACA,uBAGE,mBAFA,aACA,YAEA,uBACA,4BACE,YACA,iBCPJ,gBACE,gBAEA,2DAEE,qBACA,iBACA,iEACE,mBAEF,mFACE,gBAKF,2CASE,8CAEA,yBAXF,2CAeI,yCAKN,sCAOE,YADA,eALA,gBACA,qBAEA,wBADA,uCAEA,YAEA,CAEA,yBATF,sCAWI,YADA,eACA,EAGF,kDACE,YACA,kBAEA,uDACE,eACA,eACA,cAKN,iCACE,aACA,mCACE,kBAGF,gDACE,aACA","sources":["webpack://pleroma_fe/./src/components/async_component_error/async_component_error.vue","webpack://pleroma_fe/./src/components/settings_modal/settings_modal.scss"],"sourcesContent":["\n.async-component-error {\n display: flex;\n height: 100%;\n align-items: center;\n justify-content: center;\n .btn {\n margin: .5em;\n padding: .5em 2em;\n }\n}\n","@import 'src/_variables.scss';\n.settings-modal {\n overflow: hidden;\n\n .setting-list,\n .option-list {\n list-style-type: none;\n padding-left: 2em;\n li {\n margin-bottom: 0.5em;\n }\n .suboptions {\n margin-top: 0.3em\n }\n }\n\n &.peek {\n .settings-modal-panel {\n /* Explanation:\n * Modal is positioned vertically centered.\n * 100vh - 100% = Distance between modal's top+bottom boundaries and screen\n * (100vh - 100%) / 2 = Distance between bottom (or top) boundary and screen\n * + 100% - we move modal completely off-screen, it's top boundary touches\n * bottom of the screen\n * - 50px - leaving tiny amount of space so that titlebar + tiny amount of modal is visible\n */\n transform: translateY(calc(((100vh - 100%) / 2 + 100%) - 50px));\n\n @media all and (max-width: 800px) {\n /* For mobile, the modal takes 100% of the available screen.\n This ensures the minimized modal is always 50px above the browser bottom bar regardless of whether or not it is visible.\n */\n transform: translateY(calc(100% - 50px));\n }\n }\n }\n\n .settings-modal-panel {\n overflow: hidden;\n transition: transform;\n transition-timing-function: ease-in-out;\n transition-duration: 300ms;\n width: 1000px;\n max-width: 90vw;\n height: 90vh;\n\n @media all and (max-width: 800px) {\n max-width: 100vw;\n height: 100%;\n }\n\n >.panel-body {\n height: 100%;\n overflow-y: hidden;\n\n .btn {\n min-height: 2em;\n min-width: 10em;\n padding: 0 2em;\n }\n }\n }\n\n .settings-footer {\n display: flex;\n >* {\n margin-right: 0.5em;\n }\n\n .extra-content {\n display: flex;\n flex-grow: 1;\n }\n }\n}\n"],"names":[],"sourceRoot":""}

View file

@ -1,2 +1,2 @@
.sticker-picker{width:100%}.sticker-picker .contents{min-height:250px}.sticker-picker .contents .sticker-picker-content{display:flex;flex-wrap:wrap;padding:0 4px}.sticker-picker .contents .sticker-picker-content .sticker{display:flex;flex:1 1 auto;height:56px;margin:4px;width:56px}.sticker-picker .contents .sticker-picker-content .sticker img{height:100%}.sticker-picker .contents .sticker-picker-content .sticker img:hover{filter:drop-shadow(0 0 5px var(--accent,#d8a070))}
/*# sourceMappingURL=8532.88b90ac86f3060a3144e.css.map*/
/*# sourceMappingURL=159.1d523a00378ebd68c5b3.css.map*/

View file

@ -0,0 +1 @@
{"version":3,"file":"static/css/159.1d523a00378ebd68c5b3.css","mappings":"AAGA,gBACE,WAEA,0BACE,iBAEA,kDACE,aACA,eACA,cAEA,2DACE,aACA,cAGA,YAFA,WACA,UACA,CAEA,+DACE,YAEA,qEACE","sources":["webpack://pleroma_fe/./src/components/sticker_picker/sticker_picker.vue"],"sourcesContent":["\n@import \"../../variables\";\n\n.sticker-picker {\n width: 100%;\n\n .contents {\n min-height: 250px;\n\n .sticker-picker-content {\n display: flex;\n flex-wrap: wrap;\n padding: 0 4px;\n\n .sticker {\n display: flex;\n flex: 1 1 auto;\n margin: 4px;\n width: 56px;\n height: 56px;\n\n img {\n height: 100%;\n\n &:hover {\n filter: drop-shadow(0 0 5px var(--accent, $fallback--link));\n }\n }\n }\n }\n }\n}\n\n"],"names":[],"sourceRoot":""}

View file

@ -0,0 +1,2 @@
.async-component-error{align-items:center;display:flex;height:100%;justify-content:center}.async-component-error .btn{margin:.5em;padding:.5em 2em}.settings-modal{overflow:hidden}.settings-modal .option-list,.settings-modal .setting-list{list-style-type:none;padding-left:2em}.settings-modal .option-list li,.settings-modal .setting-list li{margin-bottom:.5em}.settings-modal .option-list .suboptions,.settings-modal .setting-list .suboptions{margin-top:.3em}.settings-modal .settings-modal-panel{height:90vh;max-width:90vw;overflow:hidden;transition:transform;transition-duration:.3s;transition-timing-function:ease-in-out;width:1000px}@media (max-width:800px){.settings-modal .settings-modal-panel{height:100%;max-width:100vw}}.settings-modal .settings-modal-panel>.panel-body{height:100%;overflow-y:hidden}.settings-modal .settings-modal-panel>.panel-body .btn{min-height:2em;min-width:10em;padding:0 2em}.settings-modal .settings-footer{display:flex}.settings-modal .settings-footer>*{margin-right:.5em}.settings-modal .settings-footer .extra-content{display:flex;flex-grow:1}.settings-modal.peek .settings-modal-panel{transform:translateY(calc(50vh + 50% - 50px))}@media (max-width:800px){.settings-modal.peek .settings-modal-panel{transform:translateY(calc(100% - 50px))}}
/*# sourceMappingURL=5948.06d2a0d84620cba6a4fb.css.map*/

View file

@ -0,0 +1 @@
{"version":3,"file":"static/css/5948.06d2a0d84620cba6a4fb.css","mappings":"AACA,uBAGE,mBAFA,aACA,YAEA,uBAEA,4BACE,YACA,iBCPJ,gBACE,gBAEA,2DAEE,qBACA,iBAEA,iEACE,mBAGF,mFACE,gBAIJ,sCAOE,YADA,eALA,gBACA,qBAEA,wBADA,uCAEA,YAEA,CAEA,yBATF,sCAWI,YADA,eACA,EAGF,kDACE,YACA,kBAEA,uDACE,eACA,eACA,cAKN,iCACE,aAEA,mCACE,kBAGF,gDACE,aACA,YAKF,2CASE,8CAEA,yBAXF,2CAgBI","sources":["webpack://pleroma_fe/./src/components/async_component_error/async_component_error.vue","webpack://pleroma_fe/./src/components/settings_modal/settings_modal.scss"],"sourcesContent":["\n.async-component-error {\n display: flex;\n height: 100%;\n align-items: center;\n justify-content: center;\n\n .btn {\n margin: 0.5em;\n padding: 0.5em 2em;\n }\n}\n","@import \"src/variables\";\n\n.settings-modal {\n overflow: hidden;\n\n .setting-list,\n .option-list {\n list-style-type: none;\n padding-left: 2em;\n\n li {\n margin-bottom: 0.5em;\n }\n\n .suboptions {\n margin-top: 0.3em;\n }\n }\n\n .settings-modal-panel {\n overflow: hidden;\n transition: transform;\n transition-timing-function: ease-in-out;\n transition-duration: 300ms;\n width: 1000px;\n max-width: 90vw;\n height: 90vh;\n\n @media all and (max-width: 800px) {\n max-width: 100vw;\n height: 100%;\n }\n\n >.panel-body {\n height: 100%;\n overflow-y: hidden;\n\n .btn {\n min-height: 2em;\n min-width: 10em;\n padding: 0 2em;\n }\n }\n }\n\n .settings-footer {\n display: flex;\n\n >* {\n margin-right: 0.5em;\n }\n\n .extra-content {\n display: flex;\n flex-grow: 1;\n }\n }\n\n &.peek {\n .settings-modal-panel {\n /* Explanation:\n * Modal is positioned vertically centered.\n * 100vh - 100% = Distance between modal's top+bottom boundaries and screen\n * (100vh - 100%) / 2 = Distance between bottom (or top) boundary and screen\n * + 100% - we move modal completely off-screen, it's top boundary touches\n * bottom of the screen\n * - 50px - leaving tiny amount of space so that titlebar + tiny amount of modal is visible\n */\n transform: translateY(calc(((100vh - 100%) / 2 + 100%) - 50px));\n\n @media all and (max-width: 800px) {\n /* For mobile, the modal takes 100% of the available screen.\n This ensures the minimized modal is always 50px above the browser bottom\n bar regardless of whether or not it is visible.\n */\n transform: translateY(calc(100% - 50px));\n }\n }\n }\n}\n"],"names":[],"sourceRoot":""}

View file

@ -1,2 +1,2 @@
.UpdateNotification{overflow:hidden}.UpdateNotificationModal{--__top-fringe:15em;--__bottom-fringe:80em;--__right-fringe:8em;font-size:15px;position:relative;transition:transform;transition-duration:.5s;transition-timing-function:ease-in-out}.UpdateNotificationModal .text{max-width:40em;padding-left:1em}@media (max-width:800px){.UpdateNotificationModal{width:100vw}}@media (max-height:600px){.UpdateNotificationModal{display:none}}.UpdateNotificationModal .content{margin-bottom:calc(var(--__bottom-fringe)*-1);margin-right:calc(var(--__right-fringe)*-1);margin-top:calc(var(--__top-fringe)*-1);overflow:hidden}.UpdateNotificationModal .content.-noImage .text{padding-right:var(--__right-fringe)}.UpdateNotificationModal .panel-body{border-color:var(--border,#222);border-style:solid;border-width:0 0 1px}.UpdateNotificationModal .panel-footer{border-width:0;grid-template-columns:auto;position:relative;z-index:22}.UpdateNotificationModal .pleroma-tan{filter:drop-shadow(5px 5px 10px rgba(0,0,0,.5));float:right;-o-object-fit:cover;object-fit:cover;-o-object-position:top;object-position:top;pointer-events:none;position:relative;shape-margin:.5em;transition:position,left,right,top,bottom,max-width,max-height;transition-duration:.5s;transition-timing-function:ease-in-out;width:25em;z-index:20}.UpdateNotificationModal .spacer-top{min-height:var(--__top-fringe)}.UpdateNotificationModal .spacer-bottom{min-height:var(--__bottom-fringe)}.UpdateNotificationModal .extra-info-group{-webkit-mask:linear-gradient(0deg,#fff,transparent) bottom/100% 2px no-repeat,linear-gradient(0deg,#fff,#fff);mask:linear-gradient(0deg,#fff,transparent) bottom/100% 2px no-repeat,linear-gradient(0deg,#fff,#fff);max-height:70vh;transition:max-height,padding,height;transition-duration:.7s;transition-timing-function:ease-in}.UpdateNotificationModal .art-credit{text-align:right}.UpdateNotificationModal.-peek{transform:translateY(calc(50vh - 50%))}.UpdateNotificationModal.-peek .pleroma-tan{float:right;shape-image-threshold:.7;z-index:10}.UpdateNotificationModal.-peek .extra-info-group{max-height:0}
/*# sourceMappingURL=6464.2fa2e5f1fa93842c62b1.css.map*/
.UpdateNotification{overflow:hidden}.UpdateNotificationModal{--__top-fringe:15em;--__bottom-fringe:80em;--__right-fringe:8em;font-size:15px;position:relative;transition:transform;transition-duration:.5s;transition-timing-function:ease-in-out}.UpdateNotificationModal .text{max-width:40em;padding-left:1em}@media (max-width:800px){.UpdateNotificationModal{width:100vw}}@media (max-height:600px){.UpdateNotificationModal{display:none}}.UpdateNotificationModal .content{margin-bottom:calc(var(--__bottom-fringe)*-1);margin-right:calc(var(--__right-fringe)*-1);margin-top:calc(var(--__top-fringe)*-1);overflow:hidden}.UpdateNotificationModal .content.-noImage .text{padding-right:var(--__right-fringe)}.UpdateNotificationModal .panel-body{border-color:var(--border,#222);border-style:solid;border-width:0 0 1px}.UpdateNotificationModal .panel-footer{border-width:0;grid-template-columns:auto;position:relative;z-index:22}.UpdateNotificationModal .pleroma-tan{filter:drop-shadow(5px 5px 10px rgba(0,0,0,.5));float:right;-o-object-fit:cover;object-fit:cover;-o-object-position:top;object-position:top;pointer-events:none;position:relative;shape-margin:.5em;transition:position,left,right,top,bottom,max-width,max-height;transition-duration:.5s;transition-timing-function:ease-in-out;width:25em;z-index:20}.UpdateNotificationModal .spacer-top{min-height:var(--__top-fringe)}.UpdateNotificationModal .spacer-bottom{min-height:var(--__bottom-fringe)}.UpdateNotificationModal .extra-info-group{-webkit-mask:linear-gradient(0deg,#fff,transparent) bottom/100% 2px no-repeat,linear-gradient(0deg,#fff,#fff);mask:linear-gradient(0deg,#fff,transparent) bottom/100% 2px no-repeat,linear-gradient(0deg,#fff,#fff);max-height:70vh;transition:max-height,padding,height;transition-duration:.7s;transition-timing-function:ease-in}.UpdateNotificationModal .art-credit{text-align:right}.UpdateNotificationModal.-peek{transform:translateY(calc(50vh - 50%))}.UpdateNotificationModal.-peek .pleroma-tan{float:right;shape-image-threshold:70%;z-index:10}.UpdateNotificationModal.-peek .extra-info-group{max-height:0}
/*# sourceMappingURL=6464.169260b661120cc50815.css.map*/

View file

@ -0,0 +1 @@
{"version":3,"file":"static/css/6464.169260b661120cc50815.css","mappings":"AAEA,oBACE,gBAGF,yBACE,mBAAoB,CACpB,sBAAuB,CACvB,oBAAqB,CAErB,eACA,kBACA,qBAEA,wBADA,sCACA,CAEA,+BACE,eACA,iBAGF,yBAhBF,yBAqBI,aAGF,0BAxBF,yBAyBI,cAGF,kCAGE,8CACA,4CAFA,wCADA,eAGA,CAGE,iDACE,oCAKN,qCAGE,gCADA,mBADA,oBAEA,CAGF,uCAGE,eACA,2BAFA,kBADA,UAGA,CAGF,sCAWE,gDAJA,YANA,qCACA,2CAUA,oBAHA,kBACA,kBAPA,+DAEA,wBADA,uCAEA,WAEA,UAIA,CAGF,qCACE,+BAGF,wCACE,kCAGF,2CAKE,6GACE,CADF,sGADA,gBAHA,qCAEA,wBADA,kCAIE,CAIJ,qCACE,iBAGF,+BAKE,uCAEA,4CACE,YAEA,0BADA,UACA,CAGF,iDACE","sources":["webpack://pleroma_fe/./src/components/update_notification/update_notification.scss"],"sourcesContent":["@import \"src/variables\";\n\n.UpdateNotification {\n overflow: hidden;\n}\n\n.UpdateNotificationModal {\n --__top-fringe: 15em; // how much pleroma-tan should stick her head above\n --__bottom-fringe: 80em; // just reserving as much as we can, number is mostly irrelevant\n --__right-fringe: 8em;\n\n font-size: 15px;\n position: relative;\n transition: transform;\n transition-timing-function: ease-in-out;\n transition-duration: 500ms;\n\n .text {\n max-width: 40em;\n padding-left: 1em;\n }\n\n @media all and (max-width: 800px) {\n /* For mobile, the modal takes 100% of the available screen.\n This ensures the minimized modal is always 50px above the browser\n bottom bar regardless of whether or not it is visible.\n */\n width: 100vw;\n }\n\n @media all and (max-height: 600px) {\n display: none;\n }\n\n .content {\n overflow: hidden;\n margin-top: calc(-1 * var(--__top-fringe));\n margin-bottom: calc(-1 * var(--__bottom-fringe));\n margin-right: calc(-1 * var(--__right-fringe));\n\n &.-noImage {\n .text {\n padding-right: var(--__right-fringe);\n }\n }\n }\n\n .panel-body {\n border-width: 0 0 1px;\n border-style: solid;\n border-color: var(--border, $fallback--border);\n }\n\n .panel-footer {\n z-index: 22;\n position: relative;\n border-width: 0;\n grid-template-columns: auto;\n }\n\n .pleroma-tan {\n object-fit: cover;\n object-position: top;\n transition: position, left, right, top, bottom, max-width, max-height;\n transition-timing-function: ease-in-out;\n transition-duration: 500ms;\n width: 25em;\n float: right;\n z-index: 20;\n position: relative;\n shape-margin: 0.5em;\n filter: drop-shadow(5px 5px 10px rgb(0 0 0 / 50%));\n pointer-events: none;\n }\n\n .spacer-top {\n min-height: var(--__top-fringe);\n }\n\n .spacer-bottom {\n min-height: var(--__bottom-fringe);\n }\n\n .extra-info-group {\n transition: max-height, padding, height;\n transition-timing-function: ease-in;\n transition-duration: 700ms;\n max-height: 70vh;\n mask:\n linear-gradient(to top, white, transparent) bottom/100% 2px no-repeat,\n linear-gradient(to top, white, white);\n }\n\n .art-credit {\n text-align: right;\n }\n\n &.-peek {\n /* Explanation:\n * 100vh - 100% = Distance between modal's top+bottom boundaries and screen\n * (100vh - 100%) / 2 = Distance between bottom (or top) boundary and screen\n */\n transform: translateY(calc(((100vh - 100%) / 2)));\n\n .pleroma-tan {\n float: right;\n z-index: 10;\n shape-image-threshold: 70%;\n }\n\n .extra-info-group {\n max-height: 0;\n }\n }\n}\n"],"names":[],"sourceRoot":""}

View file

@ -1 +0,0 @@
{"version":3,"file":"static/css/6464.2fa2e5f1fa93842c62b1.css","mappings":"AACA,oBACE,gBAGF,yBACE,mBAAoB,CACpB,sBAAuB,CACvB,oBAAqB,CAErB,eACA,kBACA,qBAEA,wBADA,sCACA,CAEA,+BACE,eACA,iBAGF,yBAhBF,yBAoBI,aAGF,0BAvBF,yBAwBI,cAGF,kCAGE,8CACA,4CAFA,wCADA,eAGA,CAGE,iDACE,oCAKN,qCAGE,gCADA,mBADA,oBAEA,CAGF,uCAGE,eACA,2BAFA,kBADA,UAGA,CAGF,sCAWE,gDAJA,YANA,qCACA,2CAUA,oBAHA,kBACA,kBAPA,+DAEA,wBADA,uCAEA,WAEA,UAIA,CAGF,qCACE,+BAGF,wCACE,kCAGF,2CAKE,6GACE,CADF,sGADA,gBAHA,qCAEA,wBADA,kCAIE,CAIJ,qCACE,iBAGF,+BAKE,uCAEA,4CACE,YAEA,yBADA,UACA,CAGF,iDACE","sources":["webpack://pleroma_fe/./src/components/update_notification/update_notification.scss"],"sourcesContent":["@import 'src/_variables.scss';\n.UpdateNotification {\n overflow: hidden;\n}\n\n.UpdateNotificationModal {\n --__top-fringe: 15em; // how much pleroma-tan should stick her head above\n --__bottom-fringe: 80em; // just reserving as much as we can, number is mostly irrelevant\n --__right-fringe: 8em;\n\n font-size: 15px;\n position: relative;\n transition: transform;\n transition-timing-function: ease-in-out;\n transition-duration: 500ms;\n\n .text {\n max-width: 40em;\n padding-left: 1em;\n }\n\n @media all and (max-width: 800px) {\n /* For mobile, the modal takes 100% of the available screen.\n This ensures the minimized modal is always 50px above the browser bottom bar regardless of whether or not it is visible.\n */\n width: 100vw;\n }\n\n @media all and (max-height: 600px) {\n display: none;\n }\n\n .content {\n overflow: hidden;\n margin-top: calc(-1 * var(--__top-fringe));\n margin-bottom: calc(-1 * var(--__bottom-fringe));\n margin-right: calc(-1 * var(--__right-fringe));\n\n &.-noImage {\n .text {\n padding-right: var(--__right-fringe);\n }\n }\n }\n\n .panel-body {\n border-width: 0 0 1px 0;\n border-style: solid;\n border-color: var(--border, $fallback--border);\n }\n\n .panel-footer {\n z-index: 22;\n position: relative;\n border-width: 0;\n grid-template-columns: auto;\n }\n\n .pleroma-tan {\n object-fit: cover;\n object-position: top;\n transition: position, left, right, top, bottom, max-width, max-height;\n transition-timing-function: ease-in-out;\n transition-duration: 500ms;\n width: 25em;\n float: right;\n z-index: 20;\n position: relative;\n shape-margin: 0.5em;\n filter: drop-shadow(5px 5px 10px rgba(0,0,0,0.5));\n pointer-events: none;\n }\n\n .spacer-top {\n min-height: var(--__top-fringe);\n }\n\n .spacer-bottom {\n min-height: var(--__bottom-fringe);\n }\n\n .extra-info-group {\n transition: max-height, padding, height;\n transition-timing-function: ease-in;\n transition-duration: 700ms;\n max-height: 70vh;\n mask:\n linear-gradient(to top, white, transparent) bottom/100% 2px no-repeat,\n linear-gradient(to top, white, white);\n }\n\n .art-credit {\n text-align: right;\n }\n\n &.-peek {\n /* Explanation:\n * 100vh - 100% = Distance between modal's top+bottom boundaries and screen\n * (100vh - 100%) / 2 = Distance between bottom (or top) boundary and screen\n */\n transform: translateY(calc(((100vh - 100%) / 2)));\n\n .pleroma-tan {\n float: right;\n z-index: 10;\n shape-image-threshold: 0.7;\n }\n\n .extra-info-group {\n max-height: 0;\n }\n }\n}\n"],"names":[],"sourceRoot":""}

View file

@ -1 +0,0 @@
{"version":3,"file":"static/css/8532.88b90ac86f3060a3144e.css","mappings":"AAGA,gBACE,WACA,0BACE,iBACA,kDACE,aACA,eACA,cACA,2DACE,aACA,cAGA,YAFA,WACA,UACA,CACA,+DACE,YACA,qEACE","sources":["webpack://pleroma_fe/./src/components/sticker_picker/sticker_picker.vue"],"sourcesContent":["\n@import '../../_variables.scss';\n\n.sticker-picker {\n width: 100%;\n .contents {\n min-height: 250px;\n .sticker-picker-content {\n display: flex;\n flex-wrap: wrap;\n padding: 0 4px;\n .sticker {\n display: flex;\n flex: 1 1 auto;\n margin: 4px;\n width: 56px;\n height: 56px;\n img {\n height: 100%;\n &:hover {\n filter: drop-shadow(0 0 5px var(--accent, $fallback--link));\n }\n }\n }\n }\n }\n}\n\n"],"names":[],"sourceRoot":""}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,2 @@
"use strict";(self.webpackChunkpleroma_fe=self.webpackChunkpleroma_fe||[]).push([[159],{30159:(t,e,n)=>{n.r(e),n.d(e,{default:()=>p});var i=n(66252),a=n(49963),c={class:"sticker-picker"},r=["image-tooltip","image"],o=["onClick"],s=["src"],l=n(7257);const u={components:{TabSwitcher:n(79354).Z},data:function(){return{meta:{stickers:[]},path:""}},computed:{pack:function(){return this.$store.state.instance.stickers||[]}},methods:{clear:function(){this.meta={stickers:[]}},pick:function(t,e){var n=this,i=this.$store;fetch(t).then((function(t){t.blob().then((function(t){var a=new File([t],e,{mimetype:"image/png"}),c=new FormData;c.append("file",a),l.Z.uploadMedia({store:i,formData:c}).then((function(t){n.$emit("uploaded",t),n.clear()}),(function(t){console.warn("Can't attach sticker"),console.warn(t),n.$emit("upload-failed","default")}))}))}))}}},p=(0,n(83744).Z)(u,[["render",function(t,e,n,l,u,p){var f=(0,i.up)("tab-switcher");return(0,i.wg)(),(0,i.iD)("div",c,[(0,i.Wm)(f,{class:"tab-switcher","render-only-focused":!0,"scrollable-tabs":""},{default:(0,i.w5)((function(){return[((0,i.wg)(!0),(0,i.iD)(i.HY,null,(0,i.Ko)(t.pack,(function(e){return(0,i.wg)(),(0,i.iD)("div",{key:e.path,"image-tooltip":e.meta.title,image:e.path+e.meta.tabIcon,class:"sticker-picker-content"},[((0,i.wg)(!0),(0,i.iD)(i.HY,null,(0,i.Ko)(e.meta.stickers,(function(n){return(0,i.wg)(),(0,i.iD)("div",{key:n,class:"sticker",onClick:(0,a.iM)((function(i){return t.pick(e.path+n,e.meta.title)}),["stop","prevent"])},[(0,i._)("img",{src:e.path+n},null,8,s)],8,o)})),128))],8,r)})),128))]})),_:1})])}]])}}]);
//# sourceMappingURL=159.3a9274574f1e33801c4a.js.map

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -33,12 +33,6 @@
/*! (c) Andrea Giammarchi - ISC */
/*! https://mths.be/punycode v1.3.2 by @mathias */
/*! js-cookie v3.0.1 | MIT */
/*! lozad.js - v1.16.0 - 2020-09-06
* https://github.com/ApoorvSaxena/lozad.js
* Copyright (c) 2020 Apoorv Saxena; Licensed MIT */
/*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,2 +1,2 @@
"use strict";(self.webpackChunkpleroma_fe=self.webpackChunkpleroma_fe||[]).push([[6464],{16464:(t,e,a)=>{a.r(e),a.d(e,{CURRENT_UPDATE_COUNTER:()=>T,default:()=>N});var n=a(66252),o=a(3577),s=a(49963),i={class:"panel-heading"},r={class:"title"},l={class:"panel-body"},u=["src"],p=(0,n._)("div",{class:"spacer-top"},null,-1),c={class:"text"},d={ref:"animatedText",class:"extra-info-group"},g={target:"_blank",href:"https://git.pleroma.social/"},h={target:"_blank",href:"https://pleroma.social/announcements/"},m={class:"art-credit"},_=(0,n._)("a",{target:"_blank",href:"https://post.ebin.club/users/pipivovott"},"pipivovott",-1),f=(0,n._)("div",{class:"spacer-bottom"},null,-1),w={class:"panel-footer"},v=a(58312),S=a(9382),b=a(31934),k=a(95326),$=a(43011),C=a(68789),y=a(84131);S.vI.add(y.NBC);var T=1;const M={data:function(){return{showingImage:!1,pleromaTanVariant:Math.random()>.5?b:k,showingMore:!1}},components:{Modal:v.Z},computed:{pleromaTanStyles:function(){return{"shape-outside":"url("+(this.pleromaTanVariant===b?$:C)+")"}},shouldShow:function(){return!this.$store.state.instance.disableUpdateNotification&&this.$store.state.users.currentUser&&this.$store.state.serverSideStorage.flagStorage.updateCounter<T&&!this.$store.state.serverSideStorage.prefsStorage.simple.dontShowUpdateNotifs}},methods:{toggleShow:function(){this.showingMore=!this.showingMore},neverShowAgain:function(){this.toggleShow(),this.$store.commit("setFlag",{flag:"updateCounter",value:T}),this.$store.commit("setPreference",{path:"simple.dontShowUpdateNotifs",value:!0}),this.$store.dispatch("pushServerSideStorage")},dismiss:function(){this.$store.commit("setFlag",{flag:"updateCounter",value:T}),this.$store.dispatch("pushServerSideStorage")}},mounted:function(){var t=this;this.contentHeightNoImage=this.$refs.animatedText.scrollHeight;var e=new Image;e.onload=function(){setTimeout((function(){t.showingImage=!0}),100)},e.src=this.pleromaTanVariant===b?$:C}},N=(0,a(83744).Z)(M,[["render",function(t,e,a,v,S,b){var k=(0,n.up)("i18n-t"),$=(0,n.up)("Modal");return(0,n.wg)(),(0,n.j4)($,{"is-open":!!t.shouldShow,class:"UpdateNotification","no-background":!0},{default:(0,n.w5)((function(){return[(0,n._)("div",{class:(0,o.C_)(["UpdateNotificationModal panel",{"-peek":!t.showingMore}])},[(0,n._)("div",i,[(0,n._)("span",r,(0,o.zw)(t.$t("update.big_update_title")),1)]),(0,n._)("div",l,[(0,n._)("div",{class:(0,o.C_)(["content",{"-noImage":!t.showingImage}])},[t.showingImage?((0,n.wg)(),(0,n.iD)("img",{key:0,class:"pleroma-tan",src:t.pleromaTanVariant,style:(0,o.j5)(t.pleromaTanStyles)},null,12,u)):(0,n.kq)("",!0),p,(0,n._)("div",c,[(0,n._)("p",null,(0,o.zw)(t.$t("update.big_update_content")),1),(0,n._)("div",d,[(0,n.Wm)(k,{keypath:"update.update_bugs",tag:"p"},{pleromaGitlab:(0,n.w5)((function(){return[(0,n._)("a",g,(0,o.zw)(t.$t("update.update_bugs_gitlab")),1)]})),_:1}),(0,n.Wm)(k,{keypath:"update.update_changelog",tag:"p"},{theFullChangelog:(0,n.w5)((function(){return[(0,n._)("a",h,(0,o.zw)(t.$t("update.update_changelog_here")),1)]})),_:1}),(0,n._)("p",m,[(0,n.Wm)(k,{keypath:"update.art_by",tag:"small"},{linkToArtist:(0,n.w5)((function(){return[_]})),_:1})])],512)]),f],2)]),(0,n._)("div",w,[(0,n._)("button",{class:"button-default",onClick:e[0]||(e[0]=(0,s.iM)((function(){return t.neverShowAgain&&t.neverShowAgain.apply(t,arguments)}),["prevent"]))},(0,o.zw)(t.$t("general.never_show_again")),1),t.showingMore?(0,n.kq)("",!0):((0,n.wg)(),(0,n.iD)("button",{key:0,class:"button-default",onClick:e[1]||(e[1]=(0,s.iM)((function(){return t.toggleShow&&t.toggleShow.apply(t,arguments)}),["prevent"]))},(0,o.zw)(t.$t("general.show_more")),1)),(0,n._)("button",{class:"button-default",onClick:e[2]||(e[2]=(0,s.iM)((function(){return t.dismiss&&t.dismiss.apply(t,arguments)}),["prevent"]))},(0,o.zw)(t.$t("general.dismiss")),1)])],2)]})),_:1},8,["is-open"])}]])}}]);
//# sourceMappingURL=6464.2ababce187697ee8b1e9.js.map
"use strict";(self.webpackChunkpleroma_fe=self.webpackChunkpleroma_fe||[]).push([[6464],{16464:(t,e,a)=>{a.r(e),a.d(e,{CURRENT_UPDATE_COUNTER:()=>T,default:()=>N});var n=a(66252),o=a(3577),s=a(49963),i={class:"panel-heading"},r={class:"title"},l={class:"panel-body"},u=["src"],p=(0,n._)("div",{class:"spacer-top"},null,-1),c={class:"text"},d={ref:"animatedText",class:"extra-info-group"},g={target:"_blank",href:"https://git.pleroma.social/"},h={target:"_blank",href:"https://pleroma.social/announcements/"},m={class:"art-credit"},_=(0,n._)("a",{target:"_blank",href:"https://post.ebin.club/users/pipivovott"},"pipivovott",-1),f=(0,n._)("div",{class:"spacer-bottom"},null,-1),w={class:"panel-footer"},v=a(48328),S=a(9382),b=a(31934),k=a(95326),$=a(43011),C=a(68789),y=a(84131);S.vI.add(y.NBC);var T=1;const M={data:function(){return{showingImage:!1,pleromaTanVariant:Math.random()>.5?b:k,showingMore:!1}},components:{Modal:v.Z},computed:{pleromaTanStyles:function(){return{"shape-outside":"url("+(this.pleromaTanVariant===b?$:C)+")"}},shouldShow:function(){return!this.$store.state.instance.disableUpdateNotification&&this.$store.state.users.currentUser&&this.$store.state.serverSideStorage.flagStorage.updateCounter<T&&!this.$store.state.serverSideStorage.prefsStorage.simple.dontShowUpdateNotifs}},methods:{toggleShow:function(){this.showingMore=!this.showingMore},neverShowAgain:function(){this.toggleShow(),this.$store.commit("setFlag",{flag:"updateCounter",value:T}),this.$store.commit("setPreference",{path:"simple.dontShowUpdateNotifs",value:!0}),this.$store.dispatch("pushServerSideStorage")},dismiss:function(){this.$store.commit("setFlag",{flag:"updateCounter",value:T}),this.$store.dispatch("pushServerSideStorage")}},mounted:function(){var t=this;this.contentHeightNoImage=this.$refs.animatedText.scrollHeight;var e=new Image;e.onload=function(){setTimeout((function(){t.showingImage=!0}),100)},e.src=this.pleromaTanVariant===b?$:C}},N=(0,a(83744).Z)(M,[["render",function(t,e,a,v,S,b){var k=(0,n.up)("i18n-t"),$=(0,n.up)("Modal");return(0,n.wg)(),(0,n.j4)($,{"is-open":!!t.shouldShow,class:"UpdateNotification","no-background":!0},{default:(0,n.w5)((function(){return[(0,n._)("div",{class:(0,o.C_)(["UpdateNotificationModal panel",{"-peek":!t.showingMore}])},[(0,n._)("div",i,[(0,n._)("span",r,(0,o.zw)(t.$t("update.big_update_title")),1)]),(0,n._)("div",l,[(0,n._)("div",{class:(0,o.C_)(["content",{"-noImage":!t.showingImage}])},[t.showingImage?((0,n.wg)(),(0,n.iD)("img",{key:0,class:"pleroma-tan",src:t.pleromaTanVariant,style:(0,o.j5)(t.pleromaTanStyles)},null,12,u)):(0,n.kq)("",!0),p,(0,n._)("div",c,[(0,n._)("p",null,(0,o.zw)(t.$t("update.big_update_content")),1),(0,n._)("div",d,[(0,n.Wm)(k,{keypath:"update.update_bugs",tag:"p"},{pleromaGitlab:(0,n.w5)((function(){return[(0,n._)("a",g,(0,o.zw)(t.$t("update.update_bugs_gitlab")),1)]})),_:1}),(0,n.Wm)(k,{keypath:"update.update_changelog",tag:"p"},{theFullChangelog:(0,n.w5)((function(){return[(0,n._)("a",h,(0,o.zw)(t.$t("update.update_changelog_here")),1)]})),_:1}),(0,n._)("p",m,[(0,n.Wm)(k,{keypath:"update.art_by",tag:"small"},{linkToArtist:(0,n.w5)((function(){return[_]})),_:1})])],512)]),f],2)]),(0,n._)("div",w,[(0,n._)("button",{class:"button-default",onClick:e[0]||(e[0]=(0,s.iM)((function(){return t.neverShowAgain&&t.neverShowAgain.apply(t,arguments)}),["prevent"]))},(0,o.zw)(t.$t("general.never_show_again")),1),t.showingMore?(0,n.kq)("",!0):((0,n.wg)(),(0,n.iD)("button",{key:0,class:"button-default",onClick:e[1]||(e[1]=(0,s.iM)((function(){return t.toggleShow&&t.toggleShow.apply(t,arguments)}),["prevent"]))},(0,o.zw)(t.$t("general.show_more")),1)),(0,n._)("button",{class:"button-default",onClick:e[2]||(e[2]=(0,s.iM)((function(){return t.dismiss&&t.dismiss.apply(t,arguments)}),["prevent"]))},(0,o.zw)(t.$t("general.dismiss")),1)])],2)]})),_:1},8,["is-open"])}]])}}]);
//# sourceMappingURL=6464.fea96fa80a7373e4e5f8.js.map

View file

@ -1,2 +0,0 @@
"use strict";(self.webpackChunkpleroma_fe=self.webpackChunkpleroma_fe||[]).push([[8532],{68532:(t,e,n)=>{n.r(e),n.d(e,{default:()=>p});var i=n(66252),a=n(49963),c={class:"sticker-picker"},r=["image-tooltip","image"],o=["onClick"],s=["src"],l=n(7257);const u={components:{TabSwitcher:n(79354).Z},data:function(){return{meta:{stickers:[]},path:""}},computed:{pack:function(){return this.$store.state.instance.stickers||[]}},methods:{clear:function(){this.meta={stickers:[]}},pick:function(t,e){var n=this,i=this.$store;fetch(t).then((function(t){t.blob().then((function(t){var a=new File([t],e,{mimetype:"image/png"}),c=new FormData;c.append("file",a),l.Z.uploadMedia({store:i,formData:c}).then((function(t){n.$emit("uploaded",t),n.clear()}),(function(t){console.warn("Can't attach sticker"),console.warn(t),n.$emit("upload-failed","default")}))}))}))}}},p=(0,n(83744).Z)(u,[["render",function(t,e,n,l,u,p){var f=(0,i.up)("tab-switcher");return(0,i.wg)(),(0,i.iD)("div",c,[(0,i.Wm)(f,{class:"tab-switcher","render-only-focused":!0,"scrollable-tabs":""},{default:(0,i.w5)((function(){return[((0,i.wg)(!0),(0,i.iD)(i.HY,null,(0,i.Ko)(t.pack,(function(e){return(0,i.wg)(),(0,i.iD)("div",{key:e.path,"image-tooltip":e.meta.title,image:e.path+e.meta.tabIcon,class:"sticker-picker-content"},[((0,i.wg)(!0),(0,i.iD)(i.HY,null,(0,i.Ko)(e.meta.stickers,(function(n){return(0,i.wg)(),(0,i.iD)("div",{key:n,class:"sticker",onClick:(0,a.iM)((function(i){return t.pick(e.path+n,e.meta.title)}),["stop","prevent"])},[(0,i._)("img",{src:e.path+n},null,8,s)],8,o)})),128))],8,r)})),128))]})),_:1})])}]])}}]);
//# sourceMappingURL=8532.290194af65a2e3a4120e.js.map

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show more